diff options
| author | Monty Brandenberg <monty@lindenlab.com> | 2012-07-16 17:35:44 -0400 | 
|---|---|---|
| committer | Monty Brandenberg <monty@lindenlab.com> | 2012-07-16 17:35:44 -0400 | 
| commit | 8d3e5f3959b071226c4a5c2c68d9fe8664ae1ffd (patch) | |
| tree | 5b740ee44b58b098bb48aed217a8870be401b9c7 | |
| parent | d238341afaecedfe227141126c4c35dcde4a0671 (diff) | |
SH-3241 Validate header correctness, SH-3243 more unit tests
Define expectations for headers for GET, POST, PUT requests.
Document those in the interface, test those with integration tests.
Verify that header overrides work as expected.
| -rw-r--r-- | indra/llcorehttp/_httpoprequest.cpp | 4 | ||||
| -rw-r--r-- | indra/llcorehttp/httprequest.h | 175 | ||||
| -rw-r--r-- | indra/llcorehttp/tests/test_httprequest.hpp | 844 | ||||
| -rw-r--r-- | indra/llcorehttp/tests/test_llcorehttp_peer.py | 1 | 
4 files changed, 960 insertions, 64 deletions
| diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 1a770f67be..a18a164f0d 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -468,6 +468,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL));  			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); +			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); +			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		}  		break; @@ -482,6 +484,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  			curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);  			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); +			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); +			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		}  		break; diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index 9dd53f4483..ab2f302d34 100644 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -214,14 +214,46 @@ public:  	/// request in other requests (like cancellation) and will be an  	/// argument when any HttpHandler object is invoked.  	/// +	/// Headers supplied by default: +	/// - Connection: keep-alive +	/// - Accept: */* +	/// - Accept-Encoding: deflate, gzip +	/// - Keep-alive: 300 +	/// - Host: <stuff> +	/// +	/// Some headers excluded by default: +	/// - Pragma: +	/// - Cache-control: +	/// - Range: +	/// - Transfer-Encoding: +	/// - Referer: +	///  	/// @param	policy_id		Default or user-defined policy class under  	///							which this request is to be serviced.  	/// @param	priority		Standard priority scheme inherited from  	///							Indra code base (U32-type scheme). -	/// @param	url -	/// @param	options			(optional) -	/// @param	headers			(optional) -	/// @param	handler			(optional) +	/// @param	url				URL with any encoded query parameters to +	///							be accessed. +	/// @param	options			Optional instance of an HttpOptions object +	///							to provide additional controls over the request +	///							function for this request only.  Any such +	///							object then becomes shared-read across threads +	///							and no code should modify the HttpOptions +	///							instance. +	/// @param	headers			Optional instance of an HttpHeaders object +	///							to provide additional and/or overridden +	///							headers for the request.  As with options, +	///							the instance becomes shared-read across threads +	///							and no code should modify the HttpHeaders +	///							instance. +	/// @param	handler			Optional pointer to an HttpHandler instance +	///							whose onCompleted() method will be invoked +	///							during calls to update().  This is a non- +	///							reference-counted object which would be a +	///							problem for shutdown and other edge cases but +	///							the pointer is only dereferenced during +	///							calls to update(). +	///  	/// @return					The handle of the request if successfully  	///							queued or LLCORE_HTTP_HANDLE_INVALID if the  	///							request could not be queued.  In the latter @@ -244,20 +276,29 @@ public:  	/// request in other requests (like cancellation) and will be an  	/// argument when any HttpHandler object is invoked.  	/// -	/// @param	policy_id		Default or user-defined policy class under -	///							which this request is to be serviced. -	/// @param	priority		Standard priority scheme inherited from -	///							Indra code base (U32-type scheme). -	/// @param	url -	/// @param	offset -	/// @param	len -	/// @param	options			(optional) -	/// @param	headers			(optional) -	/// @param	handler			(optional) -	/// @return					The handle of the request if successfully -	///							queued or LLCORE_HTTP_HANDLE_INVALID if the -	///							request could not be queued.  In the latter -	///							case, @see getStatus() will return more info. +	/// Headers supplied by default: +	/// - Connection: keep-alive +	/// - Accept: */* +	/// - Accept-Encoding: deflate, gzip +	/// - Keep-alive: 300 +	/// - Host: <stuff> +	/// - Range: <stuff>  (will be omitted if offset == 0 and len == 0) +	/// +	/// Some headers excluded by default: +	/// - Pragma: +	/// - Cache-control: +	/// - Transfer-Encoding: +	/// - Referer: +	/// +	/// @param	policy_id		@see requestGet() +	/// @param	priority		" +	/// @param	url				" +	/// @param	offset			Offset of first byte into resource to be returned. +	/// @param	len				Count of bytes to be returned +	/// @param	options			@see requestGet() +	/// @param	headers			" +	/// @param	handler			" +	/// @return					"  	///  	HttpHandle requestGetByteRange(policy_t policy_id,  								   priority_t priority, @@ -269,22 +310,37 @@ public:  								   HttpHandler * handler); -	/// -	/// @param	policy_id		Default or user-defined policy class under -	///							which this request is to be serviced. -	/// @param	priority		Standard priority scheme inherited from -	///							Indra code base. -	/// @param	url +	/// Queue a full HTTP POST.  Query arguments and body may +	/// be provided.  Caller is responsible for escaping and +	/// encoding and communicating the content types. +	/// +	/// Headers supplied by default: +	/// - Connection: keep-alive +	/// - Accept: */* +	/// - Accept-Encoding: deflate, gzip +	/// - Keep-Alive: 300 +	/// - Host: <stuff> +	/// - Content-Length: <digits> +	/// - Content-Type: application/x-www-form-urlencoded +	/// +	/// Some headers excluded by default: +	/// - Pragma: +	/// - Cache-Control: +	/// - Transfer-Encoding: ... chunked ... +	/// - Referer: +	/// - Content-Encoding: +	/// - Expect: +	/// +	/// @param	policy_id		@see requestGet() +	/// @param	priority		" +	/// @param	url				"  	/// @param	body			Byte stream to be sent as the body.  No  	///							further encoding or escaping will be done  	///							to the content. -	/// @param	options			(optional) -	/// @param	headers			(optional) -	/// @param	handler			(optional) -	/// @return					The handle of the request if successfully -	///							queued or LLCORE_HTTP_HANDLE_INVALID if the -	///							request could not be queued.  In the latter -	///							case, @see getStatus() will return more info. +	/// @param	options			@see requestGet()K(optional) +	/// @param	headers			" +	/// @param	handler			" +	/// @return					"  	///  	HttpHandle requestPost(policy_t policy_id,  						   priority_t priority, @@ -295,22 +351,37 @@ public:  						   HttpHandler * handler); -	/// -	/// @param	policy_id		Default or user-defined policy class under -	///							which this request is to be serviced. -	/// @param	priority		Standard priority scheme inherited from -	///							Indra code base. -	/// @param	url +	/// Queue a full HTTP PUT.  Query arguments and body may +	/// be provided.  Caller is responsible for escaping and +	/// encoding and communicating the content types. +	/// +	/// Headers supplied by default: +	/// - Connection: keep-alive +	/// - Accept: */* +	/// - Accept-Encoding: deflate, gzip +	/// - Keep-Alive: 300 +	/// - Host: <stuff> +	/// - Content-Length: <digits> +	/// +	/// Some headers excluded by default: +	/// - Pragma: +	/// - Cache-Control: +	/// - Transfer-Encoding: ... chunked ... +	/// - Referer: +	/// - Content-Encoding: +	/// - Expect: +	/// - Content-Type: +	/// +	/// @param	policy_id		@see requestGet() +	/// @param	priority		" +	/// @param	url				"  	/// @param	body			Byte stream to be sent as the body.  No  	///							further encoding or escaping will be done  	///							to the content. -	/// @param	options			(optional) -	/// @param	headers			(optional) -	/// @param	handler			(optional) -	/// @return					The handle of the request if successfully -	///							queued or LLCORE_HTTP_HANDLE_INVALID if the -	///							request could not be queued.  In the latter -	///							case, @see getStatus() will return more info. +	/// @param	options			@see requestGet()K(optional) +	/// @param	headers			" +	/// @param	handler			" +	/// @return					"  	///  	HttpHandle requestPut(policy_t policy_id,  						  priority_t priority, @@ -326,11 +397,8 @@ public:  	/// immediately processes it and returns the request to the reply  	/// queue.  	/// -	/// @param	handler			(optional) -	/// @return					The handle of the request if successfully -	///							queued or LLCORE_HTTP_HANDLE_INVALID if the -	///							request could not be queued.  In the latter -	///							case, @see getStatus() will return more info. +	/// @param	handler			@see requestGet() +	/// @return					"  	///  	HttpHandle requestNoOp(HttpHandler * handler); @@ -345,7 +413,8 @@ public:  	///							spend in the call.  As hinted at above, this  	///							is partly a function of application code so it's  	///							a soft limit.  A '0' value will run without -	///							time limit. +	///							time limit until everything queued has been +	///							delivered.  	///  	/// @return					Standard status code.  	HttpStatus update(long usecs); @@ -365,10 +434,8 @@ public:  	/// @param	request			Handle of previously-issued request to  	///							be changed.  	/// @param	priority		New priority value. -	/// @param	handler			(optional) -	/// @return					The handle of the request if successfully -	///							queued or LLCORE_HTTP_HANDLE_INVALID if the -	///							request could not be queued. +	/// @param	handler			@see requestGet() +	/// @return					"  	///  	HttpHandle requestSetPriority(HttpHandle request, priority_t priority, HttpHandler * handler); diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index 1acf4f9d4b..ec144693c3 100644 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -1705,11 +1705,18 @@ void HttpRequestTestObjectType::test<16>()  		// Issue a GET that *can* connect  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\W*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\W*\\*/\\*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\W*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\W*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\W*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));  		HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -1735,12 +1742,19 @@ void HttpRequestTestObjectType::test<16>()  		mStatus = HttpStatus(200);  		handler.mHeadersRequired.clear(); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\W*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\W*\\image/x-j2c", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\W*X-Reflect-range:.*", boost::regex::icase));  		handler.mHeadersDisallowed.clear(); -		handler.mHeadersDisallowed.push_back(boost::regex("\\W*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\W*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*image/x-j2c", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("\\W*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));  		handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,  										  0U,  										  url_base + "reflect/", @@ -1830,6 +1844,816 @@ void HttpRequestTestObjectType::test<16>()  } +// Test header generation on POST requests +template <> template <> +void HttpRequestTestObjectType::test<17>() +{ +	ScopedCurlInit ready; + +	// Warmup boost::regex to pre-alloc memory for memory size tests +	boost::regex warmup("askldjflasdj;f", boost::regex::icase); +	boost::regex_match("akl;sjflajfk;ajsk", warmup); + +	std::string url_base(get_base_url()); +	 +	set_test_name("Header generation for HttpRequest POST"); + +	// Handler can be stack-allocated *if* there are no dangling +	// references to it after completion of this method. +	// Create before memory record as the string copy will bump numbers. +	TestHandler2 handler(this, "handler"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); +	mHandlerCalls = 0; + +	HttpRequest * req = NULL; +	HttpOptions * options = NULL; +	HttpHeaders * headers = NULL; +	BufferArray * ba = NULL; +	 +	try +	{ +		// Get singletons created +		HttpRequest::createService(); +		 +		// Start threading early so that thread memory is invariant +		// over the test. +		HttpRequest::startThread(); + +		// create a new ref counted object with an implicit reference +		req = new HttpRequest(); + +		// options set +		options = new HttpOptions(); +		options->setWantHeaders(true); + +		// And a buffer array +		const char * msg("It was the best of times, it was the worst of times."); +		ba = new BufferArray; +		ba->append(msg, strlen(msg)); +			 +		// Issue a default POST +		mStatus = HttpStatus(200); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); +		HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, +											 0U, +											 url_base + "reflect/", +											 ba, +											 options, +											 NULL, +											 &handler); +		ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); +		ba->release(); +		ba = NULL; +			 +		// Run the notification pump. +		int count(0); +		int limit(10); +		while (count++ < limit && mHandlerCalls < 1) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Request executed in reasonable time", count < limit); +		ensure("One handler invocation for request", mHandlerCalls == 1); + + +		// Okay, request a shutdown of the servicing thread +		mStatus = HttpStatus(); +		handler.mHeadersRequired.clear(); +		handler.mHeadersDisallowed.clear(); +		handle = req->requestStopThread(&handler); +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); +	 +		// Run the notification pump again +		count = 0; +		limit = 10; +		while (count++ < limit && mHandlerCalls < 2) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Second request executed in reasonable time", count < limit); +		ensure("Second handler invocation", mHandlerCalls == 2); + +		// See that we actually shutdown the thread +		count = 0; +		limit = 10; +		while (count++ < limit && ! HttpService::isStopped()) +		{ +			usleep(100000); +		} +		ensure("Thread actually stopped running", HttpService::isStopped()); +	 +		// release options & headers +		if (options) +		{ +			options->release(); +		} +		options = NULL; + +		if (headers) +		{ +			headers->release(); +		} +		headers = NULL; +		 +		// release the request object +		delete req; +		req = NULL; + +		// Shut down service +		HttpRequest::destroyService(); +	} +	catch (...) +	{ +		stop_thread(req); +		if (ba) +		{ +			ba->release(); +			ba = NULL; +		} +		if (options) +		{ +			options->release(); +			options = NULL; +		} +		if (headers) +		{ +			headers->release(); +			headers = NULL; +		} +		delete req; +		HttpRequest::destroyService(); +		throw; +	} +} + + +// Test header generation on PUT requests +template <> template <> +void HttpRequestTestObjectType::test<18>() +{ +	ScopedCurlInit ready; + +	// Warmup boost::regex to pre-alloc memory for memory size tests +	boost::regex warmup("askldjflasdj;f", boost::regex::icase); +	boost::regex_match("akl;sjflajfk;ajsk", warmup); + +	std::string url_base(get_base_url()); +	 +	set_test_name("Header generation for HttpRequest PUT"); + +	// Handler can be stack-allocated *if* there are no dangling +	// references to it after completion of this method. +	// Create before memory record as the string copy will bump numbers. +	TestHandler2 handler(this, "handler"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); +	mHandlerCalls = 0; + +	HttpRequest * req = NULL; +	HttpOptions * options = NULL; +	HttpHeaders * headers = NULL; +	BufferArray * ba = NULL; +	 +	try +	{ +		// Get singletons created +		HttpRequest::createService(); +		 +		// Start threading early so that thread memory is invariant +		// over the test. +		HttpRequest::startThread(); + +		// create a new ref counted object with an implicit reference +		req = new HttpRequest(); + +		// options set +		options = new HttpOptions(); +		options->setWantHeaders(true); + +		// And a buffer array +		const char * msg("It was the best of times, it was the worst of times."); +		ba = new BufferArray; +		ba->append(msg, strlen(msg)); +			 +		// Issue a default PUT +		mStatus = HttpStatus(200); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:.*", boost::regex::icase)); +		HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, +											0U, +											url_base + "reflect/", +											ba, +											options, +											NULL, +											&handler); +		ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); +		ba->release(); +		ba = NULL; +			 +		// Run the notification pump. +		int count(0); +		int limit(10); +		while (count++ < limit && mHandlerCalls < 1) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Request executed in reasonable time", count < limit); +		ensure("One handler invocation for request", mHandlerCalls == 1); + + +		// Okay, request a shutdown of the servicing thread +		mStatus = HttpStatus(); +		handler.mHeadersRequired.clear(); +		handler.mHeadersDisallowed.clear(); +		handle = req->requestStopThread(&handler); +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); +	 +		// Run the notification pump again +		count = 0; +		limit = 10; +		while (count++ < limit && mHandlerCalls < 2) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Second request executed in reasonable time", count < limit); +		ensure("Second handler invocation", mHandlerCalls == 2); + +		// See that we actually shutdown the thread +		count = 0; +		limit = 10; +		while (count++ < limit && ! HttpService::isStopped()) +		{ +			usleep(100000); +		} +		ensure("Thread actually stopped running", HttpService::isStopped()); +	 +		// release options & headers +		if (options) +		{ +			options->release(); +		} +		options = NULL; + +		if (headers) +		{ +			headers->release(); +		} +		headers = NULL; +		 +		// release the request object +		delete req; +		req = NULL; + +		// Shut down service +		HttpRequest::destroyService(); +	} +	catch (...) +	{ +		stop_thread(req); +		if (ba) +		{ +			ba->release(); +			ba = NULL; +		} +		if (options) +		{ +			options->release(); +			options = NULL; +		} +		if (headers) +		{ +			headers->release(); +			headers = NULL; +		} +		delete req; +		HttpRequest::destroyService(); +		throw; +	} +} + + +// Test header generation on GET requests with overrides +template <> template <> +void HttpRequestTestObjectType::test<19>() +{ +	ScopedCurlInit ready; + +	// Warmup boost::regex to pre-alloc memory for memory size tests +	boost::regex warmup("askldjflasdj;f", boost::regex::icase); +	boost::regex_match("akl;sjflajfk;ajsk", warmup); + +	std::string url_base(get_base_url()); +	 +	set_test_name("Header generation for HttpRequest GET with header overrides"); + +	// Handler can be stack-allocated *if* there are no dangling +	// references to it after completion of this method. +	// Create before memory record as the string copy will bump numbers. +	TestHandler2 handler(this, "handler"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); +	mHandlerCalls = 0; + +	HttpRequest * req = NULL; +	HttpOptions * options = NULL; +	HttpHeaders * headers = NULL; + +	try +	{ +		// Get singletons created +		HttpRequest::createService(); +		 +		// Start threading early so that thread memory is invariant +		// over the test. +		HttpRequest::startThread(); + +		// create a new ref counted object with an implicit reference +		req = new HttpRequest(); + +		// options set +		options = new HttpOptions(); +		options->setWantHeaders(true); + +		// headers +		headers = new HttpHeaders; +		headers->mHeaders.push_back("Keep-Alive: 120"); +		headers->mHeaders.push_back("Accept-encoding: deflate"); +		headers->mHeaders.push_back("Accept: text/plain"); + +		// Issue a GET with modified headers +		mStatus = HttpStatus(200); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/plain", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*deflate", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID, +											0U, +											url_base + "reflect/", +											options, +											headers, +											&handler); +		ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); + +		// Run the notification pump. +		int count(0); +		int limit(10); +		while (count++ < limit && mHandlerCalls < 1) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Request executed in reasonable time", count < limit); +		ensure("One handler invocation for request", mHandlerCalls == 1); + +		// Okay, request a shutdown of the servicing thread +		mStatus = HttpStatus(); +		handler.mHeadersRequired.clear(); +		handler.mHeadersDisallowed.clear(); +		handle = req->requestStopThread(&handler); +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); +	 +		// Run the notification pump again +		count = 0; +		limit = 10; +		while (count++ < limit && mHandlerCalls < 2) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Second request executed in reasonable time", count < limit); +		ensure("Second handler invocation", mHandlerCalls == 2); + +		// See that we actually shutdown the thread +		count = 0; +		limit = 10; +		while (count++ < limit && ! HttpService::isStopped()) +		{ +			usleep(100000); +		} +		ensure("Thread actually stopped running", HttpService::isStopped()); +	 +		// release options & headers +		if (options) +		{ +			options->release(); +		} +		options = NULL; + +		if (headers) +		{ +			headers->release(); +		} +		headers = NULL; +		 +		// release the request object +		delete req; +		req = NULL; + +		// Shut down service +		HttpRequest::destroyService(); +	} +	catch (...) +	{ +		stop_thread(req); +		if (options) +		{ +			options->release(); +			options = NULL; +		} +		if (headers) +		{ +			headers->release(); +			headers = NULL; +		} +		delete req; +		HttpRequest::destroyService(); +		throw; +	} +} + + +// Test header generation on POST requests with overrides +template <> template <> +void HttpRequestTestObjectType::test<20>() +{ +	ScopedCurlInit ready; + +	// Warmup boost::regex to pre-alloc memory for memory size tests +	boost::regex warmup("askldjflasdj;f", boost::regex::icase); +	boost::regex_match("akl;sjflajfk;ajsk", warmup); + +	std::string url_base(get_base_url()); +	 +	set_test_name("Header generation for HttpRequest POST with header overrides"); + +	// Handler can be stack-allocated *if* there are no dangling +	// references to it after completion of this method. +	// Create before memory record as the string copy will bump numbers. +	TestHandler2 handler(this, "handler"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); +	mHandlerCalls = 0; + +	HttpRequest * req = NULL; +	HttpOptions * options = NULL; +	HttpHeaders * headers = NULL; +	BufferArray * ba = NULL; +	 +	try +	{ +		// Get singletons created +		HttpRequest::createService(); +		 +		// Start threading early so that thread memory is invariant +		// over the test. +		HttpRequest::startThread(); + +		// create a new ref counted object with an implicit reference +		req = new HttpRequest(); + +		// options set +		options = new HttpOptions(); +		options->setWantHeaders(true); + +		// headers +		headers = new HttpHeaders(); +		headers->mHeaders.push_back("keep-Alive: 120"); +		headers->mHeaders.push_back("Accept:  text/html"); +		headers->mHeaders.push_back("content-type:  application/llsd+xml"); +		headers->mHeaders.push_back("cache-control: no-store"); +		 +		// And a buffer array +		const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); +		ba = new BufferArray; +		ba->append(msg, strlen(msg)); +			 +		// Issue a default POST +		mStatus = HttpStatus(200); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/html", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("\\s*X-Reflect-cache-control:\\s*no-store", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); +		HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID, +											 0U, +											 url_base + "reflect/", +											 ba, +											 options, +											 headers, +											 &handler); +		ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); +		ba->release(); +		ba = NULL; +			 +		// Run the notification pump. +		int count(0); +		int limit(10); +		while (count++ < limit && mHandlerCalls < 1) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Request executed in reasonable time", count < limit); +		ensure("One handler invocation for request", mHandlerCalls == 1); + + +		// Okay, request a shutdown of the servicing thread +		mStatus = HttpStatus(); +		handler.mHeadersRequired.clear(); +		handler.mHeadersDisallowed.clear(); +		handle = req->requestStopThread(&handler); +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); +	 +		// Run the notification pump again +		count = 0; +		limit = 10; +		while (count++ < limit && mHandlerCalls < 2) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Second request executed in reasonable time", count < limit); +		ensure("Second handler invocation", mHandlerCalls == 2); + +		// See that we actually shutdown the thread +		count = 0; +		limit = 10; +		while (count++ < limit && ! HttpService::isStopped()) +		{ +			usleep(100000); +		} +		ensure("Thread actually stopped running", HttpService::isStopped()); +	 +		// release options & headers +		if (options) +		{ +			options->release(); +		} +		options = NULL; + +		if (headers) +		{ +			headers->release(); +		} +		headers = NULL; +		 +		// release the request object +		delete req; +		req = NULL; + +		// Shut down service +		HttpRequest::destroyService(); +	} +	catch (...) +	{ +		stop_thread(req); +		if (ba) +		{ +			ba->release(); +			ba = NULL; +		} +		if (options) +		{ +			options->release(); +			options = NULL; +		} +		if (headers) +		{ +			headers->release(); +			headers = NULL; +		} +		delete req; +		HttpRequest::destroyService(); +		throw; +	} +} + + +// Test header generation on PUT requests with overrides +template <> template <> +void HttpRequestTestObjectType::test<21>() +{ +	ScopedCurlInit ready; + +	// Warmup boost::regex to pre-alloc memory for memory size tests +	boost::regex warmup("askldjflasdj;f", boost::regex::icase); +	boost::regex_match("akl;sjflajfk;ajsk", warmup); + +	std::string url_base(get_base_url()); +	 +	set_test_name("Header generation for HttpRequest PUT with header overrides"); + +	// Handler can be stack-allocated *if* there are no dangling +	// references to it after completion of this method. +	// Create before memory record as the string copy will bump numbers. +	TestHandler2 handler(this, "handler"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); +	mHandlerCalls = 0; + +	HttpRequest * req = NULL; +	HttpOptions * options = NULL; +	HttpHeaders * headers = NULL; +	BufferArray * ba = NULL; +	 +	try +	{ +		// Get singletons created +		HttpRequest::createService(); +		 +		// Start threading early so that thread memory is invariant +		// over the test. +		HttpRequest::startThread(); + +		// create a new ref counted object with an implicit reference +		req = new HttpRequest(); + +		// options set +		options = new HttpOptions(); +		options->setWantHeaders(true); + +		// headers +		headers = new HttpHeaders; +		headers->mHeaders.push_back("content-type:  text/plain"); +		headers->mHeaders.push_back("content-type:  text/html"); +		headers->mHeaders.push_back("content-type:  application/llsd+xml"); +		 +		// And a buffer array +		const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); +		ba = new BufferArray; +		ba->append(msg, strlen(msg)); +			 +		// Issue a default PUT +		mStatus = HttpStatus(200); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); +		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/plain", boost::regex::icase)); +		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/html", boost::regex::icase)); +		HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID, +											0U, +											url_base + "reflect/", +											ba, +											options, +											headers, +											&handler); +		ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID); +		ba->release(); +		ba = NULL; +			 +		// Run the notification pump. +		int count(0); +		int limit(10); +		while (count++ < limit && mHandlerCalls < 1) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Request executed in reasonable time", count < limit); +		ensure("One handler invocation for request", mHandlerCalls == 1); + + +		// Okay, request a shutdown of the servicing thread +		mStatus = HttpStatus(); +		handler.mHeadersRequired.clear(); +		handler.mHeadersDisallowed.clear(); +		handle = req->requestStopThread(&handler); +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); +	 +		// Run the notification pump again +		count = 0; +		limit = 10; +		while (count++ < limit && mHandlerCalls < 2) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Second request executed in reasonable time", count < limit); +		ensure("Second handler invocation", mHandlerCalls == 2); + +		// See that we actually shutdown the thread +		count = 0; +		limit = 10; +		while (count++ < limit && ! HttpService::isStopped()) +		{ +			usleep(100000); +		} +		ensure("Thread actually stopped running", HttpService::isStopped()); +	 +		// release options & headers +		if (options) +		{ +			options->release(); +		} +		options = NULL; + +		if (headers) +		{ +			headers->release(); +		} +		headers = NULL; +		 +		// release the request object +		delete req; +		req = NULL; + +		// Shut down service +		HttpRequest::destroyService(); +	} +	catch (...) +	{ +		stop_thread(req); +		if (ba) +		{ +			ba->release(); +			ba = NULL; +		} +		if (options) +		{ +			options->release(); +			options = NULL; +		} +		if (headers) +		{ +			headers->release(); +			headers = NULL; +		} +		delete req; +		HttpRequest::destroyService(); +		throw; +	} +} + +  }  // end namespace tut  namespace diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index c527ce6ce0..75a3c39ef2 100644 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -141,6 +141,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):      def reflect_headers(self):          for name in self.headers.keys(): +            # print "Header:  %s: %s" % (name, self.headers[name])              self.send_header("X-Reflect-" + name, self.headers[name])      if not VERBOSE: | 
