PageRenderTime 44ms CodeModel.GetById 11ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llhttpnode.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 389 lines | 147 code | 63 blank | 179 comment | 0 complexity | bc4fca9ba870137ab5fe8a7db128bac2 MD5 | raw file
  1/** 
  2 * @file llhttpnode.h
  3 * @brief Declaration of classes for generic HTTP/LSL/REST handling.
  4 *
  5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifndef LL_LLHTTPNODE_H
 28#define LL_LLHTTPNODE_H
 29
 30#include "llpointer.h"
 31#include "llrefcount.h"
 32#include "llsd.h"
 33
 34class LLChainIOFactory;
 35
 36/**
 37 * These classes represent the HTTP framework: The URL tree, and the LLSD
 38 * REST interface that such nodes implement.
 39 * 
 40 * To implement a service, in most cases, subclass LLHTTPNode, implement
 41 * get() or post(), and create a global instance of LLHTTPRegistration<>.
 42 * This can all be done in a .cpp file, with no publically declared parts.
 43 * 
 44 * To implement a server see lliohttpserver.h
 45 * @see LLHTTPWireServer
 46 */
 47
 48/** 
 49 * @class LLHTTPNode
 50 * @brief Base class which handles url traversal, response routing
 51 * and support for standard LLSD services
 52 *
 53 * Users of the HTTP responder will typically derive a class from this
 54 * one, implement the get(), put() and/or post() methods, and then
 55 * use LLHTTPRegistration to insert it into the URL tree.
 56 *
 57 * The default implementation handles servicing the request and creating
 58 * the pipe fittings needed to read the headers, manage them, convert
 59 * to and from LLSD, etc.
 60 */
 61class LLHTTPNode
 62{
 63public:
 64	LLHTTPNode();
 65	virtual ~LLHTTPNode();
 66
 67	/** @name Responses
 68		Most subclasses override one or more of these methods to provide
 69		the service.  By default, the rest of the LLHTTPNode architecture
 70		will handle requests, create the needed LLIOPump, parse the input
 71		to LLSD, and format the LLSD result to the output.
 72		
 73		The default implementation of each of these is to call
 74		response->methodNotAllowed();  The "simple" versions can be
 75		overridden instead in those cases where the service can return
 76		an immediately computed response.
 77	*/
 78	//@{
 79public:	
 80
 81	virtual LLSD simpleGet() const;
 82	virtual LLSD simplePut(const LLSD& input) const;
 83	virtual LLSD simplePost(const LLSD& input) const;
 84	virtual LLSD simpleDel(const LLSD& context) const;
 85
 86	/**
 87	* @brief Abstract Base Class declaring Response interface.
 88	*/
 89	class Response : public LLRefCount
 90	{
 91	protected:
 92		virtual ~Response();
 93
 94	public:
 95		/**
 96		* @brief Return the LLSD content and a 200 OK.
 97		*/
 98		virtual void result(const LLSD&) = 0;
 99
100		/**
101		 * @brief return status code and message with headers.
102		 */
103		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) = 0;
104
105		/**
106		 * @brief return status code and reason string on http header,
107		 * but do not return a payload.
108		 */
109		virtual void status(S32 code, const std::string& message) = 0;
110
111		/**
112		* @brief Return no body, just status code and 'UNKNOWN ERROR'.
113		*/
114		virtual void statusUnknownError(S32 code);
115
116		virtual void notFound(const std::string& message);
117		virtual void notFound();
118		virtual void methodNotAllowed();
119
120		/**
121		* @breif Add a name: value http header.
122		*
123		* No effort is made to ensure the response is a valid http
124		* header.
125		* The headers are stored as a map of header name : value.
126		* Though HTTP allows the same header name to be transmitted
127		* more than once, this implementation only stores a header
128		* name once.
129		* @param name The name of the header, eg, "Content-Encoding"
130		* @param value The value of the header, eg, "gzip"
131		*/
132		virtual void addHeader(const std::string& name, const std::string& value);
133
134	protected:
135		/**
136		* @brief Headers to be sent back with the HTTP response.
137		*
138		* Protected class membership since derived classes are
139		* expected to use it and there is no use case yet for other
140		* uses. If such a use case arises, I suggest making a
141		* headers() public method, and moving this member data into
142		* private.
143		*/
144		LLSD mHeaders;
145	};
146
147	typedef LLPointer<Response> ResponsePtr;
148
149	virtual void get(ResponsePtr, const LLSD& context) const;
150	virtual void put(
151		ResponsePtr,
152		const LLSD& context,
153		const LLSD& input) const;
154	virtual void post(
155		ResponsePtr,
156		const LLSD& context,
157		const LLSD& input) const;
158	virtual void del(ResponsePtr, const LLSD& context) const;
159	virtual void options(ResponsePtr, const LLSD& context) const;
160	//@}
161	
162
163	/** @name URL traversal
164		 The tree is traversed by calling getChild() with successive
165		 path components, on successive results.  When getChild() returns
166		 null, or there are no more components, the last child responds to
167		 the request.
168		 
169		 The default behavior is generally correct, though wildcard nodes
170		 will want to implement validate().
171	*/
172	//@{
173public:
174	virtual LLHTTPNode* getChild(const std::string& name, LLSD& context) const;
175		/**< returns a child node, if any, at the given name
176			 default looks at children and wildcard child (see below)
177		*/
178		
179	virtual bool handles(const LLSD& remainder, LLSD& context) const;
180		/**< return true if this node can service the remaining components;
181			 default returns true if there are no remaining components
182		*/
183		
184	virtual bool validate(const std::string& name, LLSD& context) const;
185		/**< called only on wildcard nodes, to check if they will handle
186			 the name;	default is false;  overrides will want to check
187			 name, and return true if the name will construct to a valid url.
188			 For convenience, the <code>getChild()</code> method above will
189			 automatically insert the name in
190			 context["request"]["wildcard"][key] if this method returns true.
191			 For example, the node "agent/<agent_id>/detail" will set
192			 context["request"]["wildcard"]["agent_id"] eqaul to the value 
193			 found during traversal.
194		*/
195		
196	const LLHTTPNode* traverse(const std::string& path, LLSD& context) const;
197		/**< find a node, if any, that can service this path
198			 set up context["request"] information 
199 		*/
200 	//@}
201 
202	/** @name Child Nodes
203		 The standard node can have any number of child nodes under
204		 fixed names, and optionally one "wildcard" node that can
205		 handle all other names.
206		 
207		 Usually, child nodes are add through LLHTTPRegistration, not
208		 by calling this interface directly.
209		 
210		 The added node will be now owned by the parent node.
211	*/
212	//@{
213	
214	virtual void addNode(const std::string& path, LLHTTPNode* nodeToAdd);
215
216	LLSD allNodePaths() const;
217		///< Returns an arrary of node paths at and under this node
218
219	const LLHTTPNode* rootNode() const;
220	const LLHTTPNode* findNode(const std::string& name) const;
221
222
223	enum EHTTPNodeContentType
224	{
225		CONTENT_TYPE_LLSD,
226		CONTENT_TYPE_TEXT
227	};
228
229	virtual EHTTPNodeContentType getContentType() const { return CONTENT_TYPE_LLSD; }
230	//@}
231
232	/* @name Description system
233		The Description object contains information about a service.
234		All subclasses of LLHTTPNode should override describe() and use
235		the methods of the Description class to set the various properties.
236	 */
237	//@{
238		class Description
239		{
240		public:
241			void shortInfo(const std::string& s){ mInfo["description"] = s; }
242			void longInfo(const std::string& s)	{ mInfo["details"] = s; }
243
244			// Call this method when the service supports the specified verb.
245			void getAPI() { mInfo["api"].append("GET"); }
246			void putAPI() { mInfo["api"].append("PUT");  }
247			void postAPI() { mInfo["api"].append("POST"); }
248			void delAPI() { mInfo["api"].append("DELETE"); }
249
250			void input(const std::string& s)	{ mInfo["input"] = s; }
251			void output(const std::string& s)	{ mInfo["output"] = s; }
252			void source(const char* f, int l)	{ mInfo["__file__"] = f;
253												  mInfo["__line__"] = l; }
254			
255			LLSD getInfo() const { return mInfo; }
256			
257		private:
258			LLSD mInfo;
259		};
260	
261	virtual void describe(Description&) const;
262	
263	//@}
264	
265	
266	virtual const LLChainIOFactory* getProtocolHandler() const;
267		/**< Return a factory object for handling wire protocols.
268		 *   The base class returns NULL, as it doesn't know about
269		 *   wire protocols at all.  This is okay for most nodes
270		 *   as LLIOHTTPServer is smart enough to use a default
271		 *   wire protocol for HTTP for such nodes.  Specialized
272		 *   subclasses that handle things like XML-RPC will want
273		 *   to implement this.  (See LLXMLSDRPCServerFactory.)
274		 */
275
276private:
277	class Impl;
278	Impl& impl;
279};
280
281
282
283class LLSimpleResponse : public LLHTTPNode::Response
284{
285public:
286	static LLPointer<LLSimpleResponse> create();
287	
288	void result(const LLSD& result);
289	void extendedResult(S32 code, const std::string& body, const LLSD& headers);
290	
291	void status(S32 code, const std::string& message);
292
293	void print(std::ostream& out) const;
294
295	S32 mCode;
296	std::string mMessage;
297
298protected:
299	~LLSimpleResponse();
300
301private:
302        LLSimpleResponse() : mCode(0) {} // Must be accessed through LLPointer.
303};
304
305std::ostream& operator<<(std::ostream& out, const LLSimpleResponse& resp);
306
307
308
309/** 
310 * @name Automatic LLHTTPNode registration 
311 *
312 * To register a node type at a particular url path, construct a global instance
313 * of LLHTTPRegistration:
314 *
315 *		LLHTTPRegistration<LLMyNodeType> gHTTPServiceAlphaBeta("/alpha/beta");
316 *
317 * (Note the naming convention carefully.)  This object must be global and not
318 * static.  However, it needn't be declared in your .h file.  It can exist
319 * solely in the .cpp file.  The same is true of your subclass of LLHTTPNode:
320 * it can be declared and defined wholly within the .cpp file.
321 *
322 * When constructing a web server, use LLHTTPRegistrar to add all the registered
323 * nodes to the url tree:
324 *
325 *		LLHTTPRegistrar::buidlAllServices(mRootNode);
326 */
327//@{
328
329class LLHTTPRegistrar
330{
331public:
332	class NodeFactory
333	{
334	public:
335		virtual ~NodeFactory();
336		virtual LLHTTPNode* build() const = 0;
337	};
338
339	static void buildAllServices(LLHTTPNode& root);
340
341	static void registerFactory(const std::string& path, NodeFactory& factory);
342		///< construct an LLHTTPRegistration below to call this
343};
344
345template < class NodeType >
346class LLHTTPRegistration
347{
348public:
349	LLHTTPRegistration(const std::string& path)
350	{
351		LLHTTPRegistrar::registerFactory(path, mFactory);
352	}
353
354private:
355	class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory
356	{
357	public:
358		virtual LLHTTPNode* build() const { return new NodeType; }
359	};
360	
361	ThisNodeFactory	mFactory;	
362};
363
364template < class NodeType>
365class LLHTTPParamRegistration
366{
367public:
368	LLHTTPParamRegistration(const std::string& path, LLSD params) :
369		mFactory(params)
370	{
371		LLHTTPRegistrar::registerFactory(path, mFactory);
372	}
373
374private:
375	class ThisNodeFactory : public LLHTTPRegistrar::NodeFactory
376	{
377	public:
378		ThisNodeFactory(LLSD params) : mParams(params) {}
379		virtual LLHTTPNode* build() const { return new NodeType(mParams); }
380	private:
381		LLSD mParams;
382	};
383	
384	ThisNodeFactory	mFactory;	
385};
386	
387//@}
388
389#endif // LL_LLHTTPNODE_H