llhttpnode.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /**
  2. * @file llhttpnode.h
  3. * @brief Declaration of classes for generic HTTP/LSL/REST handling.
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewergpl$
  6. *
  7. * Copyright (c) 2006-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #ifndef LL_LLHTTPNODE_H
  33. #define LL_LLHTTPNODE_H
  34. #include "llpointer.h"
  35. #include "llrefcount.h"
  36. #include "llsd.h"
  37. class LLChainIOFactory;
  38. /**
  39. * These classes represent the HTTP framework: The URL tree, and the LLSD
  40. * REST interface that such nodes implement.
  41. *
  42. * To implement a service, in most cases, subclass LLHTTPNode, implement
  43. * get() or post(), and create a global instance of LLHTTPRegistration<>.
  44. * This can all be done in a .cpp file, with no publically declared parts.
  45. */
  46. /**
  47. * @class LLHTTPNode
  48. * @brief Base class which handles url traversal, response routing
  49. * and support for standard LLSD services
  50. *
  51. * Users of the HTTP responder will typically derive a class from this
  52. * one, implement the get(), put() and/or post() methods, and then
  53. * use LLHTTPRegistration to insert it into the URL tree.
  54. *
  55. * The default implementation handles servicing the request and creating
  56. * the pipe fittings needed to read the headers, manage them, convert
  57. * to and from LLSD, etc.
  58. */
  59. class LLHTTPNode
  60. {
  61. protected:
  62. LOG_CLASS(LLHTTPNode);
  63. public:
  64. LLHTTPNode();
  65. virtual ~LLHTTPNode();
  66. /** @name Responses
  67. Most subclasses override one or more of these methods to provide the
  68. service. By default, the rest of the LLHTTPNode architecture will
  69. handle requests, create the needed LLIOPump, parse the input to LLSD,
  70. and format the LLSD result to the output.
  71. The default implementation of each of these is to call
  72. response->methodNotAllowed(); The "simple" versions can be overridden
  73. instead in those cases where the service can return an immediately
  74. computed response.
  75. */
  76. //@{
  77. public:
  78. virtual LLSD simpleGet() const;
  79. virtual LLSD simplePut(const LLSD& input) const;
  80. virtual LLSD simplePost(const LLSD& input) const;
  81. virtual LLSD simpleDel(const LLSD& context) const;
  82. /**
  83. * @brief Abstract Base Class declaring Response interface.
  84. */
  85. class Response : public LLRefCount
  86. {
  87. protected:
  88. Response() = default;
  89. virtual ~Response() = default;
  90. public:
  91. // Returns the LLSD content and a 200 OK.
  92. virtual void result(const LLSD&) = 0;
  93. // Returns the status code and message with headers.
  94. virtual void extendedResult(S32 code, const std::string& message,
  95. const LLSD& headers = LLSD()) = 0;
  96. // Returns the status code and LLSD result with headers.
  97. virtual void extendedResult(S32 code, const LLSD& result,
  98. const LLSD& headers = LLSD()) = 0;
  99. /**
  100. * @brief return status code and reason string on http header, but do
  101. * not return a payload.
  102. */
  103. virtual void status(S32 code, const std::string& message) = 0;
  104. // Returns no body, just status code and 'UNKNOWN ERROR'.
  105. virtual void statusUnknownError(S32 code);
  106. virtual void notFound(const std::string& message);
  107. virtual void notFound();
  108. virtual void methodNotAllowed();
  109. // Adds a name : value http header.
  110. // No effort is made to ensure the response is a valid http header. The
  111. // headers are stored as a map of header name : value. Though HTTP
  112. // allows the same header name to be transmitted more than once, this
  113. // implementation only stores a header name once.
  114. // @param name The name of the header, eg, "Content-Encoding"
  115. // @param value The value of the header, eg, "gzip"
  116. virtual void addHeader(const std::string& name,
  117. const std::string& value);
  118. protected:
  119. // Headers to be sent back with the HTTP response.
  120. // Protected class membership since derived classes are expected to use
  121. // it and there is no use case yet for other uses. If such a use case
  122. // arises, I suggest making a headers() public method, and moving this
  123. // member data into private.
  124. LLSD mHeaders;
  125. };
  126. typedef LLPointer<Response> ResponsePtr;
  127. virtual void get(ResponsePtr, const LLSD& context) const;
  128. virtual void put(ResponsePtr, const LLSD& context,
  129. const LLSD& input) const;
  130. virtual void post(ResponsePtr, const LLSD& context,
  131. const LLSD& input) const;
  132. virtual void del(ResponsePtr, const LLSD& context) const;
  133. virtual void options(ResponsePtr, const LLSD& context) const;
  134. //@}
  135. public:
  136. // URL traversal
  137. // The tree is traversed by calling getChild() with successive path
  138. // components, on successive results. When getChild() returns null, or
  139. // there are no more components, the last child responds to the request.
  140. // The default behavior is generally correct, though wildcard nodes will
  141. // want to implement validate().
  142. // Returns a child node, if any, at the given name default looks at
  143. // children and wildcard child (see below)
  144. virtual LLHTTPNode* getChild(const std::string& name, LLSD& context) const;
  145. // returns true if this node can service the remaining components; default
  146. // returns true if there are no remaining components
  147. virtual bool handles(const LLSD& remainder, LLSD& context) const;
  148. // Called only on wildcard nodes, to check if they will handle the name;
  149. // default is false; overrides will want to check name, and return true if
  150. // the name will construct to a valid url. For convenience, the
  151. // <code>getChild()</code> method above will automatically insert the name
  152. // in context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method
  153. // returns true. For example, the node "agent/<agent_id>/detail" will set
  154. // context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] equal to the
  155. // value found during traversal.
  156. virtual bool validate(const std::string& name, LLSD& context) const;
  157. // Finds a node, if any, that can service this path set up
  158. // context[CONTEXT_REQUEST] information
  159. const LLHTTPNode* traverse(const std::string& path, LLSD& context) const;
  160. //@}
  161. // The standard node can have any number of child nodes under fixed names,
  162. // and optionally one "wildcard" node that can handle all other names.
  163. // Usually, child nodes are add through LLHTTPRegistration, not by calling
  164. // this interface directly. The added node will be now owned by the parent
  165. // node.
  166. virtual void addNode(const std::string& path, LLHTTPNode* nodeToAdd);
  167. // Returns an arrary of node paths at and under this node
  168. LLSD allNodePaths() const;
  169. const LLHTTPNode* rootNode() const;
  170. const LLHTTPNode* findNode(const std::string& name) const;
  171. enum EHTTPNodeContentType
  172. {
  173. CONTENT_TYPE_LLSD,
  174. CONTENT_TYPE_TEXT
  175. };
  176. virtual EHTTPNodeContentType getContentType() const { return CONTENT_TYPE_LLSD; }
  177. // Description system
  178. // The Description object contains information about a service. All
  179. // subclasses of LLHTTPNode should override describe() and use the methods
  180. // of the Description class to set the various properties.
  181. class Description
  182. {
  183. public:
  184. void shortInfo(const std::string& s) { mInfo["description"] = s; }
  185. void longInfo(const std::string& s) { mInfo["details"] = s; }
  186. // Call this method when the service supports the specified verb.
  187. void getAPI() { mInfo["api"].append("GET"); }
  188. void putAPI() { mInfo["api"].append("PUT"); }
  189. void postAPI() { mInfo["api"].append("POST"); }
  190. void delAPI() { mInfo["api"].append("DELETE"); }
  191. void input(const std::string& s) { mInfo["input"] = s; }
  192. void output(const std::string& s) { mInfo["output"] = s; }
  193. void source(const char* f, int l) { mInfo["__file__"] = f; mInfo["__line__"] = l; }
  194. LLSD getInfo() const { return mInfo; }
  195. private:
  196. LLSD mInfo;
  197. };
  198. virtual void describe(Description&) const;
  199. // Returns a factory object for handling wire protocols. The base class
  200. // returns NULL, as it doesn't know about wire protocols at all. This is
  201. // okay for most nodes as LLIOHTTPServer is smart enough to use a default
  202. // wire protocol for HTTP for such nodes. Specialized subclasses that
  203. // handle things like XML-RPC will want to implement this (see
  204. // LLXMLSDRPCServerFactory).
  205. virtual const LLChainIOFactory* getProtocolHandler() const;
  206. private:
  207. class Impl;
  208. Impl& impl;
  209. };
  210. class LLSimpleResponse final : public LLHTTPNode::Response
  211. {
  212. public:
  213. static LLPointer<LLSimpleResponse> create();
  214. void result(const LLSD& result) override;
  215. void extendedResult(S32 code, const std::string& body,
  216. const LLSD& headers) override;
  217. void extendedResult(S32 code, const LLSD& result,
  218. const LLSD& headers) override;
  219. void status(S32 code, const std::string& message) override;
  220. void print(std::ostream& out) const;
  221. protected:
  222. ~LLSimpleResponse() override = default;
  223. private:
  224. // Must be accessed through LLPointer.
  225. LL_INLINE LLSimpleResponse()
  226. : mCode(0)
  227. {
  228. }
  229. public:
  230. S32 mCode;
  231. std::string mMessage;
  232. };
  233. std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp);
  234. /**
  235. * @name Automatic LLHTTPNode registration
  236. *
  237. * To register a node type at a particular url path, construct a global instance
  238. * of LLHTTPRegistration:
  239. *
  240. * LLHTTPRegistration<LLMyNodeType> gHTTPServiceAlphaBeta("/alpha/beta");
  241. *
  242. * (Note the naming convention carefully.) This object must be global and not
  243. * static. However, it needn't be declared in your .h file. It can exist
  244. * solely in the .cpp file. The same is true of your subclass of LLHTTPNode:
  245. * it can be declared and defined wholly within the .cpp file.
  246. *
  247. * When constructing a web server, use LLHTTPRegistrar to add all the registered
  248. * nodes to the url tree:
  249. *
  250. * LLHTTPRegistrar::buidlAllServices(mRootNode);
  251. */
  252. //@{
  253. class LLHTTPRegistrar
  254. {
  255. protected:
  256. LOG_CLASS(LLHTTPRegistrar);
  257. public:
  258. class NodeFactory
  259. {
  260. public:
  261. virtual ~NodeFactory() = default;
  262. virtual LLHTTPNode* build() const = 0;
  263. };
  264. static void buildAllServices(LLHTTPNode& root);
  265. // Constructs an LLHTTPRegistration below to call this
  266. static void registerFactory(const std::string& path, NodeFactory& factory);
  267. };
  268. template<class NodeType>
  269. class LLHTTPRegistration
  270. {
  271. public:
  272. LL_INLINE LLHTTPRegistration(const std::string& path)
  273. {
  274. LLHTTPRegistrar::registerFactory(path, mFactory);
  275. }
  276. private:
  277. class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory
  278. {
  279. public:
  280. LL_INLINE LLHTTPNode* build() const override { return new NodeType; }
  281. };
  282. ThisNodeFactory mFactory;
  283. };
  284. template<class NodeType>
  285. class LLHTTPParamRegistration
  286. {
  287. public:
  288. LL_INLINE LLHTTPParamRegistration(const std::string& path, LLSD params)
  289. : mFactory(params)
  290. {
  291. LLHTTPRegistrar::registerFactory(path, mFactory);
  292. }
  293. private:
  294. class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory
  295. {
  296. public:
  297. LL_INLINE ThisNodeFactory(LLSD params)
  298. : mParams(params)
  299. {
  300. }
  301. LL_INLINE LLHTTPNode* build() const override { return new NodeType(mParams); }
  302. private:
  303. LLSD mParams;
  304. };
  305. ThisNodeFactory mFactory;
  306. };
  307. //@}
  308. #endif // LL_LLHTTPNODE_H