diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/cmake/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/llcommon/llkeythrottle.h | 35 | ||||
| -rw-r--r-- | indra/llmessage/llcurl.cpp | 54 | ||||
| -rw-r--r-- | indra/llmessage/llcurl.h | 28 | ||||
| -rw-r--r-- | indra/llmessage/llhttpclient.cpp | 43 | ||||
| -rw-r--r-- | indra/llmessage/llhttpnode.cpp | 27 | ||||
| -rw-r--r-- | indra/llmessage/llhttpnode.h | 88 | ||||
| -rw-r--r-- | indra/llmessage/lliohttpserver.cpp | 48 | ||||
| -rw-r--r-- | indra/newview/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/test/lliohttpserver_tut.cpp | 17 | 
10 files changed, 223 insertions, 119 deletions
| diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 9cc34ea159..f0bb241961 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -63,7 +63,6 @@ set(cmake_SOURCE_FILES      PNG.cmake      Python.cmake      QuickTime.cmake -    Smartheap.cmake      TemplateCheck.cmake      UI.cmake      UnixInstall.cmake diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 61a43b2dad..ac2f4254f2 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -55,28 +55,31 @@ class LLKeyThrottleImpl  protected:  	struct Entry {  		U32		count; -		BOOL	blocked; +		bool	blocked; -		Entry() : count(0), blocked(FALSE) { } +		Entry() : count(0), blocked(false) { }  	};  	typedef std::map<T, Entry> EntryMap; -	EntryMap * prevMap; -	EntryMap * currMap; +	EntryMap* prevMap; +	EntryMap* currMap;  	U32 countLimit;  		// maximum number of keys allowed per interval  	U64 intervalLength;		// each map covers this time period (usec or frame number)  	U64 startTime;			// start of the time period (usec or frame number) -	  		// currMap started counting at this time  		// prevMap covers the previous interval -	LLKeyThrottleImpl() : prevMap(0), currMap(0), -			      countLimit(0), intervalLength(1), -			      startTime(0) { }; +	LLKeyThrottleImpl() : +		prevMap(NULL), +		currMap(NULL), +		countLimit(0), +		intervalLength(1), +		startTime(0) +	{}  	static U64 getTime()  	{ @@ -93,7 +96,9 @@ template< class T >  class LLKeyThrottle  {  public: -	LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE)	// realtime = FALSE for frame-based throttle, TRUE for usec real-time throttle +	// @param realtime = FALSE for frame-based throttle, TRUE for usec +	// real-time throttle +	LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE)	  		: m(* new LLKeyThrottleImpl<T>)  	{  		setParameters( limit, interval, realtime ); @@ -149,7 +154,7 @@ public:  		}  		U32 prevCount = 0; -		BOOL prevBlocked = FALSE; +		bool prevBlocked = false;  		typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);  		if (prev != m.prevMap->end()) @@ -198,17 +203,17 @@ public:  		noteAction(id);  		typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];  		curr.count = llmax(m.countLimit, curr.count); -		curr.blocked = TRUE; +		curr.blocked = true;  	} -	// returns TRUE if key is blocked -	BOOL isThrottled(const T& id) const +	// returns true if key is blocked +	bool isThrottled(const T& id) const  	{  		if (m.currMap->empty()  			&& m.prevMap->empty())  		{  			// most of the time we'll fall in here -			return FALSE; +			return false;  		}  		// NOTE, we ignore the case where id is in the map but the map is stale.   @@ -226,7 +231,7 @@ public:  		{  			return entry->second.blocked;  		} -		return FALSE; +		return false;  	}  	// Get the throttling parameters diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index e282f49438..5a426c7238 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -113,6 +113,15 @@ LLCurl::Responder::~Responder()  }  // virtual +void LLCurl::Responder::error( +	U32 status, +	const std::string& reason, +	const LLSD&) +{ +	error(status, reason); +} + +// virtual  void LLCurl::Responder::error(U32 status, const std::string& reason)  {  	llinfos << status << ": " << reason << llendl; @@ -124,38 +133,16 @@ void LLCurl::Responder::result(const LLSD& content)  }  // virtual -void LLCurl::Responder::completedRaw(U32 status, const std::string& reason, -									 const LLChannelDescriptors& channels, -									 const LLIOPipe::buffer_ptr_t& buffer) +void LLCurl::Responder::completedRaw( +	U32 status, +	const std::string& reason, +	const LLChannelDescriptors& channels, +	const LLIOPipe::buffer_ptr_t& buffer)  { -	if (isGoodStatus(status)) -	{ -		LLSD content; -		LLBufferStream istr(channels, buffer.get()); -		LLSDSerialize::fromXML(content, istr); -/* -		const S32 parseError = -1; -		if(LLSDSerialize::fromXML(content, istr) == parseError) -		{ -			mStatus = 498; -			mReason = "Client Parse Error"; -		} -*/ -		completed(status, reason, content); -	} -	else if (status == 400) -	{ -		// Get reason from buffer -		char tbuf[4096]; -		S32 len = 4096; -		buffer->readAfter(channels.in(), NULL, (U8*)tbuf, len); -		tbuf[len] = 0; -		completed(status, std::string(tbuf), LLSD()); -	} -	else -	{ -		completed(status, reason, LLSD()); -	} +	LLSD content; +	LLBufferStream istr(channels, buffer.get()); +	LLSDSerialize::fromXML(content, istr); +	completed(status, reason, content);  }  // virtual @@ -167,10 +154,7 @@ void LLCurl::Responder::completed(U32 status, const std::string& reason, const L  	}  	else  	{ -		// *NOTE: This is kind of messed up. This should probably call -		// the full error method which then provides a default impl -		// which calls the thinner method. -		error(status, reason); +		error(status, reason, content);  	}  } diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 1b3d3f6266..b7634d420f 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -84,17 +84,31 @@ public:  			return((200 <= status) && (status < 300));  		} +		virtual void error( +			U32 status, +			const std::string& reason, +			const LLSD& content); +			//< called by completed() on bad status  +  		virtual void error(U32 status, const std::string& reason); -			// called with non-200 status codes +			//< called by default error(status, reason, content)  		virtual void result(const LLSD& content); -		 -		// Override point for clients that may want to use this class when the response is some other format besides LLSD -		virtual void completedRaw(U32 status, const std::string& reason, -								  const LLChannelDescriptors& channels, -								  const LLIOPipe::buffer_ptr_t& buffer); +			//< called by completed for good status codes. + +		virtual void completedRaw( +			U32 status, +			const std::string& reason, +			const LLChannelDescriptors& channels, +			const LLIOPipe::buffer_ptr_t& buffer); +			/**< Override point for clients that may want to use this +			   class when the response is some other format besides LLSD +			*/ -		virtual void completed(U32 status, const std::string& reason, const LLSD& content); +		virtual void completed( +			U32 status, +			const std::string& reason, +			const LLSD& content);  			/**< The default implemetnation calls  				either:  				* result(), or diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 859f3c1536..52cb8fe1c3 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -205,9 +205,7 @@ static void request(  	Injector* body_injector,  	LLCurl::ResponderPtr responder,  	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, -	const LLSD& headers = LLSD(), -	S32 offset = 0, -	S32 bytes = 0) +	const LLSD& headers = LLSD())  {  	if (!LLHTTPClient::hasPump())  	{ @@ -216,7 +214,7 @@ static void request(  	}  	LLPumpIO::chain_t chain; -	LLURLRequest *req = new LLURLRequest(method, url); +	LLURLRequest* req = new LLURLRequest(method, url);  	req->checkRootCertificate(true);      // Insert custom headers is the caller sent any @@ -235,7 +233,7 @@ static void request(              //to not use the proxy (read: llurlrequest.cpp)              if ((iter->first == "Pragma") && (iter->second.asString() == ""))              { -                req->useProxy(FALSE); +                req->useProxy(false);              }              header << iter->first << ": " << iter->second.asString() ;              lldebugs << "header = " << header.str() << llendl; @@ -258,34 +256,27 @@ static void request(     		chain.push_back(LLIOPipe::ptr_t(body_injector));  	} -	if (method == LLURLRequest::HTTP_GET && (offset > 0 || bytes > 0)) -	{ -		std::string range = llformat("Range: bytes=%d-%d", offset,offset+bytes-1); -		req->addHeader(range.c_str()); -   	} -	  	chain.push_back(LLIOPipe::ptr_t(req));  	theClientPump->addChain(chain, timeout);  } -void LLHTTPClient::getByteRange(const std::string& url, -								S32 offset, S32 bytes, -								ResponderPtr responder, -								const LLSD& headers, -								const F32 timeout) +void LLHTTPClient::getByteRange( +	const std::string& url, +	S32 offset, +	S32 bytes, +	ResponderPtr responder, +	const LLSD& hdrs, +	const F32 timeout)  { -	// *FIX: Why is the headers argument ignored? Phoenix 2008-04-28 -    request( -		url, -		LLURLRequest::HTTP_GET, -		NULL, -		responder, -		timeout, -		LLSD(), 	// WTF? Shouldn't this be used? -		offset, -		bytes); +	LLSD headers = hdrs; +	if(offset > 0 || bytes > 0) +	{ +		std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1); +		headers["Range"] = range; +	} +    request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);  }  void LLHTTPClient::head(const std::string& url, ResponderPtr responder, const F32 timeout) diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 196aa5f8cf..91605b4008 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -174,6 +174,26 @@ LLSD LLHTTPNode::del(const LLSD&) const  	throw NotImplemented();  } +// virtual +void  LLHTTPNode::options(ResponsePtr response, const LLSD& context) const +{ +	//llinfos << "options context: " << context << llendl; + +	// default implementation constructs an url to the documentation. +	std::string host = context[CONTEXT_REQUEST]["headers"]["host"].asString(); +	if(host.empty()) +	{ +		response->status(400, "Bad Request -- need Host header"); +		return; +	} +	std::ostringstream ostr; +	ostr << "http://" << host << "/web/server/api"; +	ostr << context[CONTEXT_REQUEST]["path"].asString(); +	static const std::string DOC_HEADER("X-Documentation-URL"); +	response->addHeader(DOC_HEADER, ostr.str()); +	response->status(200, "OK"); +} +  // virtual  LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const @@ -386,6 +406,13 @@ void LLHTTPNode::Response::methodNotAllowed()  	status(405, "Method Not Allowed");  } +void LLHTTPNode::Response::addHeader( +	const std::string& name, +	const std::string& value) +{ +	mHeaders[name] = value; +} +  void LLHTTPNode::describe(Description& desc) const  {  	desc.shortInfo("unknown service (missing describe() method)"); diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index e27056a51f..54715f2b38 100644 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -82,33 +82,79 @@ public:  	*/  	//@{  public:	 -		virtual LLSD get() const; -		virtual LLSD put(const LLSD& input) const; -		virtual LLSD post(const LLSD& input) const; -		virtual LLSD del(const LLSD& context) const; +	virtual LLSD get() const; +	virtual LLSD put(const LLSD& input) const; +	virtual LLSD post(const LLSD& input) const; +	virtual LLSD del(const LLSD& context) const; -		class Response : public LLRefCount -		{ -		protected: -			virtual ~Response(); +	class Response : public LLRefCount +	{ +	protected: +		virtual ~Response(); -		public: -			virtual void result(const LLSD&) = 0; -			virtual void status(S32 code, const std::string& message) = 0; +	public: +		/** +		 * @brief Return the LLSD content and a 200 OK. +		 */ +		virtual void result(const LLSD&) = 0; + +		/** +		 * @brief return status code and reason string on http header, +		 * but do not return a payload. +		 */ +		virtual void status(S32 code, const std::string& message) = 0; + +		/** +		 * @brief Return no body, just status code and 'UNKNOWN ERROR'. +		 */ +		void status(S32 code); + +		void notFound(const std::string& message); +		void notFound(); +		void methodNotAllowed(); + +		/** +		 * @breif Add a name: value http header. +		 * +		 * No effort is made to ensure the response is a valid http +		 * header. +		 * The headers are stored as a map of header name : value. +		 * Though HTTP allows the same header name to be transmitted +		 * more than once, this implementation only stores a header +		 * name once. +		 * @param name The name of the header, eg, "Content-Encoding" +		 * @param value The value of the header, eg, "gzip" +		 */ +		void addHeader(const std::string& name, const std::string& value); + +	protected: +		/** +		 * @brief Headers to be sent back with the HTTP response. +		 * +		 * Protected class membership since derived classes are +		 * expected to use it and there is no use case yet for other +		 * uses. If such a use case arises, I suggest making a +		 * headers() public method, and moving this member data into +		 * private. +		 */ +		LLSD mHeaders; +	}; -			void status(S32 code); -			void notFound(const std::string& message); -			void notFound(); -			void methodNotAllowed(); -		}; -		typedef LLPointer<Response> ResponsePtr; +	typedef LLPointer<Response> ResponsePtr; -		virtual void get(ResponsePtr, const LLSD& context) const; -		virtual void put(ResponsePtr, const LLSD& context, const LLSD& input) const; -		virtual void post(ResponsePtr, const LLSD& context, const LLSD& input) const; -		virtual void del(ResponsePtr, const LLSD& context) const; +	virtual void get(ResponsePtr, const LLSD& context) const; +	virtual void put( +		ResponsePtr, +		const LLSD& context, +		const LLSD& input) const; +	virtual void post( +		ResponsePtr, +		const LLSD& context, +		const LLSD& input) const; +	virtual void del(ResponsePtr, const LLSD& context) const; +	virtual void options(ResponsePtr, const LLSD& context) const;  	//@} diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index ec5cb93d69..90f8ef7638 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -57,10 +57,13 @@  static const char HTTP_VERSION_STR[] = "HTTP/1.0";  static const std::string CONTEXT_REQUEST("request");  static const std::string CONTEXT_RESPONSE("response"); +static const std::string CONTEXT_VERB("verb"); +static const std::string CONTEXT_HEADERS("headers");  static const std::string HTTP_VERB_GET("GET");  static const std::string HTTP_VERB_PUT("PUT");  static const std::string HTTP_VERB_POST("POST");  static const std::string HTTP_VERB_DELETE("DELETE"); +static const std::string HTTP_VERB_OPTIONS("OPTIONS");  static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;  static void* sTimingCallbackData = NULL; @@ -130,6 +133,7 @@ private:  	LLSD mGoodResult;  	S32 mStatusCode;  	std::string mStatusMessage;	 +	LLSD mHeaders;  };  LLIOPipe::EStatus LLHTTPPipe::process_impl( @@ -164,7 +168,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		static LLTimer timer;  		timer.reset(); -		std::string verb = context[CONTEXT_REQUEST]["verb"]; +		std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];  		if(verb == HTTP_VERB_GET)  		{  			mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); @@ -185,6 +189,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		{  			mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);  		}		 +		else if(verb == HTTP_VERB_OPTIONS) +		{ +			mNode.options(LLHTTPNode::ResponsePtr(mResponse), context); +		}		  		else   		{  		    mResponse->methodNotAllowed(); @@ -231,7 +239,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		case STATE_GOOD_RESULT:  		{ -			context[CONTEXT_RESPONSE]["contentType"] = "application/xml"; +			LLSD headers = mHeaders; +			headers["Content-Type"] = "application/xml"; +			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;  			LLBufferStream ostr(channels, buffer.get());  			LLSDSerialize::toXML(mGoodResult, ostr); @@ -240,7 +250,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		case STATE_STATUS_RESULT:  		{ -			context[CONTEXT_RESPONSE]["contentType"] = "text/plain"; +			LLSD headers = mHeaders; +			headers["Content-Type"] = "text/plain"; +			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;  			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;  			context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;  			LLBufferStream ostr(channels, buffer.get()); @@ -287,6 +299,7 @@ void LLHTTPPipe::Response::result(const LLSD& r)  	mPipe->mStatusMessage = "OK";  	mPipe->mGoodResult = r;  	mPipe->mState = STATE_GOOD_RESULT; +	mPipe->mHeaders = mHeaders;  	mPipe->unlockChain();	  } @@ -302,6 +315,7 @@ void LLHTTPPipe::Response::status(S32 code, const std::string& message)  	mPipe->mStatusCode = code;  	mPipe->mStatusMessage = message;  	mPipe->mState = STATE_STATUS_RESULT; +	mPipe->mHeaders = mHeaders;  	mPipe->unlockChain();  } @@ -389,17 +403,24 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(  		}  		ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n"; -		 -		std::string type = context[CONTEXT_RESPONSE]["contentType"].asString(); -		if (!type.empty()) -		{ -			ostr << "Content-Type: " << type << "\r\n"; -		}  		S32 content_length = buffer->countAfter(channels.in(), NULL);  		if(0 < content_length)  		{  			ostr << "Content-Length: " << content_length << "\r\n";  		} +		// *NOTE: This guard can go away once the LLSD static map +		// iterator is available. Phoenix. 2008-05-09 +		LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS]; +		if(headers.isDefined()) +		{ +			LLSD::map_iterator iter = headers.beginMap(); +			LLSD::map_iterator end = headers.endMap(); +			for(; iter != end; ++iter) +			{ +				ostr << (*iter).first << ": " << (*iter).second.asString() +					<< "\r\n"; +			} +		}  		ostr << "\r\n";  		LLChangeChannel change(channels.in(), channels.out()); @@ -606,11 +627,12 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  				read_next_line = true;  				LLMemoryStream header((U8*)buf, len);  				header >> mVerb; -				 +  				if((HTTP_VERB_GET == mVerb)  				   || (HTTP_VERB_POST == mVerb)  				   || (HTTP_VERB_PUT == mVerb) -				   || (HTTP_VERB_DELETE == mVerb)) +				   || (HTTP_VERB_DELETE == mVerb) +				   || (HTTP_VERB_OPTIONS == mVerb))  				{  					header >> mAbsPathAndQuery;  					header >> mVersion; @@ -721,7 +743,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  	{  		// hey, hey, we should have everything now, so we pass it to  		// a content handler. -		context[CONTEXT_REQUEST]["verb"] = mVerb; +		context[CONTEXT_REQUEST][CONTEXT_VERB] = mVerb;  		const LLHTTPNode* node = mRootNode.traverse(mPath, context);  		if(node)  		{ @@ -765,7 +787,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  				= mBuildContext["remote-host"];  			context[CONTEXT_REQUEST]["remote-port"]  				= mBuildContext["remote-port"]; -			context[CONTEXT_REQUEST]["headers"] = mHeaders; +			context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders;  			const LLChainIOFactory* protocolHandler  				= node->getProtocolHandler(); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 20876d630f..85cb5dd007 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -28,7 +28,6 @@ include(LScript)  include(Linking)  include(Mozlib)  include(NDOF) -include(Smartheap)  include(TemplateCheck)  include(UI)  include(UnixInstall) diff --git a/indra/test/lliohttpserver_tut.cpp b/indra/test/lliohttpserver_tut.cpp index 5401d1a8ae..e5607cdad7 100644 --- a/indra/test/lliohttpserver_tut.cpp +++ b/indra/test/lliohttpserver_tut.cpp @@ -327,6 +327,23 @@ namespace tut  		ensure_starts_with("large echo status", result, "HTTP/1.0 200 OK\r\n");  	} +	template<> template<> +	void HTTPServiceTestObject::test<8>() +	{ +		// test the OPTIONS http method -- the default implementation +		// should return the X-Documentation-URL +		std::ostringstream http_request; +		http_request << "OPTIONS /  HTTP/1.0\r\nHost: localhost\r\n\r\n"; +		bool timeout = false; +		std::string result = makeRequest("/", http_request.str(), timeout); +		ensure_starts_with("OPTIONS verb ok", result, "HTTP/1.0 200 OK\r\n"); +		ensure_contains( +			"Doc url header exists", +			result, +			"X-Documentation-URL: http://localhost"); +	} + +  	/* TO DO:  		test generation of not found and method not allowed errors  	*/ | 
