diff options
Diffstat (limited to 'indra/llcorehttp/tests')
| -rwxr-xr-x | indra/llcorehttp/tests/test_httpheaders.hpp | 345 | ||||
| -rwxr-xr-x | indra/llcorehttp/tests/test_httprequest.hpp | 701 | ||||
| -rwxr-xr-x | indra/llcorehttp/tests/test_httpstatus.hpp | 59 | ||||
| -rwxr-xr-x | indra/llcorehttp/tests/test_llcorehttp_peer.py | 72 | 
4 files changed, 1030 insertions, 147 deletions
| diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp index ce0d19b058..668c36dc66 100755 --- a/indra/llcorehttp/tests/test_httpheaders.hpp +++ b/indra/llcorehttp/tests/test_httpheaders.hpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc.   *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -36,7 +36,6 @@  using namespace LLCoreInt; -  namespace tut  { @@ -63,7 +62,7 @@ void HttpHeadersTestObjectType::test<1>()  	HttpHeaders * headers = new HttpHeaders();  	ensure("One ref on construction of HttpHeaders", headers->getRefCount() == 1);  	ensure("Memory being used", mMemTotal < GetMemTotal()); -	ensure("Nothing in headers", 0 == headers->mHeaders.size()); +	ensure("Nothing in headers", 0 == headers->size());  	// release the implicit reference, causing the object to be released  	headers->release(); @@ -85,14 +84,340 @@ void HttpHeadersTestObjectType::test<2>()  	{  		// Append a few strings -		std::string str1("Pragma:"); -		headers->mHeaders.push_back(str1); -		std::string str2("Accept: application/json"); -		headers->mHeaders.push_back(str2); +		std::string str1n("Pragma"); +		std::string str1v(""); +		headers->append(str1n, str1v); +		std::string str2n("Accept"); +		std::string str2v("application/json"); +		headers->append(str2n, str2v); +	 +		ensure("Headers retained", 2 == headers->size()); +		HttpHeaders::container_t & c(headers->getContainerTESTONLY()); +		 +		ensure("First name is first name", c[0].first == str1n); +		ensure("First value is first value", c[0].second == str1v); +		ensure("Second name is second name", c[1].first == str2n); +		ensure("Second value is second value", c[1].second == str2v); +	} +	 +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +template <> template <> +void HttpHeadersTestObjectType::test<3>() +{ +	set_test_name("HttpHeaders basic find"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); +	 +	{ +		// Append a few strings +		std::string str1n("Uno"); +		std::string str1v("1"); +		headers->append(str1n, str1v); +		std::string str2n("doS"); +		std::string str2v("2-2-2-2"); +		headers->append(str2n, str2v); +		std::string str3n("TRES"); +		std::string str3v("trois gymnopedie"); +		headers->append(str3n, str3v); +	 +		ensure("Headers retained", 3 == headers->size()); + +		const std::string * result(NULL); + +		// Find a header +		result = headers->find("TRES"); +		ensure("Found the last item", result != NULL); +		ensure("Last item is a nice", result != NULL && str3v == *result); + +		// appends above are raw and find is case sensitive +		result = headers->find("TReS"); +		ensure("Last item not found due to case", result == NULL); + +		result = headers->find("TRE"); +		ensure("Last item not found due to prefixing (1)", result == NULL); + +		result = headers->find("TRESS"); +		ensure("Last item not found due to prefixing (2)", result == NULL); +	} +	 +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +template <> template <> +void HttpHeadersTestObjectType::test<4>() +{ +	set_test_name("HttpHeaders normalized header entry"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); +	 +	{ +		static char line1[] = " AcCePT : image/yourfacehere"; +		static char line1v[] = "image/yourfacehere"; +		headers->appendNormal(line1, sizeof(line1) - 1); +		 +		ensure("First append worked in some fashion", 1 == headers->size()); + +		const std::string * result(NULL); + +		// Find a header +		result = headers->find("accept"); +		ensure("Found 'accept'", result != NULL); +		ensure("accept value has face", result != NULL && *result == line1v); + +		// Left-clean on value +		static char line2[] = " next : \t\tlinejunk \t"; +		headers->appendNormal(line2, sizeof(line2) - 1); +		ensure("Second append worked", 2 == headers->size()); +		result = headers->find("next"); +		ensure("Found 'next'", result != NULL); +		ensure("next value is left-clean", result != NULL && +			   *result == "linejunk \t"); + +		// First value unmolested +		result = headers->find("accept"); +		ensure("Found 'accept' again", result != NULL); +		ensure("accept value has face", result != NULL && *result == line1v); + +		// Colons in value are okay +		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; +		static char line3v[] = ":plop:-neuf-=vleem="; +		headers->appendNormal(line3, sizeof(line3) - 1); +		ensure("Third append worked", 3 == headers->size()); +		result = headers->find("fancy-pants"); +		ensure("Found 'fancy-pants'", result != NULL); +		ensure("fancy-pants value has colons", result != NULL && *result == line3v); + +		// Zero-length value +		static char line4[] = "all-talk-no-walk:"; +		headers->appendNormal(line4, sizeof(line4) - 1); +		ensure("Fourth append worked", 4 == headers->size()); +		result = headers->find("all-talk-no-walk"); +		ensure("Found 'all-talk'", result != NULL); +		ensure("al-talk value is zero-length", result != NULL && result->size() == 0); + +		// Zero-length name +		static char line5[] = ":all-talk-no-walk"; +		static char line5v[] = "all-talk-no-walk"; +		headers->appendNormal(line5, sizeof(line5) - 1); +		ensure("Fifth append worked", 5 == headers->size()); +		result = headers->find(""); +		ensure("Found no-name", result != NULL); +		ensure("no-name value is something", result != NULL && *result == line5v); + +		// Lone colon is still something +		headers->clear(); +		static char line6[] = "  :"; +		headers->appendNormal(line6, sizeof(line6) - 1); +		ensure("Sixth append worked", 1 == headers->size()); +		result = headers->find(""); +		ensure("Found 2nd no-name", result != NULL); +		ensure("2nd no-name value is nothing", result != NULL && result->size() == 0); + +		// Line without colons is taken as-is and unstripped in name +		static char line7[] = " \toskdgioasdghaosdghoowg28342908tg8902hg0hwedfhqew890v7qh0wdebv78q0wdevbhq>?M>BNM<ZV>?NZ? \t"; +		headers->appendNormal(line7, sizeof(line7) - 1); +		ensure("Seventh append worked", 2 == headers->size()); +		result = headers->find(line7); +		ensure("Found whatsit line", result != NULL); +		ensure("Whatsit line has no value", result != NULL && result->size() == 0); + +		// Normaling interface heeds the byte count, doesn't look for NUL-terminator +		static char line8[] = "binary:ignorestuffontheendofthis"; +		headers->appendNormal(line8, 13); +		ensure("Eighth append worked", 3 == headers->size()); +		result = headers->find("binary"); +		ensure("Found 'binary'", result != NULL); +		ensure("binary value was limited to 'ignore'", result != NULL && +			   *result == "ignore"); + +	} -		ensure("Headers retained", 2 == headers->mHeaders.size()); -		ensure("First is first", headers->mHeaders[0] == str1); -		ensure("Second is second", headers->mHeaders[1] == str2); +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +// Verify forward iterator finds everything as expected +template <> template <> +void HttpHeadersTestObjectType::test<5>() +{ +	set_test_name("HttpHeaders iterator tests"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); + +	HttpHeaders::iterator end(headers->end()), begin(headers->begin()); +	ensure("Empty container has equal begin/end const iterators", end == begin); +	HttpHeaders::const_iterator cend(headers->end()), cbegin(headers->begin()); +	ensure("Empty container has equal rbegin/rend const iterators", cend == cbegin); + +	ensure("Empty container has equal begin/end iterators", headers->end() == headers->begin()); +	 +	{ +		static char line1[] = " AcCePT : image/yourfacehere"; +		static char line1v[] = "image/yourfacehere"; +		headers->appendNormal(line1, sizeof(line1) - 1); + +		static char line2[] = " next : \t\tlinejunk \t"; +		static char line2v[] = "linejunk \t"; +		headers->appendNormal(line2, sizeof(line2) - 1); + +		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; +		static char line3v[] = ":plop:-neuf-=vleem="; +		headers->appendNormal(line3, sizeof(line3) - 1); + +		static char line4[] = "all-talk-no-walk:"; +		static char line4v[] = ""; +		headers->appendNormal(line4, sizeof(line4) - 1); + +		static char line5[] = ":all-talk-no-walk"; +		static char line5v[] = "all-talk-no-walk"; +		headers->appendNormal(line5, sizeof(line5) - 1); + +		static char line6[] = "  :"; +		static char line6v[] = ""; +		headers->appendNormal(line6, sizeof(line6) - 1); + +		ensure("All entries accounted for", 6 == headers->size()); + +		static char * values[] = { +			line1v, +			line2v, +			line3v, +			line4v, +			line5v, +			line6v +		}; +			 +		int i(0); +		HttpHeaders::const_iterator cend(headers->end()); +		for (HttpHeaders::const_iterator it(headers->begin()); +			 cend != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Const Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		} + +		// Rewind, do non-consts +		i = 0; +		HttpHeaders::iterator end(headers->end()); +		for (HttpHeaders::iterator it(headers->begin()); +			 end != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Const Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		} +	} +	 +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +// Reverse iterators find everything as expected +template <> template <> +void HttpHeadersTestObjectType::test<6>() +{ +	set_test_name("HttpHeaders reverse iterator tests"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); + +	HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin()); +	ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin); +	HttpHeaders::const_reverse_iterator crend(headers->rend()), crbegin(headers->rbegin()); +	ensure("Empty container has equal rbegin/rend const iterators", crend == crbegin); +	 +	{ +		static char line1[] = " AcCePT : image/yourfacehere"; +		static char line1v[] = "image/yourfacehere"; +		headers->appendNormal(line1, sizeof(line1) - 1); + +		static char line2[] = " next : \t\tlinejunk \t"; +		static char line2v[] = "linejunk \t"; +		headers->appendNormal(line2, sizeof(line2) - 1); + +		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; +		static char line3v[] = ":plop:-neuf-=vleem="; +		headers->appendNormal(line3, sizeof(line3) - 1); + +		static char line4[] = "all-talk-no-walk:"; +		static char line4v[] = ""; +		headers->appendNormal(line4, sizeof(line4) - 1); + +		static char line5[] = ":all-talk-no-walk"; +		static char line5v[] = "all-talk-no-walk"; +		headers->appendNormal(line5, sizeof(line5) - 1); + +		static char line6[] = "  :"; +		static char line6v[] = ""; +		headers->appendNormal(line6, sizeof(line6) - 1); + +		ensure("All entries accounted for", 6 == headers->size()); + +		static char * values[] = { +			line6v, +			line5v, +			line4v, +			line3v, +			line2v, +			line1v +		}; +			 +		int i(0); +		HttpHeaders::const_reverse_iterator cend(headers->rend()); +		for (HttpHeaders::const_reverse_iterator it(headers->rbegin()); +			 cend != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Const Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		} + +		// Rewind, do non-consts +		i = 0; +		HttpHeaders::reverse_iterator end(headers->rend()); +		for (HttpHeaders::reverse_iterator it(headers->rbegin()); +			 end != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		}  	}  	// release the implicit reference, causing the object to be released diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index 900a699887..2311753c65 100755 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -69,6 +69,8 @@ void usleep(unsigned long usec);  namespace tut  { +typedef std::vector<std::pair<boost::regex, boost::regex> > regex_container_t; +  struct HttpRequestTestData  {  	// the test objects inherit from this so the member functions and variables @@ -118,11 +120,17 @@ public:  					for (int i(0); i < mHeadersRequired.size(); ++i)  					{  						bool found = false; -						for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin()); -							 header->mHeaders.end() != iter; +						for (HttpHeaders::const_iterator iter(header->begin()); +							 header->end() != iter;  							 ++iter)  						{ -							if (boost::regex_match(*iter, mHeadersRequired[i])) +							// std::cerr << "Header: " << (*iter).first +							//		  << ": " << (*iter).second << std::endl; +							 +							if (boost::regex_match((*iter).first, +												   mHeadersRequired[i].first) && +								boost::regex_match((*iter).second, +												   mHeadersRequired[i].second))  							{  								found = true;  								break; @@ -138,11 +146,14 @@ public:  				{  					for (int i(0); i < mHeadersDisallowed.size(); ++i)  					{ -						for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin()); -							 header->mHeaders.end() != iter; +						for (HttpHeaders::const_iterator iter(header->begin()); +							 header->end() != iter;  							 ++iter)  						{ -							if (boost::regex_match(*iter, mHeadersDisallowed[i])) +							if (boost::regex_match((*iter).first, +												   mHeadersDisallowed[i].first) && +								boost::regex_match((*iter).second, +												   mHeadersDisallowed[i].second))  							{  								std::ostringstream str;  								str << "Disallowed header # " << i << " not found in response"; @@ -168,8 +179,8 @@ public:  	std::string mName;  	HttpHandle mExpectHandle;  	std::string mCheckContentType; -	std::vector<boost::regex> mHeadersRequired; -	std::vector<boost::regex> mHeadersDisallowed; +	regex_container_t mHeadersRequired; +	regex_container_t mHeadersDisallowed;  };  typedef test_group<HttpRequestTestData> HttpRequestTestGroupType; @@ -1211,7 +1222,7 @@ void HttpRequestTestObjectType::test<12>()  		HttpRequest::createService();  		// Enable tracing -		HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2); +		HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);  		// Start threading early so that thread memory is invariant  		// over the test. @@ -1329,7 +1340,7 @@ void HttpRequestTestObjectType::test<13>()  		HttpRequest::createService();  		// Enable tracing -		HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2); +		HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);  		// Start threading early so that thread memory is invariant  		// over the test. @@ -1344,7 +1355,9 @@ void HttpRequestTestObjectType::test<13>()  		// Issue a GET that succeeds  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("\\W*X-LL-Special:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase), +										  boost::regex(".*", boost::regex::icase)));  		HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,  													 0U,  													 url_base, @@ -1711,18 +1724,54 @@ void HttpRequestTestObjectType::test<16>()  		// Issue a GET that *can* connect  		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.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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase)));  		HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -1744,23 +1793,60 @@ void HttpRequestTestObjectType::test<16>()  		// Do a texture-style fetch  		headers = new HttpHeaders; -		headers->mHeaders.push_back("Accept: image/x-j2c"); +		headers->append("Accept", "image/x-j2c");  		mStatus = HttpStatus(200);  		handler.mHeadersRequired.clear();  		handler.mHeadersDisallowed.clear(); -		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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("image/x-j2c", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("\\W*X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase)));  		handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,  										  0U,  										  url_base + "reflect/", @@ -1901,20 +1987,63 @@ void HttpRequestTestObjectType::test<17>()  		// 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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer_encoding", boost::regex::icase), +				boost::regex(".*chunked.*", boost::regex::icase)));  		HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,  											 0U,  											 url_base + "reflect/", @@ -2061,20 +2190,64 @@ void HttpRequestTestObjectType::test<18>()  		// 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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*chunked.*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +  		HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -2215,27 +2388,73 @@ void HttpRequestTestObjectType::test<19>()  		// 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"); +		headers->append("Keep-Alive", "120"); +		headers->append("Accept-encoding", "deflate"); +		headers->append("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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("text/plain", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("deflate", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("120", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("300", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase)));  		HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -2368,10 +2587,10 @@ void HttpRequestTestObjectType::test<20>()  		// 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"); +		headers->append("keep-Alive", "120"); +		headers->append("Accept", "text/html"); +		headers->append("content-type", "application/llsd+xml"); +		headers->append("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>"); @@ -2380,23 +2599,76 @@ void HttpRequestTestObjectType::test<20>()  		// 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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("text/html", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("120", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/llsd\\+xml", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex("no-store", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("300", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +  		HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,  											 0U,  											 url_base + "reflect/", @@ -2538,9 +2810,9 @@ void HttpRequestTestObjectType::test<21>()  		// 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"); +		headers->append("content-type", "text/plain"); +		headers->append("content-type", "text/html"); +		headers->append("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>"); @@ -2549,22 +2821,71 @@ void HttpRequestTestObjectType::test<21>()  		// 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)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/llsd\\+xml", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("text/plain", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("text/html", boost::regex::icase)));  		HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -2854,6 +3175,142 @@ void HttpRequestTestObjectType::test<22>()  	}  } +template <> template <> +void HttpRequestTestObjectType::test<23>() +{ +	ScopedCurlInit ready; + +	set_test_name("HttpRequest GET 503s with 'Retry-After'"); + +	// This tests mainly that the code doesn't fall over if +	// various well- and mis-formed Retry-After headers are +	// sent along with the response.  Direct inspection of +	// the parsing result isn't supported. +	 +	// 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"); +	std::string url_base(get_base_url() + "/503/");	// path to 503 generators +		 +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); +	mHandlerCalls = 0; + +	HttpRequest * req = NULL; +	HttpOptions * opts = 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(); +		ensure("Memory allocated on construction", mMemTotal < GetMemTotal()); + +		opts = new HttpOptions(); +		opts->setRetries(1);			// Retry once only +		opts->setUseRetryAfter(true);	// Try to parse the retry-after header +		 +		// Issue a GET that 503s with valid retry-after +		mStatus = HttpStatus(503); +		int url_limit(6); +		for (int i(0); i < url_limit; ++i) +		{ +			std::ostringstream url; +			url << url_base << i << "/"; +			HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, +														 0U, +														 url.str(), +														 0, +														 0, +														 opts, +														 NULL, +														 &handler); + +			std::ostringstream testtag; +			testtag << "Valid handle returned for 503 request #" << i; +			ensure(testtag.str(), handle != LLCORE_HTTP_HANDLE_INVALID); +		} +		 + +		// Run the notification pump. +		int count(0); +		int limit(300);				// One retry but several seconds needed +		while (count++ < limit && mHandlerCalls < url_limit) +		{ +			req->update(0); +			usleep(100000); +		} +		ensure("Request executed in reasonable time", count < limit); +		ensure("One handler invocation for request", mHandlerCalls == url_limit); + +		// Okay, request a shutdown of the servicing thread +		mStatus = HttpStatus(); +		mHandlerCalls = 0; +		HttpHandle handle = req->requestStopThread(&handler); +		ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID); +	 +		// Run the notification pump again +		count = 0; +		limit = 100; +		while (count++ < limit && mHandlerCalls < 1) +		{ +			req->update(1000000); +			usleep(100000); +		} +		ensure("Second request executed in reasonable time", count < limit); +		ensure("Second handler invocation", mHandlerCalls == 1); + +		// 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 +		opts->release(); +		opts = NULL; +		 +		// release the request object +		delete req; +		req = NULL; + +		// Shut down service +		HttpRequest::destroyService(); +	 +#if defined(WIN32) +		// Can only do this memory test on Windows.  On other platforms, +		// the LL logging system holds on to memory and produces what looks +		// like memory leaks... +	 +		// printf("Old mem:  %d, New mem:  %d\n", mMemTotal, GetMemTotal()); +		ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal()); +#endif +	} +	catch (...) +	{ +		stop_thread(req); +		if (opts) +		{ +			opts->release(); +			opts = NULL; +		} +		delete req; +		HttpRequest::destroyService(); +		throw; +	} +} + +  }  // end namespace tut  namespace diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp index b5538528c5..0b379836c9 100755 --- a/indra/llcorehttp/tests/test_httpstatus.hpp +++ b/indra/llcorehttp/tests/test_httpstatus.hpp @@ -259,6 +259,65 @@ void HttpStatusTestObjectType::test<7>()  	ensure(msg == "Unknown error");  } + +template <> template <> +void HttpStatusTestObjectType::test<8>() +{ +	set_test_name("HttpStatus toHex() nominal function"); +	 +	HttpStatus status(404); +	std::string msg = status.toHex(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure(msg == "01940001"); +} + + +template <> template <> +void HttpStatusTestObjectType::test<9>() +{ +	set_test_name("HttpStatus toTerseString() nominal function"); +	 +	HttpStatus status(404); +	std::string msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Normal HTTP 404", msg == "Http_404"); + +	status = HttpStatus(200); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Normal HTTP 200", msg == "Http_200"); + +	status = HttpStatus(200, HE_REPLY_ERROR); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Unsuccessful HTTP 200", msg == "Http_200");			// No distinction for error + +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Easy couldn't connect error", msg == "Easy_7"); + +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Multi out-of-memory error", msg == "Multi_3"); + +	status = HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_SET); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Core option not set error", msg == "Core_7"); + +	status = HttpStatus(22000, 1); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Undecodable error", msg == "Unknown_1"); + +	status = HttpStatus(22000, -1); +	msg = status.toTerseString(); +	// std::cout << "Result:  " << msg << std::endl; +	ensure("Undecodable error 65535", msg == "Unknown_65535"); +} +  } // end namespace tut  #endif	// TEST_HTTP_STATUS_H diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index 3c3af8dc75..04cde651c4 100755 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -69,6 +69,15 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):                             "Content-Range: bytes 0-75/2983",                             "Content-Length: 76"      -- '/bug2295/inv_cont_range/0/'  Generates HE_INVALID_CONTENT_RANGE error in llcorehttp. +    - '/503/'           Generate 503 responses with various kinds +                        of 'retry-after' headers +    -- '/503/0/'            "Retry-After: 2"    +    -- '/503/1/'            "Retry-After: Thu, 31 Dec 2043 23:59:59 GMT" +    -- '/503/2/'            "Retry-After: Fri, 31 Dec 1999 23:59:59 GMT" +    -- '/503/3/'            "Retry-After: " +    -- '/503/4/'            "Retry-After: (*#*(@*(@(")" +    -- '/503/5/'            "Retry-After: aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo" +    -- '/503/6/'            "Retry-After: 1 2 3 4 5 6 7 8 9 10"      Some combinations make no sense, there's no effort to protect      you from that. @@ -143,22 +152,40 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):          if "/sleep/" in self.path:              time.sleep(30) -        if "fail" in self.path: -            status = data.get("status", 500) -            # self.responses maps an int status to a (short, long) pair of -            # strings. We want the longer string. That's why we pass a string -            # pair to get(): the [1] will select the second string, whether it -            # came from self.responses or from our default pair. -            reason = data.get("reason", -                               self.responses.get(status, -                                                  ("fail requested", -                                                   "Your request specified failure status %s " -                                                   "without providing a reason" % status))[1]) -            debug("fail requested: %s: %r", status, reason) -            self.send_error(status, reason) +        if "/503/" in self.path: +            # Tests for various kinds of 'Retry-After' header parsing +            body = None +            if "/503/0/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "2") +            elif "/503/1/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "Thu, 31 Dec 2043 23:59:59 GMT") +            elif "/503/2/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "Fri, 31 Dec 1999 23:59:59 GMT") +            elif "/503/3/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "") +            elif "/503/4/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "(*#*(@*(@(") +            elif "/503/5/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo") +            elif "/503/6/" in self.path: +                self.send_response(503) +                self.send_header("retry-after", "1 2 3 4 5 6 7 8 9 10") +            else: +                # Unknown request +                self.send_response(400) +                body = "Unknown /503/ path in server"              if "/reflect/" in self.path:                  self.reflect_headers() +            self.send_header("Content-type", "text/plain")              self.end_headers() +            if body: +                self.wfile.write(body)          elif "/bug2295/" in self.path:              # Test for https://jira.secondlife.com/browse/BUG-2295              # @@ -194,8 +221,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):              self.end_headers()              if body:                  self.wfile.write(body) -        else: -            # Normal response path +        elif "fail" not in self.path:              data = data.copy()          # we're going to modify              # Ensure there's a "reply" key in data, even if there wasn't before              data["reply"] = data.get("reply", llsd.LLSD("success")) @@ -210,6 +236,22 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):              self.end_headers()              if withdata:                  self.wfile.write(response) +        else:                           # fail requested +            status = data.get("status", 500) +            # self.responses maps an int status to a (short, long) pair of +            # strings. We want the longer string. That's why we pass a string +            # pair to get(): the [1] will select the second string, whether it +            # came from self.responses or from our default pair. +            reason = data.get("reason", +                               self.responses.get(status, +                                                  ("fail requested", +                                                   "Your request specified failure status %s " +                                                   "without providing a reason" % status))[1]) +            debug("fail requested: %s: %r", status, reason) +            self.send_error(status, reason) +            if "/reflect/" in self.path: +                self.reflect_headers() +            self.end_headers()      def reflect_headers(self):          for name in self.headers.keys(): | 
