diff options
Diffstat (limited to 'indra/llcorehttp')
| -rwxr-xr-x | indra/llcorehttp/_httplibcurl.cpp | 17 | ||||
| -rwxr-xr-x | indra/llcorehttp/_httpoprequest.cpp | 12 | ||||
| -rwxr-xr-x | indra/llcorehttp/examples/http_texture_load.cpp | 4 | ||||
| -rwxr-xr-x | indra/llcorehttp/httpheaders.cpp | 141 | ||||
| -rwxr-xr-x | indra/llcorehttp/httpheaders.h | 112 | ||||
| -rwxr-xr-x | indra/llcorehttp/tests/test_httpheaders.hpp | 345 | ||||
| -rwxr-xr-x | indra/llcorehttp/tests/test_httprequest.hpp | 563 | 
7 files changed, 1040 insertions, 154 deletions
| diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index 6fe0bfc7d1..d187697e7b 100755 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -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 @@ -359,12 +359,17 @@ int HttpLibcurl::getActiveCountInClass(int policy_class) const  struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist)  { -	for (HttpHeaders::container_t::const_iterator it(headers->mHeaders.begin()); - -		headers->mHeaders.end() != it; -		 ++it) +	const HttpHeaders::const_iterator end(headers->end()); +	for (HttpHeaders::const_iterator it(headers->begin()); end != it; ++it)  	{ -		slist = curl_slist_append(slist, (*it).c_str()); +		static const char sep[] = ": "; +		std::string header; +		header.reserve((*it).first.size() + (*it).second.size() + sizeof(sep)); +		header.append((*it).first); +		header.append(sep); +		header.append((*it).second); +		 +		slist = curl_slist_append(slist, header.c_str());  	}  	return slist;  } diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index d403b2d249..a4c0a12fdc 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -618,7 +618,8 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi  	const size_t hdr_size(size * nmemb);  	const char * hdr_data(static_cast<const char *>(data));		// Not null terminated - +	bool is_header(true); +	  	if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len))  	{  		// One of possibly several status lines.  Reset what we know and start over @@ -629,8 +630,9 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi  		op->mStatus = HttpStatus();  		if (op->mReplyHeaders)  		{ -			op->mReplyHeaders->mHeaders.clear(); +			op->mReplyHeaders->clear();  		} +		is_header = false;  	}  	// Nothing in here wants a final CR/LF combination.  Remove @@ -645,18 +647,18 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi  	}  	// Save header if caller wants them in the response -	if (op->mProcFlags & PF_SAVE_HEADERS) +	if (is_header && op->mProcFlags & PF_SAVE_HEADERS)  	{  		// Save headers in response  		if (! op->mReplyHeaders)  		{  			op->mReplyHeaders = new HttpHeaders;  		} -		op->mReplyHeaders->mHeaders.push_back(std::string(hdr_data, wanted_hdr_size)); +		op->mReplyHeaders->appendNormal(hdr_data, wanted_hdr_size);  	}  	// Detect and parse 'Content-Range' headers -	if (op->mProcFlags & PF_SCAN_RANGE_HEADER) +	if (is_header && op->mProcFlags & PF_SCAN_RANGE_HEADER)  	{  		char hdr_buffer[128];			// Enough for a reasonable header  		size_t frag_size((std::min)(wanted_hdr_size, sizeof(hdr_buffer) - 1)); diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp index 40ad4f047d..909dc5b0cb 100755 --- a/indra/llcorehttp/examples/http_texture_load.cpp +++ b/indra/llcorehttp/examples/http_texture_load.cpp @@ -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 @@ -328,7 +328,7 @@ WorkingSet::WorkingSet()  	mTextures.reserve(30000);  	mHeaders = new LLCore::HttpHeaders; -	mHeaders->mHeaders.push_back("Accept: image/x-j2c"); +	mHeaders->append("Accept", "image/x-j2c");  } diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp index 2832696271..23ebea361c 100755 --- a/indra/llcorehttp/httpheaders.cpp +++ b/indra/llcorehttp/httpheaders.cpp @@ -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 @@ -26,6 +26,8 @@  #include "httpheaders.h" +#include "llstring.h" +  namespace LLCore  { @@ -40,5 +42,142 @@ HttpHeaders::~HttpHeaders()  {} +void +HttpHeaders::clear() +{ +	mHeaders.clear(); +} + + +void HttpHeaders::append(const std::string & name, const std::string & value) +{ +	mHeaders.push_back(value_type(name, value)); +} + + +void HttpHeaders::append(const char * name, const char * value) +{ +	mHeaders.push_back(value_type(name, value)); +} + + +void HttpHeaders::appendNormal(const char * header, size_t size) +{ +	std::string name; +	std::string value; + +	int col_pos(0); +	for (; col_pos < size; ++col_pos) +	{ +		if (':' == header[col_pos]) +			break; +	} +	 +	if (col_pos < size) +	{ +		// Looks like a header, split it and normalize. +		// Name is everything before the colon, may be zero-length. +		name.assign(header, col_pos); + +		// Value is everything after the colon, may also be zero-length. +		const size_t val_len(size - col_pos - 1); +		if (val_len) +		{ +			value.assign(header + col_pos + 1, val_len); +		} + +		// Clean the strings +		LLStringUtil::toLower(name); +		LLStringUtil::trim(name); +		LLStringUtil::trimHead(value); +	} +	else +	{ +		// Uncertain what this is, we'll pack it as +		// a name without a value.  Won't clean as we don't +		// know what it is... +		name.assign(header, size); +	} + +	mHeaders.push_back(value_type(name, value)); +} + + +// Find from end to simulate a tradition of using single-valued +// std::map for this in the past. +const std::string * HttpHeaders::find(const char * name) const +{ +	const_reverse_iterator iend(rend()); +	for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) +	{ +		if ((*iter).first == name) +		{ +			return &(*iter).second; +		} +	} +	return NULL; +} + + +// Standard Iterators +HttpHeaders::iterator HttpHeaders::begin() +{ +	return mHeaders.begin(); +} + + +HttpHeaders::const_iterator HttpHeaders::begin() const +{ +	return mHeaders.begin(); +} + + +HttpHeaders::iterator HttpHeaders::end() +{ +	return mHeaders.end(); +} + + +HttpHeaders::const_iterator HttpHeaders::end() const +{ +	return mHeaders.end(); +} + + +// Standard Reverse Iterators +HttpHeaders::reverse_iterator HttpHeaders::rbegin() +{ +	return mHeaders.rbegin(); +} + + +HttpHeaders::const_reverse_iterator HttpHeaders::rbegin() const +{ +	return mHeaders.rbegin(); +} + + +HttpHeaders::reverse_iterator HttpHeaders::rend() +{ +	return mHeaders.rend(); +} + + +HttpHeaders::const_reverse_iterator HttpHeaders::rend() const +{ +	return mHeaders.rend(); +} + + +// Return the raw container to the caller. +// +// To be used FOR UNIT TESTS ONLY. +// +HttpHeaders::container_t & HttpHeaders::getContainerTESTONLY() +{ +	return mHeaders; +} + +  }   // end namespace LLCore diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index 3449daa3a1..f70cd898f3 100755 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -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 @@ -43,13 +43,26 @@ namespace LLCore  /// caller has asked that headers be returned (not the default  /// option).  /// -/// @note -/// This is a minimally-functional placeholder at the moment -/// to fill out the class hierarchy.  The final class will be -/// something else, probably more pair-oriented.  It's also -/// an area where shared values are desirable so refcounting is -/// already specced and a copy-on-write scheme imagined. -/// Expect changes here. +/// Class is mostly a thin wrapper around a vector of pairs +/// of strings.  Methods provided are few and intended to +/// reflect actual use patterns.  These include: +/// - Clearing the list +/// - Appending a name/value pair to the vector +/// - Processing a raw byte string into a normalized name/value +///   pair and appending the result. +/// - Simple case-sensitive find-last-by-name search +/// - Forward and reverse iterators over all pairs +/// +/// Container is ordered and multi-valued.  Headers are +/// written in the order in which they are appended and +/// are stored in the order in which they're received from +/// the wire.  The same header may appear two or more times +/// in any container.  Searches using the simple find() +/// interface will find only the last occurrence (somewhat +/// simulates the use of std::map).  Fuller searches require +/// the use of an iterator.  Headers received from the wire +/// are only returned from the last request when redirections +/// are involved.  ///  /// Threading:  Not intrinsically thread-safe.  It *is* expected  /// that callers will build these objects and then share them @@ -64,6 +77,16 @@ namespace LLCore  class HttpHeaders : public LLCoreInt::RefCounted  {  public: +	typedef std::pair<std::string, std::string> header_t; +	typedef std::vector<header_t> container_t; +	typedef container_t::iterator iterator; +	typedef container_t::const_iterator const_iterator; +	typedef container_t::reverse_iterator reverse_iterator; +	typedef container_t::const_reverse_iterator const_reverse_iterator; +	typedef container_t::value_type value_type; +	typedef container_t::size_type size_type; + +public:  	/// @post In addition to the instance, caller has a refcount  	/// to the instance.  A call to @see release() will destroy  	/// the instance. @@ -76,7 +99,78 @@ protected:  	void operator=(const HttpHeaders &);		// Not defined  public: -	typedef std::vector<std::string> container_t; +	// Empty the list of headers. +	void clear(); + +	// Append a name/value pair supplied as either std::strings +	// or NUL-terminated char * to the header list.  No normalization +	// is performed on the strings.  No conformance test is +	// performed (names may contain spaces, colons, etc.). +	// +	void append(const std::string & name, const std::string & value); +	void append(const char * name, const char * value); + +	// Extract a name/value pair from a raw byte array using +	// the first colon character as a separator.  Input string +	// does not need to be NUL-terminated.  Resulting name/value +	// pair is appended to the header list. +	// +	// Normalization is performed on the name/value pair as +	// follows: +	// - name is lower-cased according to mostly ASCII rules +	// - name is left- and right-trimmed of spaces and tabs +	// - value is left-trimmed of spaces and tabs +	// - either or both of name and value may be zero-length +	// +	// By convention, headers read from the wire will be normalized +	// in this fashion prior to delivery to any HttpHandler code. +	// Headers to be written to the wire are left as appended to +	// the list. +	void appendNormal(const char * header, size_t size); + +	// Perform a simple, case-sensitive search of the header list +	// returning a pointer to the value of the last matching header +	// in the header list.  If none is found, a NULL pointer is returned. +	// +	// Any pointer returned references objects in the container itself +	// and will have the same lifetime as this class.  If you want +	// the value beyond the lifetime of this instance, make a copy. +	// +	// @arg		name	C-style string giving the name of a header +	//					to search.  The comparison is case-sensitive +	//					though list entries may have been normalized +	//					to lower-case. +	// +	// @return			NULL if the header wasn't found otherwise +	//					a pointer to a std::string in the container. +	//					Pointer is valid only for the lifetime of +	//					the container or until container is modifed. +	// +	const std::string * find(const char * name) const; + +	// Count of headers currently in the list. +	size_type size() const +		{ +			return mHeaders.size(); +		} + +	// Standard std::vector-based forward iterators. +	iterator begin(); +	const_iterator begin() const; +	iterator end(); +	const_iterator end() const; + +	// Standard std::vector-based reverse iterators. +	reverse_iterator rbegin(); +	const_reverse_iterator rbegin() const; +	reverse_iterator rend(); +	const_reverse_iterator rend() const; + +public: +	// For unit tests only - not a public API +	container_t &		getContainerTESTONLY(); +	 +protected:  	container_t			mHeaders;  }; // end class HttpHeaders 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 e5488cf941..27d65f171e 100755 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.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 @@ -60,6 +60,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 @@ -109,11 +111,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; @@ -129,11 +137,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"; @@ -159,8 +170,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; @@ -1335,7 +1346,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, @@ -1702,18 +1715,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/", @@ -1735,23 +1784,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/", @@ -1892,20 +1978,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/", @@ -2052,20 +2181,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/", @@ -2206,27 +2379,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/", @@ -2359,10 +2578,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>"); @@ -2371,23 +2590,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/", @@ -2529,9 +2801,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>"); @@ -2540,22 +2812,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/", | 
