diff --git a/autobuild.xml b/autobuild.xml
index 148ca1710b50ba9c45e192b62ee35d6c3460a89f..331e3d8cec7270bc2b7cff2cf0bd5b1e8a65b17e 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -498,9 +498,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-	      <string>10352aab979c333a52dbad21b6e6fba9</string>
+              <string>10352aab979c333a52dbad21b6e6fba9</string>
               <key>url</key>
-	      <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274403/arch/Darwin/installer/fmodex-4.44-darwin-20130419.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274403/arch/Darwin/installer/fmodex-4.44-darwin-20130419.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -510,7 +510,7 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-          <string>79e45527aa9fb90b813599dff5ce01a7</string>
+              <string>79e45527aa9fb90b813599dff5ce01a7</string>
               <key>url</key>
               <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274378/arch/Linux/installer/fmodex-4.44-linux-20130419.tar.bz2</string>
             </map>
@@ -522,9 +522,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-	      <string>0980cdf98a322a780ba739e324d0b955</string>
+              <string>0980cdf98a322a780ba739e324d0b955</string>
               <key>url</key>
-	      <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274401/arch/CYGWIN/installer/fmodex-4.44-windows-20130419.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274401/arch/CYGWIN/installer/fmodex-4.44-windows-20130419.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -747,7 +747,6 @@
           </map>
         </map>
       </map>
-
       <key>google_breakpad</key>
       <map>
         <key>license</key>
@@ -762,10 +761,10 @@
           <map>
             <key>archive</key>
             <map>
-           <key>hash</key>
-	   <string>aff5566e04003de0383941981198e04e</string>
-          <key>url</key>
-          <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
+              <key>hash</key>
+              <string>aff5566e04003de0383941981198e04e</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -774,10 +773,10 @@
           <map>
             <key>archive</key>
             <map>
-             <key>hash</key>
-	         <string>52257e5eb166a0b69c9c0c38f6e1920e</string>
-             <key>url</key>
-	         <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
+              <key>hash</key>
+              <string>52257e5eb166a0b69c9c0c38f6e1920e</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -787,9 +786,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-	      <string>d812a6dfcabe6528198a3191068dac09</string>
+              <string>d812a6dfcabe6528198a3191068dac09</string>
               <key>url</key>
-             <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/CYGWIN/installer/google_breakpad-0.0.0-rev1099-windows-20130329.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/CYGWIN/installer/google_breakpad-0.0.0-rev1099-windows-20130329.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -837,7 +836,7 @@
               <key>hash</key>
               <string>98994d5b0b4b3d43be22aa6a5c36e6fa</string>
               <key>url</key>
-		<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock-graham/rev/272961/arch/CYGWIN/installer/gmock-1.6.0-windows-20130327.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock-graham/rev/272961/arch/CYGWIN/installer/gmock-1.6.0-windows-20130327.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -1291,9 +1290,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>5bc44db15eb3cca021382e40e04a9a38</string>
+              <string>55e009de4f87023a57e0a04a19f8a25b</string>
               <key>url</key>
-              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/271972/arch/Linux/installer/llappearanceutility_source-0.1-linux-20130315.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/277110/arch/Linux/installer/llappearanceutility_source-0.1-linux-20130606.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
diff --git a/build.sh b/build.sh
index a78f368e475aa9a52c1aa42ade842ff093fa29c4..9694131a6744aef20961fb141e831734f31d46cc 100755
--- a/build.sh
+++ b/build.sh
@@ -275,11 +275,15 @@ then
     if $build_viewer_deb && [ "$last_built_variant" == "Release" ]
     then
       begin_section "Build Viewer Debian Package"
-      local have_private_repo=false
+      have_private_repo=false
+      
+      # Get the current version. 
+      current_version=`dpkg-parsechangelog | grep ^Version | awk '{ print $2 }'`
+      
       # mangle the changelog
       dch --force-bad-version \
           --distribution unstable \
-          --newversion "${VIEWER_VERSION}" \
+          --newversion "${current_version}"+"${revision}" \
           "Automated build #$build_id, repository $branch revision $revision." \
           >> "$build_log" 2>&1
 
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index 0094e313c7916d72c6d844ad62f852f842debaf0..7fc6957254db81d766c2345596b0eae8391d345a 100755
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -38,6 +38,11 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
         message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'") 
     endif ( EXISTS ${VIEWER_VERSION_BASE_FILE} )
 
+    if ("${VIEWER_VERSION_REVISION}" STREQUAL "")
+      message("Ultimate fallback, revision was blank or not set: will use 0")
+      set(VIEWER_VERSION_REVISION 0)
+    endif ("${VIEWER_VERSION_REVISION}" STREQUAL "")
+
     set(VIEWER_CHANNEL_VERSION_DEFINES
         "LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\""
         "LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}"
diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt
index e003ed77883684fd8f54604332e49d048c263048..48e8b566a61a06e32ed1ea5c9e88c4e9f356ea12 100755
--- a/indra/edit-me-to-trigger-new-build.txt
+++ b/indra/edit-me-to-trigger-new-build.txt
@@ -1,5 +1 @@
-Wed Nov  7 00:25:19 UTC 2012
-
-
-
-
+Mon Apr 15 14:35:39 EDT 2013
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 3bb759d45879890b3e81b78be9b9db48971d7a0b..e3497c107df6a5dac0f2b8698f91f3073e4fcc40 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -488,25 +488,6 @@ void LLAvatarAppearance::computeBodySize()
 	mAvatarOffset.mV[VX] = 0.0f;
 	mAvatarOffset.mV[VY] = 0.0f;
 
-	// Certain configurations of avatars can force the overall height (with offset) to go negative.
-	// Enforce a constraint to make sure we don't go below 0.1 meters.
-	// Camera positioning and other things start to break down when your avatar is "walking" while being fully underground
-	if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f) 
-	{
-		mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail.
-
-		llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f);
-
-		if (mWearableData && isSelf()) 
-		{
-			LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0);
-			if (shape) 
-			{
-				shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false);
-			}
-		}
-	}
-
 	if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
 	{
 		mBodySize = new_body_size;
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index bce25402581032514c6cce838ddc26e69c0d951a..0a6a236d34996741fd5dc343e2899a33f9c3ee8a 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -137,7 +137,7 @@ class LLAvatarAppearance : public LLCharacter
 	typedef std::map<std::string, LLJoint*> joint_map_t;
 	joint_map_t			mJointMap;
 	
-	void				computeBodySize();
+	virtual void		computeBodySize();
 
 
 protected:
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 3a4a8facc217ef7b041d83a614618009bd0901bb..72a997cd898c96386b0b11da3ec9c42448839846 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -177,7 +177,6 @@ set(llcommon_HEADER_FILES
     llhandle.h
     llhash.h
     llheartbeat.h
-    llhttpstatuscodes.h
     llindexedqueue.h
     llinitparam.h
     llinstancetracker.h
diff --git a/indra/llcommon/llhttpstatuscodes.h b/indra/llcommon/llhttpstatuscodes.h
deleted file mode 100755
index 0173461dad3966ffc81b94225b7ef5d254f1617b..0000000000000000000000000000000000000000
--- a/indra/llcommon/llhttpstatuscodes.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/** 
- * @file llhttpstatuscodes.h
- * @brief Constants for HTTP status codes
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_HTTP_STATUS_CODES_H
-#define LL_HTTP_STATUS_CODES_H
-
-#include "stdtypes.h"
-
-// Standard errors from HTTP spec:
-// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
-const S32 HTTP_CONTINUE = 100;
-const S32 HTTP_SWITCHING_PROTOCOLS = 101;
-
-// Success
-const S32 HTTP_OK = 200;
-const S32 HTTP_CREATED = 201;
-const S32 HTTP_ACCEPTED = 202;
-const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
-const S32 HTTP_NO_CONTENT = 204;
-const S32 HTTP_RESET_CONTENT = 205;
-const S32 HTTP_PARTIAL_CONTENT = 206;
-
-// Redirection
-const S32 HTTP_MULTIPLE_CHOICES = 300;
-const S32 HTTP_MOVED_PERMANENTLY = 301;
-const S32 HTTP_FOUND = 302;
-const S32 HTTP_SEE_OTHER = 303;
-const S32 HTTP_NOT_MODIFIED = 304;
-const S32 HTTP_USE_PROXY = 305;
-const S32 HTTP_TEMPORARY_REDIRECT = 307;
-
-// Client Error
-const S32 HTTP_BAD_REQUEST = 400;
-const S32 HTTP_UNAUTHORIZED = 401;
-const S32 HTTP_PAYMENT_REQUIRED = 402;
-const S32 HTTP_FORBIDDEN = 403;
-const S32 HTTP_NOT_FOUND = 404;
-const S32 HTTP_METHOD_NOT_ALLOWED = 405;
-const S32 HTTP_NOT_ACCEPTABLE = 406;
-const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
-const S32 HTTP_REQUEST_TIME_OUT = 408;
-const S32 HTTP_CONFLICT = 409;
-const S32 HTTP_GONE = 410;
-const S32 HTTP_LENGTH_REQUIRED = 411;
-const S32 HTTP_PRECONDITION_FAILED = 412;
-const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
-const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
-const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
-const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
-const S32 HTTP_EXPECTATION_FAILED = 417;
-
-// Server Error
-const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
-const S32 HTTP_NOT_IMPLEMENTED = 501;
-const S32 HTTP_BAD_GATEWAY = 502;
-const S32 HTTP_SERVICE_UNAVAILABLE = 503;
-const S32 HTTP_GATEWAY_TIME_OUT = 504;
-const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
-
-// We combine internal process errors with status codes
-// These status codes should not be sent over the wire
-//   and indicate something went wrong internally.
-// If you get these they are not normal.
-const S32 HTTP_INTERNAL_ERROR = 499;
-
-#endif
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 8276ec836a77399ed164ff02d4ec65a3286aafb5..9e4b92227ed807666e26f063ddb4e1a3bb9ba558 100755
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -126,7 +126,9 @@ class LLSD::Impl
 	virtual UUID	asUUID() const				{ return LLUUID(); }
 	virtual Date	asDate() const				{ return LLDate(); }
 	virtual URI		asURI() const				{ return LLURI(); }
-	virtual Binary	asBinary() const			{ return std::vector<U8>(); }
+	virtual const Binary&	asBinary() const	{ static const std::vector<U8> empty; return empty; }
+
+	virtual const String& asStringRef() const { static const std::string empty; return empty; } 
 	
 	virtual bool has(const String&) const		{ return false; }
 	virtual LLSD get(const String&) const		{ return LLSD(); }
@@ -270,6 +272,7 @@ namespace
 		virtual LLSD::Date		asDate() const	{ return LLDate(mValue); }
 		virtual LLSD::URI		asURI() const	{ return LLURI(mValue); }
 		virtual int				size() const	{ return mValue.size(); }
+		virtual const LLSD::String&	asStringRef() const { return mValue; }
 	};
 	
 	LLSD::Integer	ImplString::asInteger() const
@@ -348,7 +351,7 @@ namespace
 	public:
 		ImplBinary(const LLSD::Binary& v) : Base(v) { }
 				
-		virtual LLSD::Binary	asBinary() const{ return mValue; }
+		virtual const LLSD::Binary&	asBinary() const{ return mValue; }
 	};
 
 
@@ -838,7 +841,9 @@ LLSD::String	LLSD::asString() const	{ return safe(impl).asString(); }
 LLSD::UUID		LLSD::asUUID() const	{ return safe(impl).asUUID(); }
 LLSD::Date		LLSD::asDate() const	{ return safe(impl).asDate(); }
 LLSD::URI		LLSD::asURI() const		{ return safe(impl).asURI(); }
-LLSD::Binary	LLSD::asBinary() const	{ return safe(impl).asBinary(); }
+const LLSD::Binary&	LLSD::asBinary() const	{ return safe(impl).asBinary(); }
+
+const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
 
 // const char * helpers
 LLSD::LLSD(const char* v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index 5eb69059ac6e5f41e4f76504f6d081419652766f..b9f490718c5f4bcdd5472d63009718bc77b7388c 100755
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -249,7 +249,10 @@ class LL_COMMON_API LLSD
 		UUID	asUUID() const;
 		Date	asDate() const;
 		URI		asURI() const;
-		Binary	asBinary() const;
+		const Binary&	asBinary() const;
+
+		// asStringRef on any non-string type will return a ref to an empty string.
+		const String&	asStringRef() const;
 
 		operator Boolean() const	{ return asBoolean(); }
 		operator Integer() const	{ return asInteger(); }
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index ad4fce6f359b8dbb6277402ed615394c98de118a..774d827762757b86b32fcec5891584b28638a872 100755
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -873,7 +873,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const
 {
 /**
  * Undefined: '!'<br>
- * Boolean: 't' for true 'f' for false<br>
+ * Boolean: '1' for true '0' for false<br>
  * Integer: 'i' + 4 bytes network byte order<br>
  * Real: 'r' + 8 bytes IEEE double<br>
  * UUID: 'u' + 16 byte unsigned integer<br>
@@ -1260,13 +1260,38 @@ std::string LLSDNotationFormatter::escapeString(const std::string& in)
 
 // virtual
 S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
+{
+	S32 rv = format_impl(data, ostr, options, 0);
+	return rv;
+}
+
+S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
 {
 	S32 format_count = 1;
+	std::string pre;
+	std::string post;
+
+	if (options & LLSDFormatter::OPTIONS_PRETTY)
+	{
+		for (U32 i = 0; i < level; i++)
+		{
+			pre += "    ";
+		}
+		post = "\n";
+	}
+
 	switch(data.type())
 	{
 	case LLSD::TypeMap:
 	{
+		if (0 != level) ostr << post << pre;
 		ostr << "{";
+		std::string inner_pre;
+		if (options & LLSDFormatter::OPTIONS_PRETTY)
+		{
+			inner_pre = pre + "    ";
+		}
+
 		bool need_comma = false;
 		LLSD::map_const_iterator iter = data.beginMap();
 		LLSD::map_const_iterator end = data.endMap();
@@ -1274,18 +1299,18 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
 		{
 			if(need_comma) ostr << ",";
 			need_comma = true;
-			ostr << '\'';
+			ostr << post << inner_pre << '\'';
 			serialize_string((*iter).first, ostr);
 			ostr << "':";
-			format_count += format((*iter).second, ostr);
+			format_count += format_impl((*iter).second, ostr, options, level + 2);
 		}
-		ostr << "}";
+		ostr << post << pre << "}";
 		break;
 	}
 
 	case LLSD::TypeArray:
 	{
-		ostr << "[";
+		ostr << post << pre << "[";
 		bool need_comma = false;
 		LLSD::array_const_iterator iter = data.beginArray();
 		LLSD::array_const_iterator end = data.endArray();
@@ -1293,7 +1318,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
 		{
 			if(need_comma) ostr << ",";
 			need_comma = true;
-			format_count += format(*iter, ostr);
+			format_count += format_impl(*iter, ostr, options, level + 1);
 		}
 		ostr << "]";
 		break;
@@ -1343,7 +1368,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
 
 	case LLSD::TypeString:
 		ostr << '\'';
-		serialize_string(data.asString(), ostr);
+		serialize_string(data.asStringRef(), ostr);
 		ostr << '\'';
 		break;
 
@@ -1360,9 +1385,26 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti
 	case LLSD::TypeBinary:
 	{
 		// *FIX: memory inefficient.
-		std::vector<U8> buffer = data.asBinary();
+		const std::vector<U8>& buffer = data.asBinary();
 		ostr << "b(" << buffer.size() << ")\"";
-		if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size());
+		if(buffer.size())
+		{
+			if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY)
+			{
+				std::ios_base::fmtflags old_flags = ostr.flags();
+				ostr.setf( std::ios::hex, std::ios::basefield );
+				ostr << "0x";
+				for (int i = 0; i < buffer.size(); i++)
+				{
+					ostr << (int) buffer[i];
+				}
+				ostr.flags(old_flags);
+			}
+			else
+			{
+				ostr.write((const char*)&buffer[0], buffer.size());
+			}
+		}
 		ostr << "\"";
 		break;
 	}
@@ -1460,7 +1502,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
 
 	case LLSD::TypeString:
 		ostr.put('s');
-		formatString(data.asString(), ostr);
+		formatString(data.asStringRef(), ostr);
 		break;
 
 	case LLSD::TypeDate:
@@ -1478,9 +1520,8 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
 
 	case LLSD::TypeBinary:
 	{
-		// *FIX: memory inefficient.
 		ostr.put('b');
-		std::vector<U8> buffer = data.asBinary();
+		const std::vector<U8>& buffer = data.asBinary();
 		U32 size_nbo = htonl(buffer.size());
 		ostr.write((const char*)(&size_nbo), sizeof(U32));
 		if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size());
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index e7a5507385c07bd0c05b42d2477336e04d6d3c1d..23a0c8cfb1e332ea0346517c1cec74d2e33514b9 100755
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -416,7 +416,8 @@ class LL_COMMON_API LLSDFormatter : public LLRefCount
 	typedef enum e_formatter_options_type
 	{
 		OPTIONS_NONE = 0,
-		OPTIONS_PRETTY = 1
+		OPTIONS_PRETTY = 1,
+		OPTIONS_PRETTY_BINARY = 2
 	} EFormatterOptions;
 
 	/** 
@@ -507,6 +508,17 @@ class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter
 	 * @return Returns The number of LLSD objects fomatted out
 	 */
 	virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const;
+
+protected:
+
+	/** 
+	 * @brief Implementation to format the data. This is called recursively.
+	 *
+	 * @param data The data to write.
+	 * @param ostr The destination stream for the data.
+	 * @return Returns The number of LLSD objects fomatted out
+	 */
+	S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const;
 };
 
 
@@ -634,7 +646,7 @@ class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter
  *  </code>
  *
  * *NOTE - formerly this class inherited from its template parameter Formatter,
- * but all insnatiations passed in LLRefCount subclasses.  This conflicted with
+ * but all instantiations passed in LLRefCount subclasses.  This conflicted with
  * the auto allocation intended for this class template (demonstrated in the
  * example above).  -brad
  */
@@ -720,6 +732,18 @@ class LL_COMMON_API LLSDSerialize
 		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
 		return f->format(sd, str, LLSDFormatter::OPTIONS_NONE);
 	}
+	static S32 toPrettyNotation(const LLSD& sd, std::ostream& str)
+	{
+		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
+		return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY);
+	}
+	static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str)
+	{
+		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;
+		return f->format(sd, str, 
+				LLSDFormatter::OPTIONS_PRETTY | 
+				LLSDFormatter::OPTIONS_PRETTY_BINARY);
+	}
 	static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes)
 	{
 		LLPointer<LLSDNotationParser> p = new LLSDNotationParser;
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index cef743a7beab012a31a2b42233da8f33db9588b6..3ef7a7e4c12b5af547640bb45472e822f8600dce 100755
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -168,8 +168,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
 		break;
 
 	case LLSD::TypeString:
-		if(data.asString().empty()) ostr << pre << "<string />" << post;
-		else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post;
+		if(data.asStringRef().empty()) ostr << pre << "<string />" << post;
+		else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post;
 		break;
 
 	case LLSD::TypeDate:
@@ -182,7 +182,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
 
 	case LLSD::TypeBinary:
 	{
-		LLSD::Binary buffer = data.asBinary();
+		const LLSD::Binary& buffer = data.asBinary();
 		if(buffer.empty())
 		{
 			ostr << pre << "<binary />" << post;
@@ -375,13 +375,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
 		{
 			break;
 		}
+		count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
+		if (!count)
 		{
-		
-			count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
-			if (!count)
-			{
-				break;
-			}
+			break;
 		}
 		status = XML_ParseBuffer(mParser, count, false);
 
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 803417d368b899d81a9cc8c8aca09e925103a097..562fd26658e6e30346ef026e8c916222a8c8acd4 100755
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -182,7 +182,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd)
 
 char* ll_pretty_print_sd(const LLSD& sd)
 {
-	const U32 bufferSize = 10 * 1024;
+	const U32 bufferSize = 100 * 1024;
 	static char buffer[bufferSize];
 	std::ostringstream stream;
 	//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp
index 6fe0bfc7d1a1dcdab3eebfabdd80f83a6a522853..d49f615ac42f007c073b8d6a56941e5a839e555c 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
@@ -31,7 +31,7 @@
 #include "_httpoprequest.h"
 #include "_httppolicy.h"
 
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 
 
 namespace LLCore
@@ -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 51a8eaf9989373575c35d6d8f09b882ffc052a19..95e0f72c0b09810dc1c2ac3b08c9e3b7ff1d9030 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.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
@@ -44,7 +44,7 @@
 #include "_httplibcurl.h"
 #include "_httpinternal.h"
 
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 #include "llproxy.h"
 
 namespace
@@ -479,6 +479,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
 			curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
 			curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);
 			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
+			// *TODO: Should this be 'Keep-Alive' ?
 			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
 			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
 		}
@@ -609,7 +610,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
@@ -620,8 +622,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
@@ -636,18 +639,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 40ad4f047dfcc0141cadaa25eb638bd6f278f8af..909dc5b0cb0f63b6de8792357af881e04151f136 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 2832696271440cb3681a4a5186670a31862d433d..23ebea361c1246b7589918cab569e2527be70d5e 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 3449daa3a1311c859720cc1624c885420822a7c2..f70cd898f3949eb641991bd76fdd3650c5abe885 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
@@ -63,6 +76,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
@@ -76,7 +99,78 @@ class HttpHeaders : public LLCoreInt::RefCounted
 	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 ce0d19b05842bc49c55b98fd1eaa807a7a6aa681..668c36dc66bc142947a99546dee4ee6e152be5be 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 e5488cf941e7a8b7c0892965aa6664d596a44edf..27d65f171ecb483541933c18657b02bbdac05d7b 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/",
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index fb2d43e3b0d6c25af71214e8cf3f1bbe255198fd..b86e73c69070495c0bdee360b76d22e4933ddef3 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -50,18 +50,21 @@ BOOL gSent = false;
 
 class LLCrashLoggerResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLCrashLoggerResponder);
 public:
 	LLCrashLoggerResponder() 
 	{
 	}
 
-	virtual void error(U32 status, const std::string& reason)
+protected:
+	virtual void httpFailure()
 	{
+		llwarns << dumpResponse() << llendl;
 		gBreak = true;
 	}
 
-	virtual void result(const LLSD& content)
-	{	
+	virtual void httpSuccess()
+	{
 		gBreak = true;
 		gSent = true;
 	}
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 41d58c6deb5b2c476012deb32bccefe661a13b3e..6336d02f227a05052b49336ee15be85c902b934c 100755
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -50,6 +50,7 @@ static const std::string INV_DESC_LABEL("desc");
 static const std::string INV_PERMISSIONS_LABEL("permissions");
 static const std::string INV_SHADOW_ID_LABEL("shadow_id");
 static const std::string INV_ASSET_ID_LABEL("asset_id");
+static const std::string INV_LINKED_ID_LABEL("linked_id");
 static const std::string INV_SALE_INFO_LABEL("sale_info");
 static const std::string INV_FLAGS_LABEL("flags");
 static const std::string INV_CREATION_DATE_LABEL("created_at");
@@ -249,13 +250,6 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co
 	return TRUE;
 }
 
-
-void LLInventoryObject::removeFromServer()
-{
-	// don't do nothin'
-	llwarns << "LLInventoryObject::removeFromServer() called.  Doesn't do anything." << llendl;
-}
-
 void LLInventoryObject::updateParentOnServer(BOOL) const
 {
 	// don't do nothin'
@@ -268,7 +262,7 @@ void LLInventoryObject::updateServer(BOOL) const
 	llwarns << "LLInventoryObject::updateServer() called.  Doesn't do anything." << llendl;
 }
 
-inline
+// static
 void LLInventoryObject::correctInventoryName(std::string& name)
 {
 	LLStringUtil::replaceNonstandardASCII(name, ' ');
@@ -423,12 +417,17 @@ U32 LLInventoryItem::getCRC32() const
 	return crc;
 }
 
+// static
+void LLInventoryItem::correctInventoryDescription(std::string& desc)
+{
+	LLStringUtil::replaceNonstandardASCII(desc, ' ');
+	LLStringUtil::replaceChar(desc, '|', ' ');
+}
 
 void LLInventoryItem::setDescription(const std::string& d)
 {
 	std::string new_desc(d);
-	LLStringUtil::replaceNonstandardASCII(new_desc, ' ');
-	LLStringUtil::replaceChar(new_desc, '|', ' ');
+	LLInventoryItem::correctInventoryDescription(new_desc);
 	if( new_desc != mDescription )
 	{
 		mDescription = new_desc;
@@ -1050,11 +1049,16 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
 
 LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
 
-bool LLInventoryItem::fromLLSD(const LLSD& sd)
+bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
 {
 	LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE);
-	mInventoryType = LLInventoryType::IT_NONE;
-	mAssetUUID.setNull();
+	if (is_new)
+	{
+		// If we're adding LLSD to an existing object, need avoid
+		// clobbering these fields.
+		mInventoryType = LLInventoryType::IT_NONE;
+		mAssetUUID.setNull();
+	}
 	std::string w;
 
 	w = INV_ITEM_ID_LABEL;
@@ -1111,6 +1115,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
 	{
 		mAssetUUID = sd[w];
 	}
+	w = INV_LINKED_ID_LABEL;
+	if (sd.has(w))
+	{
+		mAssetUUID = sd[w];
+	}
 	w = INV_ASSET_TYPE_LABEL;
 	if (sd.has(w))
 	{
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 99716ed7be6d13290756c80b191385eed8c25d73..b718f0f9b7aaa65aa385757f9c1954a7a0e7e9dc 100755
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -86,22 +86,19 @@ class LLInventoryObject : public LLRefCount
 	void setType(LLAssetType::EType type);
 	virtual void setCreationDate(time_t creation_date_utc); // only stored for items
 
-private:
 	// in place correction for inventory name string
-	void correctInventoryName(std::string& name);
+	static void correctInventoryName(std::string& name);
 
 	//--------------------------------------------------------------------
 	// File Support
 	//   Implemented here so that a minimal information set can be transmitted
 	//   between simulator and viewer.
 	//--------------------------------------------------------------------
-public:
 	// virtual BOOL importFile(LLFILE* fp);
 	virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const;
 	virtual BOOL importLegacyStream(std::istream& input_stream);
 	virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const;
 
-	virtual void removeFromServer();
 	virtual void updateParentOnServer(BOOL) const;
 	virtual void updateServer(BOOL) const;
 
@@ -174,6 +171,7 @@ class LLInventoryItem : public LLInventoryObject
 	//--------------------------------------------------------------------
 public:
 	void setAssetUUID(const LLUUID& asset_id);
+	static void correctInventoryDescription(std::string& name);
 	void setDescription(const std::string& new_desc);
 	void setSaleInfo(const LLSaleInfo& sale_info);
 	void setPermissions(const LLPermissions& perm);
@@ -212,7 +210,7 @@ class LLInventoryItem : public LLInventoryObject
 	void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
 	LLSD asLLSD() const;
 	void asLLSD( LLSD& sd ) const;
-	bool fromLLSD(const LLSD& sd);
+	bool fromLLSD(const LLSD& sd, bool is_new = true);
 
 	//--------------------------------------------------------------------
 	// Member Variables
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 1a90c32fe4fd0ee38433164a7e7a0d59ddfb885a..6fa2669be6f6d83396c91ae39d4ef7b142a8ffb4 100755
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -43,6 +43,7 @@ set(llmessage_SOURCE_FILES
     llhttpassetstorage.cpp
     llhttpclient.cpp
     llhttpclientadapter.cpp
+    llhttpconstants.cpp
     llhttpnode.cpp
     llhttpsender.cpp
     llinstantmessage.cpp
@@ -58,7 +59,6 @@ set(llmessage_SOURCE_FILES
     llmessagetemplate.cpp
     llmessagetemplateparser.cpp
     llmessagethrottle.cpp
-    llmime.cpp
     llnamevalue.cpp
     llnullcipher.cpp
     llpacketack.cpp
@@ -67,7 +67,6 @@ set(llmessage_SOURCE_FILES
     llpartdata.cpp
     llproxy.cpp
     llpumpio.cpp
-    llregionpresenceverifier.cpp
     llsdappservices.cpp
     llsdhttpserver.cpp
     llsdmessage.cpp
@@ -135,6 +134,7 @@ set(llmessage_HEADER_FILES
     llhttpclient.h
     llhttpclientinterface.h
     llhttpclientadapter.h
+    llhttpconstants.h
     llhttpnode.h
     llhttpnodeadapter.h
     llhttpsender.h
@@ -153,7 +153,6 @@ set(llmessage_HEADER_FILES
     llmessagetemplate.h
     llmessagetemplateparser.h
     llmessagethrottle.h
-    llmime.h
     llmsgvariabletype.h
     llnamevalue.h
     llnullcipher.h
@@ -166,7 +165,6 @@ set(llmessage_HEADER_FILES
     llqueryflags.h
     llregionflags.h
     llregionhandle.h
-    llregionpresenceverifier.h
     llsdappservices.h
     llsdhttpserver.h
     llsdmessage.h
@@ -230,17 +228,15 @@ target_link_libraries(
 # tests
 if (LL_TESTS)
   SET(llmessage_TEST_SOURCE_FILES
-    # llhttpclientadapter.cpp
-    llmime.cpp
     llnamevalue.cpp
     lltrustedmessageservice.cpp
     lltemplatemessagedispatcher.cpp
-      llregionpresenceverifier.cpp
     )
   LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}")
 
   #    set(TEST_DEBUG on)
   set(test_libs
+    ${CURL_LIBRARIES}
     ${LLMESSAGE_LIBRARIES}
     ${WINDOWS_LIBRARIES}
     ${LLVFS_LIBRARIES}
@@ -267,6 +263,7 @@ if (LL_TESTS)
 
   LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}")
+  LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")
   LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")
 endif (LL_TESTS)
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 9a68093427d241b8c8000edfdc18920598333b18..e0b71acbd51be7d0e957298f12e8877240eb83fa 100755
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -121,7 +121,7 @@ namespace LLAvatarNameCache
 	// Erase expired names from cache
 	void eraseUnrefreshed();
 
-	bool expirationFromCacheControl(LLSD headers, F64 *expires);
+	bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
 }
 
 /* Sample response:
@@ -165,33 +165,31 @@ namespace LLAvatarNameCache
 
 class LLAvatarNameResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLAvatarNameResponder);
 private:
 	// need to store agent ids that are part of this request in case of
 	// an error, so we can flag them as unavailable
 	std::vector<LLUUID> mAgentIDs;
 
-	// Need the headers to look up Expires: and Retry-After:
-	LLSD mHeaders;
-	
 public:
 	LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
-	:	mAgentIDs(agent_ids),
-		mHeaders()
+	:	mAgentIDs(agent_ids)
 	{ }
 	
-	/*virtual*/ void completedHeader(U32 status, const std::string& reason, 
-		const LLSD& headers)
-	{
-		mHeaders = headers;
-	}
-
-	/*virtual*/ void result(const LLSD& content)
+protected:
+	/*virtual*/ void httpSuccess()
 	{
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		// Pull expiration out of headers if available
-		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders);
+		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders());
 		F64 now = LLFrameTimer::getTotalSeconds();
 
-		LLSD agents = content["agents"];
+		const LLSD& agents = content["agents"];
 		LLSD::array_const_iterator it = agents.beginArray();
 		for ( ; it != agents.endArray(); ++it)
 		{
@@ -212,7 +210,7 @@ class LLAvatarNameResponder : public LLHTTPClient::Responder
 		}
 
 		// Same logic as error response case
-		LLSD unresolved_agents = content["bad_ids"];
+		const LLSD& unresolved_agents = content["bad_ids"];
 		S32  num_unresolved = unresolved_agents.size();
 		if (num_unresolved > 0)
 		{
@@ -236,14 +234,13 @@ class LLAvatarNameResponder : public LLHTTPClient::Responder
                                  << LL_ENDL;
     }
 
-	/*virtual*/ void error(U32 status, const std::string& reason)
+	/*virtual*/ void httpFailure()
 	{
 		// If there's an error, it might be caused by PeopleApi,
 		// or when loading textures on startup and using a very slow 
 		// network, this query may time out.
 		// What we should do depends on whether or not we have a cached name
-		LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason
-								<< LL_ENDL;
+		LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL;
 
 		// Add dummy records for any agent IDs in this request that we do not have cached already
 		std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
@@ -691,7 +688,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
 	sCache[agent_id] = av_name;
 }
 
-F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
+F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)
 {
 	F64 expires = 0.0;
 	if (expirationFromCacheControl(headers, &expires))
@@ -707,17 +704,21 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
 	}
 }
 
-bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
+bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *expires)
 {
 	bool fromCacheControl = false;
 	F64 now = LLFrameTimer::getTotalSeconds();
 
 	// Allow the header to override the default
-	LLSD cache_control_header = headers["cache-control"];
-	if (cache_control_header.isDefined())
+	std::string cache_control;
+	if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL))
+	{
+		cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString();
+	}
+
+	if (!cache_control.empty())
 	{
 		S32 max_age = 0;
-		std::string cache_control = cache_control_header.asString();
 		if (max_age_from_cache_control(cache_control, &max_age))
 		{
 			*expires = now + (F64)max_age;
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 2a8eb46187b1af5fbd308fbb551f6fe73f73a85f..1f50c489613c36884e2c51a5b377e070c6d8f9fb 100755
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -88,7 +88,7 @@ namespace LLAvatarNameCache
 
 	// Compute name expiration time from HTTP Cache-Control header,
 	// or return default value, in seconds from epoch.
-	F64 nameExpirationFromHeaders(LLSD headers);
+	F64 nameExpirationFromHeaders(const LLSD& headers);
 
 	void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
 }
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 47041a2880710e50e201cca400a3e35f44511b0d..68282626aeec3d634c13dce823e96824a9bf463c 100755
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -49,6 +49,7 @@
 #include "llproxy.h"
 #include "llsdserialize.h"
 #include "llstl.h"
+#include "llstring.h"
 #include "llthread.h"
 #include "lltimer.h"
 
@@ -98,7 +99,7 @@ void check_curl_code(CURLcode code)
 	{
 		// linux appears to throw a curl error once per session for a bad initialization
 		// at a pretty random time (when enabling cookies).
-		llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl;
+		LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;
 	}
 }
 
@@ -108,7 +109,7 @@ void check_curl_multi_code(CURLMcode code)
 	{
 		// linux appears to throw a curl error once per session for a bad initialization
 		// at a pretty random time (when enabling cookies).
-		llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl;
+		LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;
 	}
 }
 
@@ -133,6 +134,7 @@ std::string LLCurl::getVersionString()
 //////////////////////////////////////////////////////////////////////////////
 
 LLCurl::Responder::Responder()
+	: mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)
 {
 }
 
@@ -142,22 +144,30 @@ LLCurl::Responder::~Responder()
 }
 
 // virtual
-void LLCurl::Responder::errorWithContent(
-	U32 status,
-	const std::string& reason,
-	const LLSD&)
+void LLCurl::Responder::httpFailure()
 {
-	error(status, reason);
+	LL_WARNS("curl") << dumpResponse() << LL_ENDL;
 }
 
-// virtual
-void LLCurl::Responder::error(U32 status, const std::string& reason)
+std::string LLCurl::Responder::dumpResponse() const 
 {
-	llinfos << mURL << " [" << status << "]: " << reason << llendl;
+	std::ostringstream s;
+	s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] "
+	  << "[status:" << mStatus << "] "
+	  << "[reason:" << mReason << "] ";
+
+	if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE))
+	{
+		s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] ";
+	}
+
+	s << "[content:" << mContent << "]";
+
+	return s.str();
 }
 
 // virtual
-void LLCurl::Responder::result(const LLSD& content)
+void LLCurl::Responder::httpSuccess()
 {
 }
 
@@ -166,44 +176,109 @@ void LLCurl::Responder::setURL(const std::string& url)
 	mURL = url;
 }
 
+void LLCurl::Responder::successResult(const LLSD& content)
+{
+	setResult(HTTP_OK, "", content);
+	httpSuccess();
+}
+
+void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
+{
+	setResult(status, reason, content);
+	httpFailure();
+}
+
+void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
+{
+	setResult(status, reason, content);
+	httpCompleted();
+}
+
+void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
+{
+	mStatus = status;
+	mReason = reason;
+	mContent = content;
+}
+
+void LLCurl::Responder::setHTTPMethod(EHTTPMethod method)
+{
+	mHTTPMethod = method;
+}
+
+void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value)
+{
+	mResponseHeaders[header] = value;
+}
+
+const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const
+{
+	if (mResponseHeaders.has(header))
+	{
+		return mResponseHeaders[header].asStringRef();
+	}
+	static const std::string empty;
+	return empty;
+}
+
+bool LLCurl::Responder::hasResponseHeader(const std::string& header) const
+{
+	if (mResponseHeaders.has(header)) return true;
+	return false;
+}
+
 // virtual
 void LLCurl::Responder::completedRaw(
-	U32 status,
-	const std::string& reason,
 	const LLChannelDescriptors& channels,
 	const LLIOPipe::buffer_ptr_t& buffer)
 {
-	LLSD content;
 	LLBufferStream istr(channels, buffer.get());
-	const bool emit_errors = false;
-	if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(content, istr, emit_errors))
+	const bool emit_parse_errors = false;
+
+	std::string debug_body("(empty)");
+	bool parsed=true;
+	if (EOF == istr.peek())
+	{
+		parsed=false;
+	}
+	// Try to parse body as llsd, no matter what 'content-type' says.
+	else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors))
+	{
+		parsed=false;
+		char body[1025]; 
+		body[1024] = '\0';
+		istr.seekg(0, std::ios::beg);
+		istr.get(body,1024);
+		if (strlen(body) > 0)
+		{
+			mContent = body;
+			debug_body = body;
+		}
+	}
+
+	// Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
+	if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE)))
 	{
-		llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl;
-		content["reason"] = reason;
+		llwarns << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] " 
+			<< "(" << mReason << ") body: " << debug_body << llendl;
 	}
 
-	completed(status, reason, content);
+	httpCompleted();
 }
 
 // virtual
-void LLCurl::Responder::completed(U32 status, const std::string& reason, const LLSD& content)
+void LLCurl::Responder::httpCompleted()
 {
-	if (isGoodStatus(status))
+	if (isGoodStatus())
 	{
-		result(content);
+		httpSuccess();
 	}
 	else
 	{
-		errorWithContent(status, reason, content);
+		httpFailure();
 	}
 }
 
-//virtual
-void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, const LLSD& content)
-{
-
-}
-
 //////////////////////////////////////////////////////////////////////////////
 
 std::set<CURL*> LLCurl::Easy::sFreeHandles;
@@ -287,7 +362,8 @@ LLCurl::Easy* LLCurl::Easy::getEasy()
 	if (!easy->mCurlEasyHandle)
 	{
 		// this can happen if we have too many open files (fails in c-ares/ares_init.c)
-		llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
+		LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: " 
+			<< gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
 		delete easy;
 		return NULL;
 	}
@@ -312,10 +388,14 @@ LLCurl::Easy::~Easy()
 	for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
 	LL_CHECK_MEMORY
 	if (mResponder && LLCurl::sNotQuitting) //aborted
-	{	
-		std::string reason("Request timeout, aborted.") ;
-		mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort
-			reason, mChannels, mOutput);		
+	{
+		// HTTP_REQUEST_TIME_OUT, timeout, abort
+		// *TODO: This looks like improper use of the 408 status code.
+		// See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9
+		// This status code should be returned by the *server* when:
+		// "The client did not produce a request within the time that the server was prepared to wait."
+		mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted.");
+		mResponder->completedRaw(mChannels, mOutput);
 		LL_CHECK_MEMORY
 	}
 	mResponder = NULL;
@@ -379,9 +459,9 @@ void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
 	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
 }
 
-U32 LLCurl::Easy::report(CURLcode code)
+S32 LLCurl::Easy::report(CURLcode code)
 {
-	U32 responseCode = 0;	
+	S32 responseCode = 0;
 	std::string responseReason;
 	
 	if (code == CURLE_OK)
@@ -391,14 +471,15 @@ U32 LLCurl::Easy::report(CURLcode code)
 	}
 	else
 	{
-		responseCode = 499;
+		responseCode = HTTP_INTERNAL_ERROR;
 		responseReason = strerror(code) + " : " + mErrorBuffer;
 		setopt(CURLOPT_FRESH_CONNECT, TRUE);
 	}
 
 	if (mResponder)
 	{	
-		mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput);
+		mResponder->setResult(responseCode, responseReason);
+		mResponder->completedRaw(mChannels, mOutput);
 		mResponder = NULL;
 	}
 	
@@ -435,9 +516,31 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
 	check_curl_code(result);
 }
 
+void LLCurl::Easy::slist_append(const std::string& header, const std::string& value)
+{
+	std::string pair(header);
+	if (value.empty())
+	{
+		pair += ":";
+	}
+	else
+	{
+		pair += ": ";
+		pair += value;
+	}
+	slist_append(pair.c_str());
+}
+
 void LLCurl::Easy::slist_append(const char* str)
 {
-	mHeaders = curl_slist_append(mHeaders, str);
+	if (str)
+	{
+		mHeaders = curl_slist_append(mHeaders, str);
+		if (!mHeaders)
+		{
+			llwarns << "curl_slist_append() call returned NULL appending " << str << llendl;
+		}
+	}
 }
 
 size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
@@ -524,8 +627,9 @@ void LLCurl::Easy::prepRequest(const std::string& url,
 
 	if (!post)
 	{
-		slist_append("Connection: keep-alive");
-		slist_append("Keep-alive: 300");
+		// *TODO: Should this be set to 'Keep-Alive' ?
+		slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive");
+		slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300");
 		// Accept and other headers
 		for (std::vector<std::string>::const_iterator iter = headers.begin();
 			 iter != headers.end(); ++iter)
@@ -804,7 +908,7 @@ S32 LLCurl::Multi::process()
 		++processed;
 		if (msg->msg == CURLMSG_DONE)
 		{
-			U32 response = 0;
+			S32 response = 0;
 			Easy* easy = NULL ;
 
 			{
@@ -823,7 +927,7 @@ S32 LLCurl::Multi::process()
 			}
 			else
 			{
-				response = 499;
+				response = HTTP_INTERNAL_ERROR;
 				//*TODO: change to llwarns
 				llerrs << "cleaned up curl request completed!" << llendl;
 			}
@@ -1122,13 +1226,13 @@ bool LLCurlRequest::getByteRange(const std::string& url,
 	easy->setopt(CURLOPT_HTTPGET, 1);
 	if (length > 0)
 	{
-		std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1);
-		easy->slist_append(range.c_str());
+		std::string range = llformat("bytes=%d-%d", offset,offset+length-1);
+		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
 	}
 	else if (offset > 0)
 	{
-		std::string range = llformat("Range: bytes=%d-", offset);
-		easy->slist_append(range.c_str());
+		std::string range = llformat("bytes=%d-", offset);
+		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
 	}
 	easy->setHeaders();
 	bool res = addEasy(easy);
@@ -1155,7 +1259,7 @@ bool LLCurlRequest::post(const std::string& url,
 	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
 	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
 
-	easy->slist_append("Content-Type: application/llsd+xml");
+	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
 	easy->setHeaders();
 
 	lldebugs << "POSTING: " << bytes << " bytes." << llendl;
@@ -1183,7 +1287,7 @@ bool LLCurlRequest::post(const std::string& url,
 	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
 	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
 
-	easy->slist_append("Content-Type: application/octet-stream");
+	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
 	easy->setHeaders();
 
 	lldebugs << "POSTING: " << bytes << " bytes." << llendl;
@@ -1555,6 +1659,14 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void*
 	}
 }
 
+void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value)
+{
+	if (isValid() && mEasy)
+	{
+		mEasy->slist_append(header, value);
+	}
+}
+
 void LLCurlEasyRequest::slist_append(const char* str)
 {
 	if (isValid() && mEasy)
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 7bcf61e233d6ff8967cc3b46c618cdf9d60a5cf6..8a65c783be1b52d18e9040f7a6cf3426348b940b 100755
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -39,6 +39,7 @@
 #include <curl/curl.h> // TODO: remove dependency
 
 #include "llbuffer.h"
+#include "llhttpconstants.h"
 #include "lliopipe.h"
 #include "llsd.h"
 #include "llthread.h"
@@ -77,59 +78,92 @@ class LLCurl
 		Responder();
 		virtual ~Responder();
 
-		/**
-		 * @brief return true if the status code indicates success.
-		 */
-		static bool isGoodStatus(U32 status)
+		virtual bool followRedir() 
 		{
-			return((200 <= status) && (status < 300));
+			return false;
 		}
-		
-		virtual void errorWithContent(
-			U32 status,
-			const std::string& reason,
-			const LLSD& content);
-			//< called by completed() on bad status 
-
-		virtual void error(U32 status, const std::string& reason);
-			//< called by default error(status, reason, content)
-		
-		virtual void result(const LLSD& content);
-			//< called by completed for good status codes.
 
+		/**
+		 * @brief return true if the status code indicates success.
+		 */
+		bool isGoodStatus() const { return isHttpGoodStatus(mStatus); }
+
+		S32 getStatus() const { return mStatus; }
+		const std::string& getReason() const { return mReason; }
+		const LLSD& getContent() const { return mContent; }
+		bool hasResponseHeader(const std::string& header) const;
+		const std::string& getResponseHeader(const std::string& header) const;
+		const LLSD& getResponseHeaders() const { return mResponseHeaders; }
+		const std::string& getURL() const { return mURL; }
+		EHTTPMethod getHTTPMethod() const { return mHTTPMethod; }
+
+		// This formats response information for use in log spam.  Includes content spam.
+		std::string dumpResponse() const;
+
+		// Allows direct triggering of success/error with different results.
+		void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
+		void successResult(const LLSD& content);
+		void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
+
+		// The default implementation will try to parse body content as an LLSD, however
+		// it should not spam about parsing failures unless the server sent a
+		// Content-Type: application/llsd+xml header.
 		virtual void completedRaw(
-			U32 status,
-			const std::string& reason,
 			const LLChannelDescriptors& channels,
 			const LLIOPipe::buffer_ptr_t& buffer);
 			/**< Override point for clients that may want to use this
 			   class when the response is some other format besides LLSD
 			*/
+			
 
-		virtual void completed(
-			U32 status,
-			const std::string& reason,
-			const LLSD& content);
-			/**< The default implemetnation calls
+		// The http* methods are not public since these should be triggered internally
+		// after status, reason, content, etc have been set.
+		// If you need to trigger a completion method, use the *Result methods, above.
+	protected:
+		// These methods are the preferred way to process final results.
+		// By default, when one of these is called the following information will be resolved:
+		// * HTTP status code - getStatus()
+		// * Reason string - getReason()
+		// * Content - getContent()
+		// * Response Headers - getResponseHeaders()
+
+		// By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code.
+		virtual void httpSuccess();
+			//< called by completed for good status codes.
+
+		// By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code.
+		virtual void httpFailure();
+			//< called by httpCompleted() on bad status 
+
+		// httpCompleted does not generally need to be overridden, unless
+		// you don't care about the status code (which determine httpFailure or httpSuccess)
+		// or if you want to re-interpret what a 'good' vs' bad' status code is.
+		virtual void httpCompleted();
+			/**< The default implementation calls
 				either:
-				* result(), or
-				* error() 
+				* httpSuccess(), or
+				* httpFailure() 
 			*/
-			
-			// Override to handle parsing of the header only.  Note: this is the only place where the contents
-			// of the header can be parsed.  In the ::completed call above only the body is contained in the LLSD.
-			virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content);
-
-			// Used internally to set the url for debugging later.
-			void setURL(const std::string& url);
 
-			virtual bool followRedir() 
-			{
-				return false;
-			}
+	public:
+		void setHTTPMethod(EHTTPMethod method);
+		void setURL(const std::string& url);
+		void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD());
+		void setResponseHeader(const std::string& header, const std::string& value);
 
 	private:
+		// These can be accessed by the get* methods.  Treated as 'read-only' during completion handlers.
+		EHTTPMethod mHTTPMethod;
 		std::string mURL;
+		LLSD mResponseHeaders;
+
+	protected:
+		// These should also generally be treated as 'read-only' during completion handlers
+		// and should be accessed by the get* methods.  The exception to this rule would
+		// be when overriding the completedRaw method in preparation for calling httpCompleted().
+		S32 mStatus;
+		std::string mReason;
+		LLSD mContent;
 	};
 	typedef LLPointer<Responder>	ResponderPtr;
 
@@ -225,10 +259,11 @@ class LLCurl::Easy
 	// Copies the string so that it is guaranteed to stick around
 	void setoptString(CURLoption option, const std::string& value);
 
+	void slist_append(const std::string& header, const std::string& value);
 	void slist_append(const char* str);
 	void setHeaders();
 
-	U32 report(CURLcode);
+	S32 report(CURLcode);
 	void getTransferInfo(LLCurl::TransferInfo* info);
 
 	void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false);
@@ -484,6 +519,7 @@ class LLCurlEasyRequest
 	void setWriteCallback(curl_write_callback callback, void* userdata);
 	void setReadCallback(curl_read_callback callback, void* userdata);
 	void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
+	void slist_append(const std::string& header, const std::string& value);
 	void slist_append(const char* str);
 	void sendRequest(const std::string& url);
 	void requestComplete();
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
index 7dcf160c9ba9c3ccb8d88a4b84d09cdbbac7d01f..e841c8e3ed548177739ce57ee875357e6927b1af 100755
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ b/indra/llmessage/llhttpassetstorage.cpp
@@ -51,13 +51,6 @@ const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f;
 
 const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096;
 
-const S32 HTTP_OK = 200;
-const S32 HTTP_PUT_OK = 201;
-const S32 HTTP_NO_CONTENT = 204;
-const S32 HTTP_MISSING = 404;
-const S32 HTTP_SERVER_BAD_GATEWAY = 502;
-const S32 HTTP_SERVER_TEMP_UNAVAILABLE = 503;
-
 /////////////////////////////////////////////////////////////////////////////////
 // LLTempAssetData
 // An asset not stored on central asset store, but on a simulator node somewhere.
@@ -952,7 +945,7 @@ void LLHTTPAssetStorage::checkForTimeouts()
 			{
 				if (curl_msg->data.result == CURLE_OK && 
 					(   curl_result == HTTP_OK 
-					 || curl_result == HTTP_PUT_OK 
+					 || curl_result == HTTP_CREATED
 					 || curl_result == HTTP_NO_CONTENT))
 				{
 					llinfos << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << llendl;
@@ -963,8 +956,8 @@ void LLHTTPAssetStorage::checkForTimeouts()
 				}
 				else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||
 						curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
-						curl_result == HTTP_SERVER_BAD_GATEWAY ||
-						curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)
+						curl_result == HTTP_BAD_GATEWAY ||
+						curl_result == HTTP_SERVICE_UNAVAILABLE)
 				{
 					llwarns << "Re-requesting upload for " << req->getUUID() << ".  Received upload error to " << req->mURLBuffer <<
 						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
@@ -985,8 +978,8 @@ void LLHTTPAssetStorage::checkForTimeouts()
 
 				if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||
 						curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
-						curl_result == HTTP_SERVER_BAD_GATEWAY ||
-						curl_result == HTTP_SERVER_TEMP_UNAVAILABLE))
+						curl_result == HTTP_BAD_GATEWAY ||
+						curl_result == HTTP_SERVICE_UNAVAILABLE))
 				{
 					// shared upload finished callback
 					// in the base class, this is called from processUploadComplete
@@ -1018,7 +1011,7 @@ void LLHTTPAssetStorage::checkForTimeouts()
 					llwarns << "Failure downloading " << req->mURLBuffer << 
 						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
 
-					xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
+					xfer_result = (curl_result == HTTP_NOT_FOUND) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
 
 					if (req->mVFile)
 					{
@@ -1240,7 +1233,7 @@ S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asse
 		}
 		else
 		{
-			xfer_result = curl_result == HTTP_MISSING ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
+			xfer_result = curl_result == HTTP_NOT_FOUND ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
 			llinfos << "Failure downloading " << req.mURLBuffer << 
 				" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
 		}
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 3561459bb40f28da675fed5bb755aa4d3eb83af9..53cef5455924a328454a03d3fc4ee15f2c61d3a0 100755
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -54,7 +54,7 @@ namespace
 	{
 	public:
 		LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder)
-			: LLURLRequestComplete(), mResponder(responder), mStatus(499),
+			: LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR),
 			  mReason("LLURLRequest complete w/no status")
 		{
 		}
@@ -63,7 +63,7 @@ namespace
 		{
 		}
 
-		virtual void httpStatus(U32 status, const std::string& reason)
+		virtual void httpStatus(S32 status, const std::string& reason)
 		{
 			LLURLRequestComplete::httpStatus(status,reason);
 
@@ -74,30 +74,33 @@ namespace
 		virtual void complete(const LLChannelDescriptors& channels,
 							  const buffer_ptr_t& buffer)
 		{
+			// *TODO: Re-interpret mRequestStatus codes?
+			//        Would like to detect curl errors, such as
+			//        connection errors, write erros, etc.
 			if (mResponder.get())
 			{
-				// Allow clients to parse headers before we attempt to parse
-				// the body and provide completed/result/error calls.
-				mResponder->completedHeader(mStatus, mReason, mHeaderOutput);
-				mResponder->completedRaw(mStatus, mReason, channels, buffer);
+				mResponder->setResult(mStatus, mReason);
+				mResponder->completedRaw(channels, buffer);
 			}
 		}
 		virtual void header(const std::string& header, const std::string& value)
 		{
-			mHeaderOutput[header] = value;
+			if (mResponder.get())
+			{
+				mResponder->setResponseHeader(header, value);
+			}
 		}
 
 	private:
 		LLCurl::ResponderPtr mResponder;
-		U32 mStatus;
+		S32 mStatus;
 		std::string mReason;
-		LLSD mHeaderOutput;
 	};
 	
 	class Injector : public LLIOPipe
 	{
 	public:
-		virtual const char* contentType() = 0;
+		virtual const std::string& contentType() = 0;
 	};
 
 	class LLSDInjector : public Injector
@@ -106,7 +109,7 @@ namespace
 		LLSDInjector(const LLSD& sd) : mSD(sd) {}
 		virtual ~LLSDInjector() {}
 
-		const char* contentType() { return "application/llsd+xml"; }
+		const std::string& contentType() { return HTTP_CONTENT_LLSD_XML; }
 
 		virtual EStatus process_impl(const LLChannelDescriptors& channels,
 			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
@@ -126,7 +129,7 @@ namespace
 		RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {}
 		virtual ~RawInjector() {delete mData;}
 
-		const char* contentType() { return "application/octet-stream"; }
+		const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
 
 		virtual EStatus process_impl(const LLChannelDescriptors& channels,
 			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
@@ -147,7 +150,7 @@ namespace
 		FileInjector(const std::string& filename) : mFilename(filename) {}
 		virtual ~FileInjector() {}
 
-		const char* contentType() { return "application/octet-stream"; }
+		const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
 
 		virtual EStatus process_impl(const LLChannelDescriptors& channels,
 			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
@@ -180,7 +183,7 @@ namespace
 		VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {}
 		virtual ~VFileInjector() {}
 
-		const char* contentType() { return "application/octet-stream"; }
+		const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }
 
 		virtual EStatus process_impl(const LLChannelDescriptors& channels,
 			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump)
@@ -213,7 +216,7 @@ void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback cal
 
 static void request(
 	const std::string& url,
-	LLURLRequest::ERequestAction method,
+	EHTTPMethod method,
 	Injector* body_injector,
 	LLCurl::ResponderPtr responder,
 	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
@@ -224,7 +227,7 @@ static void request(
 	{
 		if (responder)
 		{
-			responder->completed(U32_MAX, "No pump", LLSD());
+			responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");
 		}
 		delete body_injector;
 		return;
@@ -236,7 +239,7 @@ static void request(
 	{
 		if (responder)
 		{
-			responder->completed(498, "Internal Error - curl failure", LLSD());
+			responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure");
 		}
 		delete req;
 		delete body_injector;
@@ -245,81 +248,74 @@ static void request(
 
 	req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
 
-	
-	lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
-		<< headers << llendl;
+
+	LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL;
 
 	// Insert custom headers if the caller sent any
 	if (headers.isMap())
 	{
-		if (headers.has("Cookie"))
+		if (headers.has(HTTP_OUT_HEADER_COOKIE))
 		{
 			req->allowCookies();
 		}
 
-        LLSD::map_const_iterator iter = headers.beginMap();
-        LLSD::map_const_iterator end  = headers.endMap();
-
-        for (; iter != end; ++iter)
-        {
-            std::ostringstream header;
-            //if the header is "Pragma" with no value
-            //the caller intends to force libcurl to drop
-            //the Pragma header it so gratuitously inserts
-            //Before inserting the header, force libcurl
-            //to not use the proxy (read: llurlrequest.cpp)
-			static const std::string PRAGMA("Pragma");
-			if ((iter->first == PRAGMA) && (iter->second.asString().empty()))
-            {
-                req->useProxy(false);
-            }
-            header << iter->first << ": " << iter->second.asString() ;
-            lldebugs << "header = " << header.str() << llendl;
-            req->addHeader(header.str().c_str());
-        }
-    }
+		LLSD::map_const_iterator iter = headers.beginMap();
+		LLSD::map_const_iterator end  = headers.endMap();
+
+		for (; iter != end; ++iter)
+		{
+			//if the header is "Pragma" with no value
+			//the caller intends to force libcurl to drop
+			//the Pragma header it so gratuitously inserts
+			//Before inserting the header, force libcurl
+			//to not use the proxy (read: llurlrequest.cpp)
+			if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty()))
+			{
+				req->useProxy(false);
+			}
+			LL_DEBUGS("LLHTTPClient") << "header = " << iter->first 
+				<< ": " << iter->second.asString() << LL_ENDL;
+			req->addHeader(iter->first, iter->second.asString());
+		}
+	}
 
 	// Check to see if we have already set Accept or not. If no one
 	// set it, set it to application/llsd+xml since that's what we
 	// almost always want.
-	if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST )
+	if( method != HTTP_PUT && method != HTTP_POST )
 	{
-		static const std::string ACCEPT("Accept");
-		if(!headers.has(ACCEPT))
+		if(!headers.has(HTTP_OUT_HEADER_ACCEPT))
 		{
-			req->addHeader("Accept: application/llsd+xml");
+			req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
 		}
 	}
 
 	if (responder)
 	{
 		responder->setURL(url);
+		responder->setHTTPMethod(method);
 	}
 
 	req->setCallback(new LLHTTPClientURLAdaptor(responder));
 
-	if (method == LLURLRequest::HTTP_POST  &&  gMessageSystem)
+	if (method == HTTP_POST  &&  gMessageSystem)
 	{
-		req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d",
-								gMessageSystem->mPort).c_str());
-   	}
+		req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d",
+					gMessageSystem->mPort));
+	}
 
-	if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST)
+	if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)
 	{
-		static const std::string CONTENT_TYPE("Content-Type");
-		if(!headers.has(CONTENT_TYPE))
+		if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE))
 		{
 			// If the Content-Type header was passed in, it has
 			// already been added as a header through req->addHeader
 			// in the loop above. We defer to the caller's wisdom, but
 			// if they did not specify a Content-Type, then ask the
 			// injector.
-			req->addHeader(
-				llformat(
-					"Content-Type: %s",
-					body_injector->contentType()).c_str());
+			req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType());
 		}
-   		chain.push_back(LLIOPipe::ptr_t(body_injector));
+		chain.push_back(LLIOPipe::ptr_t(body_injector));
 	}
 
 	chain.push_back(LLIOPipe::ptr_t(req));
@@ -340,9 +336,9 @@ void LLHTTPClient::getByteRange(
 	if(offset > 0 || bytes > 0)
 	{
 		std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
-		headers["Range"] = range;
+		headers[HTTP_OUT_HEADER_RANGE] = range;
 	}
-    request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
+    request(url,HTTP_GET, NULL, responder, timeout, headers);
 }
 
 void LLHTTPClient::head(
@@ -351,16 +347,16 @@ void LLHTTPClient::head(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
+	request(url, HTTP_HEAD, NULL, responder, timeout, headers);
 }
 
 void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
+	request(url, HTTP_GET, NULL, responder, timeout, headers);
 }
 void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
+	request(url, HTTP_HEAD, NULL, responder, timeout, headers);
 }
 void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout)
 {
@@ -401,7 +397,7 @@ class LLHTTPBuffer
 		return content;
 	}
 
-	std::string asString()
+	const std::string& asString()
 	{
 		return mBuffer;
 	}
@@ -430,7 +426,7 @@ class LLHTTPBuffer
   */
 static LLSD blocking_request(
 	const std::string& url,
-	LLURLRequest::ERequestAction method,
+	EHTTPMethod method,
 	const LLSD& body,
 	const LLSD& headers = LLSD(),
 	const F32 timeout = 5
@@ -473,11 +469,11 @@ static LLSD blocking_request(
 	}
 	
 	// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
-	if (method == LLURLRequest::HTTP_GET)
+	if (method == HTTP_GET)
 	{
 		curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
 	}
-	else if (method == LLURLRequest::HTTP_POST)
+	else if (method == HTTP_POST)
 	{
 		curl_easy_setopt(curlp, CURLOPT_POST, 1);
 		//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
@@ -486,18 +482,20 @@ static LLSD blocking_request(
 		body_str = ostr.str();
 		curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());
 		//copied from PHP libs, correct?
-		headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml");
+		headers_list = curl_slist_append(headers_list, 
+				llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
 
 		// copied from llurlrequest.cpp
 		// it appears that apache2.2.3 or django in etch is busted. If
 		// we do not clear the expect header, we get a 500. May be
 		// limited to django/mod_wsgi.
-		headers_list = curl_slist_append(headers_list, "Expect:");
+		headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str());
 	}
 	
 	// * Do the action using curl, handle results
 	lldebugs << "HTTP body: " << body_str << llendl;
-	headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml");
+	headers_list = curl_slist_append(headers_list,
+				llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
 	CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);
 	if ( curl_result != CURLE_OK )
 	{
@@ -506,11 +504,11 @@ static LLSD blocking_request(
 
 	LLSD response = LLSD::emptyMap();
 	S32 curl_success = curl_easy_perform(curlp);
-	S32 http_status = 499;
+	S32 http_status = HTTP_INTERNAL_ERROR;
 	curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);
 	response["status"] = http_status;
 	// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
-	if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
+	if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) )
 	{
 		// We expect 404s, don't spam for them.
 		llwarns << "CURL REQ URL: " << url << llendl;
@@ -540,12 +538,12 @@ static LLSD blocking_request(
 
 LLSD LLHTTPClient::blockingGet(const std::string& url)
 {
-	return blocking_request(url, LLURLRequest::HTTP_GET, LLSD());
+	return blocking_request(url, HTTP_GET, LLSD());
 }
 
 LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
 {
-	return blocking_request(url, LLURLRequest::HTTP_POST, body);
+	return blocking_request(url, HTTP_POST, body);
 }
 
 void LLHTTPClient::put(
@@ -555,7 +553,17 @@ void LLHTTPClient::put(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
+	request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
+}
+
+void LLHTTPClient::patch(
+	const std::string& url,
+	const LLSD& body,
+	ResponderPtr responder,
+	const LLSD& headers,
+	const F32 timeout)
+{
+	request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers);
 }
 
 void LLHTTPClient::post(
@@ -565,7 +573,7 @@ void LLHTTPClient::post(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
+	request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
 }
 
 void LLHTTPClient::postRaw(
@@ -576,7 +584,7 @@ void LLHTTPClient::postRaw(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
+	request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
 }
 
 void LLHTTPClient::postFile(
@@ -586,7 +594,7 @@ void LLHTTPClient::postFile(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers);
+	request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers);
 }
 
 void LLHTTPClient::postFile(
@@ -597,7 +605,7 @@ void LLHTTPClient::postFile(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
+	request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
 }
 
 // static
@@ -607,7 +615,7 @@ void LLHTTPClient::del(
 	const LLSD& headers,
 	const F32 timeout)
 {
-	request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers);
+	request(url, HTTP_DELETE, NULL, responder, timeout, headers);
 }
 
 // static
@@ -619,8 +627,8 @@ void LLHTTPClient::move(
 	const F32 timeout)
 {
 	LLSD headers = hdrs;
-	headers["Destination"] = destination;
-	request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers);
+	headers[HTTP_OUT_HEADER_DESTINATION] = destination;
+	request(url, HTTP_MOVE, NULL, responder, timeout, headers);
 }
 
 
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
index a7236ba16994200052aa4d1a5736ba12ff478be6..4e7495495fd3bfc7f2df01ee8096e0618a3344fe 100755
--- a/indra/llmessage/llhttpclient.h
+++ b/indra/llmessage/llhttpclient.h
@@ -74,6 +74,14 @@ class LLHTTPClient
 		ResponderPtr,
 		const LLSD& headers = LLSD(),
 		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
+	static void patch(
+		const std::string& url,
+		const LLSD& body,
+		ResponderPtr,
+		const LLSD& headers = LLSD(),
+		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
 	static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
 	static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
 
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
index 0b59209af1b6d1efea5e01150b4d92fcd29ac6bf..b56a804f9422ad5a475d2fbd051a6c801e36dc0d 100755
--- a/indra/llmessage/llhttpclientadapter.cpp
+++ b/indra/llmessage/llhttpclientadapter.cpp
@@ -35,18 +35,18 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo
 {
 	LLSD empty_pragma_header;
 	// Pragma is required to stop curl adding "no-cache"
-	// Space is required to stop llurlrequest from turnning off proxying
-	empty_pragma_header["Pragma"] = " "; 
+	// Space is required to stop llurlrequest from turning off proxying
+	empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " "; 
 	LLHTTPClient::get(url, responder, empty_pragma_header);
 }
 
 void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) 
 {
 	LLSD empty_pragma_header = headers;
-	if (!empty_pragma_header.has("Pragma"))
+	if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))
 	{
 		// as above
-		empty_pragma_header["Pragma"] = " ";
+		empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
 	}
 	LLHTTPClient::get(url, responder, empty_pragma_header);
 }
@@ -56,3 +56,18 @@ void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::
 	LLHTTPClient::put(url, body, responder);
 }
 
+void LLHTTPClientAdapter::put(
+		const std::string& url,
+		const LLSD& body,
+		LLCurl::ResponderPtr responder,
+		const LLSD& headers)
+{
+	LLHTTPClient::put(url, body, responder, headers);
+}
+
+void LLHTTPClientAdapter::del(
+	const std::string& url,
+	LLCurl::ResponderPtr responder)
+{
+	LLHTTPClient::del(url, responder);
+}
diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h
index aae6426a5921646cbf2768324c103cd21d39de96..270282c66fb43ed6ee2a516d7572e744e226e6ed 100755
--- a/indra/llmessage/llhttpclientadapter.h
+++ b/indra/llmessage/llhttpclientadapter.h
@@ -37,6 +37,14 @@ class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLH
 	virtual void get(const std::string& url, LLCurl::ResponderPtr responder);
 	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers);
 	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder);
+	virtual void put(
+		const std::string& url,
+		const LLSD& body,
+		LLCurl::ResponderPtr responder,
+		const LLSD& headers);
+	virtual void del(
+		const std::string& url,
+		LLCurl::ResponderPtr responder);
 };
 
 #endif
diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..016f1f19708a8182964fe22937569a0a9fa1f604
--- /dev/null
+++ b/indra/llmessage/llhttpconstants.cpp
@@ -0,0 +1,224 @@
+/** 
+ * @file llhttpconstants.cpp
+ * @brief Implementation of the HTTP request / response constant lookups
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * 
+ * Copyright (c) 2013, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llhttpconstants.h"
+#include "lltimer.h"
+
+// for curl_getdate() (apparently parsing RFC 1123 dates is hard)
+#include <curl/curl.h>
+
+// Outgoing headers. Do *not* use these to check incoming headers.
+// For incoming headers, use the lower-case headers, below.
+const std::string HTTP_OUT_HEADER_ACCEPT("Accept");
+const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET("Accept-Charset");
+const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING("Accept-Encoding");
+const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE("Accept-Language");
+const std::string HTTP_OUT_HEADER_ACCEPT_RANGES("Accept-Ranges");
+const std::string HTTP_OUT_HEADER_AGE("Age");
+const std::string HTTP_OUT_HEADER_ALLOW("Allow");
+const std::string HTTP_OUT_HEADER_AUTHORIZATION("Authorization");
+const std::string HTTP_OUT_HEADER_CACHE_CONTROL("Cache-Control");
+const std::string HTTP_OUT_HEADER_CONNECTION("Connection");
+const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION("Content-Description");
+const std::string HTTP_OUT_HEADER_CONTENT_ENCODING("Content-Encoding");
+const std::string HTTP_OUT_HEADER_CONTENT_ID("Content-ID");
+const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE("Content-Language");
+const std::string HTTP_OUT_HEADER_CONTENT_LENGTH("Content-Length");
+const std::string HTTP_OUT_HEADER_CONTENT_LOCATION("Content-Location");
+const std::string HTTP_OUT_HEADER_CONTENT_MD5("Content-MD5");
+const std::string HTTP_OUT_HEADER_CONTENT_RANGE("Content-Range");
+const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding");
+const std::string HTTP_OUT_HEADER_CONTENT_TYPE("Content-Type");
+const std::string HTTP_OUT_HEADER_COOKIE("Cookie");
+const std::string HTTP_OUT_HEADER_DATE("Date");
+const std::string HTTP_OUT_HEADER_DESTINATION("Destination");
+const std::string HTTP_OUT_HEADER_ETAG("ETag");
+const std::string HTTP_OUT_HEADER_EXPECT("Expect");
+const std::string HTTP_OUT_HEADER_EXPIRES("Expires");
+const std::string HTTP_OUT_HEADER_FROM("From");
+const std::string HTTP_OUT_HEADER_HOST("Host");
+const std::string HTTP_OUT_HEADER_IF_MATCH("If-Match");
+const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE("If-Modified-Since");
+const std::string HTTP_OUT_HEADER_IF_NONE_MATCH("If-None-Match");
+const std::string HTTP_OUT_HEADER_IF_RANGE("If-Range");
+const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since");
+const std::string HTTP_OUT_HEADER_KEEP_ALIVE("Keep-Alive");
+const std::string HTTP_OUT_HEADER_LAST_MODIFIED("Last-Modified");
+const std::string HTTP_OUT_HEADER_LOCATION("Location");
+const std::string HTTP_OUT_HEADER_MAX_FORWARDS("Max-Forwards");
+const std::string HTTP_OUT_HEADER_MIME_VERSION("MIME-Version");
+const std::string HTTP_OUT_HEADER_PRAGMA("Pragma");
+const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate");
+const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization");
+const std::string HTTP_OUT_HEADER_RANGE("Range");
+const std::string HTTP_OUT_HEADER_REFERER("Referer");
+const std::string HTTP_OUT_HEADER_RETRY_AFTER("Retry-After");
+const std::string HTTP_OUT_HEADER_SERVER("Server");
+const std::string HTTP_OUT_HEADER_SET_COOKIE("Set-Cookie");
+const std::string HTTP_OUT_HEADER_TE("TE");
+const std::string HTTP_OUT_HEADER_TRAILER("Trailer");
+const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING("Transfer-Encoding");
+const std::string HTTP_OUT_HEADER_UPGRADE("Upgrade");
+const std::string HTTP_OUT_HEADER_USER_AGENT("User-Agent");
+const std::string HTTP_OUT_HEADER_VARY("Vary");
+const std::string HTTP_OUT_HEADER_VIA("Via");
+const std::string HTTP_OUT_HEADER_WARNING("Warning");
+const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE("WWW-Authenticate");
+
+// Incoming headers are normalized to lower-case.
+const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE("accept-language");
+const std::string HTTP_IN_HEADER_CACHE_CONTROL("cache-control");
+const std::string HTTP_IN_HEADER_CONTENT_LENGTH("content-length");
+const std::string HTTP_IN_HEADER_CONTENT_LOCATION("content-location");
+const std::string HTTP_IN_HEADER_CONTENT_TYPE("content-type");
+const std::string HTTP_IN_HEADER_HOST("host");
+const std::string HTTP_IN_HEADER_LOCATION("location");
+const std::string HTTP_IN_HEADER_RETRY_AFTER("retry-after");
+const std::string HTTP_IN_HEADER_SET_COOKIE("set-cookie");
+const std::string HTTP_IN_HEADER_USER_AGENT("user-agent");
+const std::string HTTP_IN_HEADER_X_FORWARDED_FOR("x-forwarded-for");
+
+const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml");
+const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream");
+const std::string HTTP_CONTENT_XML("application/xml");
+const std::string HTTP_CONTENT_JSON("application/json");
+const std::string HTTP_CONTENT_TEXT_HTML("text/html");
+const std::string HTTP_CONTENT_TEXT_HTML_UTF8("text/html; charset=utf-8");
+const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8("text/plain; charset=utf-8");
+const std::string HTTP_CONTENT_TEXT_LLSD("text/llsd");
+const std::string HTTP_CONTENT_TEXT_XML("text/xml");
+const std::string HTTP_CONTENT_TEXT_LSL("text/lsl");
+const std::string HTTP_CONTENT_TEXT_PLAIN("text/plain");
+const std::string HTTP_CONTENT_IMAGE_X_J2C("image/x-j2c");
+const std::string HTTP_CONTENT_IMAGE_J2C("image/j2c");
+const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg");
+const std::string HTTP_CONTENT_IMAGE_PNG("image/png");
+const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp");
+
+const std::string HTTP_NO_CACHE("no-cache");
+const std::string HTTP_NO_CACHE_CONTROL("no-cache, max-age=0");
+
+const std::string HTTP_VERB_INVALID("(invalid)");
+const std::string HTTP_VERB_HEAD("HEAD");
+const std::string HTTP_VERB_GET("GET");
+const std::string HTTP_VERB_PUT("PUT");
+const std::string HTTP_VERB_POST("POST");
+const std::string HTTP_VERB_DELETE("DELETE");
+const std::string HTTP_VERB_MOVE("MOVE");
+const std::string HTTP_VERB_OPTIONS("OPTIONS");
+
+const std::string& httpMethodAsVerb(EHTTPMethod method)
+{
+	static const std::string VERBS[] =
+	{
+		HTTP_VERB_INVALID,
+		HTTP_VERB_HEAD,
+		HTTP_VERB_GET,
+		HTTP_VERB_PUT,
+		HTTP_VERB_POST,
+		HTTP_VERB_DELETE,
+		HTTP_VERB_MOVE,
+		HTTP_VERB_OPTIONS
+	};
+	if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))
+	{
+		return VERBS[0];
+	}
+	return VERBS[method];
+}
+
+bool isHttpInformationalStatus(S32 status)
+{
+	// Check for status 1xx.
+	return((100 <= status) && (status < 200));
+}
+
+bool isHttpGoodStatus(S32 status)
+{
+	// Check for status 2xx.
+	return((200 <= status) && (status < 300));
+}
+
+bool isHttpRedirectStatus(S32 status)
+{
+	// Check for status 3xx.
+	return((300 <= status) && (status < 400));
+}
+
+bool isHttpClientErrorStatus(S32 status)
+{
+	// Status 499 is sometimes used for re-interpreted status 2xx errors
+	// based on body content.  Treat these as potentially retryable 'server' status errors,
+	// since we do not have enough context to know if this will always fail.
+	if (HTTP_INTERNAL_ERROR == status) return false;
+
+	// Check for status 5xx.
+	return((400 <= status) && (status < 500));
+}
+
+bool isHttpServerErrorStatus(S32 status)
+{
+	// Status 499 is sometimes used for re-interpreted status 2xx errors.
+	// Allow retry of these, since we don't have enough information in this
+	// context to know if this will always fail.
+	if (HTTP_INTERNAL_ERROR == status) return true;
+
+	// Check for status 5xx.
+	return((500 <= status) && (status < 600));
+}
+
+// Parses 'Retry-After' header contents and returns seconds until retry should occur.
+bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait)
+{
+	// *TODO:  This needs testing!   Not in use yet.
+	// Examples of Retry-After headers:
+	// Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+	// Retry-After: 120
+
+	// Check for number of seconds version, first:
+	char* end = 0;
+	// Parse as double
+	double seconds = std::strtod(retry_after.c_str(), &end);
+	if ( end != 0 && *end == 0 )
+	{
+		// Successful parse
+		seconds_to_wait = (F32) seconds;
+		return true;
+	}
+
+	// Parse rfc1123 date.
+	time_t date = curl_getdate(retry_after.c_str(), NULL );
+	if (-1 == date) return false;
+
+	seconds_to_wait = (F64)date - LLTimer::getTotalSeconds();
+
+	return true;
+}
+
diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h
new file mode 100755
index 0000000000000000000000000000000000000000..aa947af414b2d3af97b70106bc408d4b9bdb58aa
--- /dev/null
+++ b/indra/llmessage/llhttpconstants.h
@@ -0,0 +1,224 @@
+/** 
+ * @file llhttpconstants.h
+ * @brief Constants for HTTP requests and responses
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2001-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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_HTTP_CONSTANTS_H
+#define LL_HTTP_CONSTANTS_H
+
+#include "stdtypes.h"
+
+/////// HTTP STATUS CODES ///////
+
+// Standard errors from HTTP spec:
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
+const S32 HTTP_CONTINUE = 100;
+const S32 HTTP_SWITCHING_PROTOCOLS = 101;
+
+// Success
+const S32 HTTP_OK = 200;
+const S32 HTTP_CREATED = 201;
+const S32 HTTP_ACCEPTED = 202;
+const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
+const S32 HTTP_NO_CONTENT = 204;
+const S32 HTTP_RESET_CONTENT = 205;
+const S32 HTTP_PARTIAL_CONTENT = 206;
+
+// Redirection
+const S32 HTTP_MULTIPLE_CHOICES = 300;
+const S32 HTTP_MOVED_PERMANENTLY = 301;
+const S32 HTTP_FOUND = 302;
+const S32 HTTP_SEE_OTHER = 303;
+const S32 HTTP_NOT_MODIFIED = 304;
+const S32 HTTP_USE_PROXY = 305;
+const S32 HTTP_TEMPORARY_REDIRECT = 307;
+
+// Client Error
+const S32 HTTP_BAD_REQUEST = 400;
+const S32 HTTP_UNAUTHORIZED = 401;
+const S32 HTTP_PAYMENT_REQUIRED = 402;
+const S32 HTTP_FORBIDDEN = 403;
+const S32 HTTP_NOT_FOUND = 404;
+const S32 HTTP_METHOD_NOT_ALLOWED = 405;
+const S32 HTTP_NOT_ACCEPTABLE = 406;
+const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
+const S32 HTTP_REQUEST_TIME_OUT = 408;
+const S32 HTTP_CONFLICT = 409;
+const S32 HTTP_GONE = 410;
+const S32 HTTP_LENGTH_REQUIRED = 411;
+const S32 HTTP_PRECONDITION_FAILED = 412;
+const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
+const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
+const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
+const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+const S32 HTTP_EXPECTATION_FAILED = 417;
+
+// Server Error
+const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
+const S32 HTTP_NOT_IMPLEMENTED = 501;
+const S32 HTTP_BAD_GATEWAY = 502;
+const S32 HTTP_SERVICE_UNAVAILABLE = 503;
+const S32 HTTP_GATEWAY_TIME_OUT = 504;
+const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
+
+// We combine internal process errors with status codes
+// These status codes should not be sent over the wire
+//   and indicate something went wrong internally.
+// If you get these they are not normal.
+const S32 HTTP_INTERNAL_CURL_ERROR = 498;
+const S32 HTTP_INTERNAL_ERROR = 499;
+
+
+////// HTTP Methods //////
+
+extern const std::string HTTP_VERB_INVALID;
+extern const std::string HTTP_VERB_HEAD;
+extern const std::string HTTP_VERB_GET;
+extern const std::string HTTP_VERB_PUT;
+extern const std::string HTTP_VERB_POST;
+extern const std::string HTTP_VERB_DELETE;
+extern const std::string HTTP_VERB_MOVE;
+extern const std::string HTTP_VERB_OPTIONS;
+
+enum EHTTPMethod
+{
+	HTTP_INVALID = 0,
+	HTTP_HEAD,
+	HTTP_GET,
+	HTTP_PUT,
+	HTTP_POST,
+	HTTP_DELETE,
+	HTTP_MOVE, // Caller will need to set 'Destination' header
+	HTTP_OPTIONS,
+	HTTP_PATCH,
+	HTTP_METHOD_COUNT
+};
+
+const std::string& httpMethodAsVerb(EHTTPMethod method);
+bool isHttpInformationalStatus(S32 status);
+bool isHttpGoodStatus(S32 status);
+bool isHttpRedirectStatus(S32 status);
+bool isHttpClientErrorStatus(S32 status);
+bool isHttpServerErrorStatus(S32 status);
+
+// Parses 'Retry-After' header contents and returns seconds until retry should occur.
+bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait);
+
+//// HTTP Headers /////
+
+// Outgoing headers. Do *not* use these to check incoming headers.
+// For incoming headers, use the lower-case headers, below.
+extern const std::string HTTP_OUT_HEADER_ACCEPT;
+extern const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET;
+extern const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING;
+extern const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE;
+extern const std::string HTTP_OUT_HEADER_ACCEPT_RANGES;
+extern const std::string HTTP_OUT_HEADER_AGE;
+extern const std::string HTTP_OUT_HEADER_ALLOW;
+extern const std::string HTTP_OUT_HEADER_AUTHORIZATION;
+extern const std::string HTTP_OUT_HEADER_CACHE_CONTROL;
+extern const std::string HTTP_OUT_HEADER_CONNECTION;
+extern const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION;
+extern const std::string HTTP_OUT_HEADER_CONTENT_ENCODING;
+extern const std::string HTTP_OUT_HEADER_CONTENT_ID;
+extern const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE;
+extern const std::string HTTP_OUT_HEADER_CONTENT_LENGTH;
+extern const std::string HTTP_OUT_HEADER_CONTENT_LOCATION;
+extern const std::string HTTP_OUT_HEADER_CONTENT_MD5;
+extern const std::string HTTP_OUT_HEADER_CONTENT_RANGE;
+extern const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING;
+extern const std::string HTTP_OUT_HEADER_CONTENT_TYPE;
+extern const std::string HTTP_OUT_HEADER_COOKIE;
+extern const std::string HTTP_OUT_HEADER_DATE;
+extern const std::string HTTP_OUT_HEADER_DESTINATION;
+extern const std::string HTTP_OUT_HEADER_ETAG;
+extern const std::string HTTP_OUT_HEADER_EXPECT;
+extern const std::string HTTP_OUT_HEADER_EXPIRES;
+extern const std::string HTTP_OUT_HEADER_FROM;
+extern const std::string HTTP_OUT_HEADER_HOST;
+extern const std::string HTTP_OUT_HEADER_IF_MATCH;
+extern const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE;
+extern const std::string HTTP_OUT_HEADER_IF_NONE_MATCH;
+extern const std::string HTTP_OUT_HEADER_IF_RANGE;
+extern const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE;
+extern const std::string HTTP_OUT_HEADER_KEEP_ALIVE;
+extern const std::string HTTP_OUT_HEADER_LAST_MODIFIED;
+extern const std::string HTTP_OUT_HEADER_LOCATION;
+extern const std::string HTTP_OUT_HEADER_MAX_FORWARDS;
+extern const std::string HTTP_OUT_HEADER_MIME_VERSION;
+extern const std::string HTTP_OUT_HEADER_PRAGMA;
+extern const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE;
+extern const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION;
+extern const std::string HTTP_OUT_HEADER_RANGE;
+extern const std::string HTTP_OUT_HEADER_REFERER;
+extern const std::string HTTP_OUT_HEADER_RETRY_AFTER;
+extern const std::string HTTP_OUT_HEADER_SERVER;
+extern const std::string HTTP_OUT_HEADER_SET_COOKIE;
+extern const std::string HTTP_OUT_HEADER_TE;
+extern const std::string HTTP_OUT_HEADER_TRAILER;
+extern const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING;
+extern const std::string HTTP_OUT_HEADER_UPGRADE;
+extern const std::string HTTP_OUT_HEADER_USER_AGENT;
+extern const std::string HTTP_OUT_HEADER_VARY;
+extern const std::string HTTP_OUT_HEADER_VIA;
+extern const std::string HTTP_OUT_HEADER_WARNING;
+extern const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE;
+
+// Incoming headers are normalized to lower-case.
+extern const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE;
+extern const std::string HTTP_IN_HEADER_CACHE_CONTROL;
+extern const std::string HTTP_IN_HEADER_CONTENT_LENGTH;
+extern const std::string HTTP_IN_HEADER_CONTENT_LOCATION;
+extern const std::string HTTP_IN_HEADER_CONTENT_TYPE;
+extern const std::string HTTP_IN_HEADER_HOST;
+extern const std::string HTTP_IN_HEADER_LOCATION;
+extern const std::string HTTP_IN_HEADER_RETRY_AFTER;
+extern const std::string HTTP_IN_HEADER_SET_COOKIE;
+extern const std::string HTTP_IN_HEADER_USER_AGENT;
+extern const std::string HTTP_IN_HEADER_X_FORWARDED_FOR;
+
+//// HTTP Content Types ////
+
+extern const std::string HTTP_CONTENT_LLSD_XML;
+extern const std::string HTTP_CONTENT_OCTET_STREAM;
+extern const std::string HTTP_CONTENT_XML;
+extern const std::string HTTP_CONTENT_JSON;
+extern const std::string HTTP_CONTENT_TEXT_HTML;
+extern const std::string HTTP_CONTENT_TEXT_HTML_UTF8;
+extern const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8;
+extern const std::string HTTP_CONTENT_TEXT_LLSD;
+extern const std::string HTTP_CONTENT_TEXT_XML;
+extern const std::string HTTP_CONTENT_TEXT_LSL;
+extern const std::string HTTP_CONTENT_TEXT_PLAIN;
+extern const std::string HTTP_CONTENT_IMAGE_X_J2C;
+extern const std::string HTTP_CONTENT_IMAGE_J2C;
+extern const std::string HTTP_CONTENT_IMAGE_JPEG;
+extern const std::string HTTP_CONTENT_IMAGE_PNG;
+extern const std::string HTTP_CONTENT_IMAGE_BMP;
+
+//// HTTP Cache Settings ////
+extern const std::string HTTP_NO_CACHE;
+extern const std::string HTTP_NO_CACHE_CONTROL;
+
+#endif
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index 5c2f73eccb809bb32e50900ec9fd23f0139b4596..5058fdaf517aaabe1a921dc9c9b76d3c2ab8bc1b 100755
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -30,9 +30,15 @@
 #include <boost/tokenizer.hpp>
 
 #include "llstl.h"
-#include "lliohttpserver.h" // for string constants
+#include "llhttpconstants.h"
 
-static const std::string CONTEXT_WILDCARD("wildcard");
+const std::string CONTEXT_HEADERS("headers");
+const std::string CONTEXT_PATH("path");
+const std::string CONTEXT_QUERY_STRING("query-string");
+const std::string CONTEXT_REQUEST("request");
+const std::string CONTEXT_RESPONSE("response");
+const std::string CONTEXT_VERB("verb");
+const std::string CONTEXT_WILDCARD("wildcard");
 
 /**
  * LLHTTPNode
@@ -173,21 +179,23 @@ LLSD LLHTTPNode::simpleDel(const LLSD&) const
 void  LLHTTPNode::options(ResponsePtr response, const LLSD& context) const
 {
 	//llinfos << "options context: " << context << llendl;
+	LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL;
 
 	// default implementation constructs an url to the documentation.
+	// *TODO: Check for 'Host' header instead of 'host' header?
 	std::string host(
-		context[CONTEXT_REQUEST][CONTEXT_HEADERS]["host"].asString());
+		context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString());
 	if(host.empty())
 	{
-		response->status(400, "Bad Request -- need Host header");
+		response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header");
 		return;
 	}
 	std::ostringstream ostr;
 	ostr << "http://" << host << "/web/server/api";
-	ostr << context[CONTEXT_REQUEST]["path"].asString();
+	ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString();
 	static const std::string DOC_HEADER("X-Documentation-URL");
 	response->addHeader(DOC_HEADER, ostr.str());
-	response->status(200, "OK");
+	response->status(HTTP_OK, "OK");
 }
 
 
@@ -389,17 +397,17 @@ void LLHTTPNode::Response::statusUnknownError(S32 code)
 
 void LLHTTPNode::Response::notFound(const std::string& message)
 {
-	status(404, message);
+	status(HTTP_NOT_FOUND, message);
 }
 
 void LLHTTPNode::Response::notFound()
 {
-	status(404, "Not Found");
+	status(HTTP_NOT_FOUND, "Not Found");
 }
 
 void LLHTTPNode::Response::methodNotAllowed()
 {
-	status(405, "Method Not Allowed");
+	status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed");
 }
 
 void LLHTTPNode::Response::addHeader(
@@ -467,7 +475,7 @@ LLSimpleResponse::~LLSimpleResponse()
 
 void LLSimpleResponse::result(const LLSD& result)
 {
-	status(200, "OK");
+	status(HTTP_OK, "OK");
 }
 
 void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const LLSD& headers)
@@ -475,6 +483,11 @@ void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const L
 	status(code,body);
 }
 
+void LLSimpleResponse::extendedResult(S32 code, const LLSD& r, const LLSD& headers)
+{
+	status(code,"(LLSD)");
+}
+
 void LLSimpleResponse::status(S32 code, const std::string& message)
 {
 	mCode = code;
diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h
index 148647ddde16ecbc76fb3fa4dc138a285a876933..1144d88be16dfb62864b36e4c85ae065efab14c7 100755
--- a/indra/llmessage/llhttpnode.h
+++ b/indra/llmessage/llhttpnode.h
@@ -31,6 +31,17 @@
 #include "llrefcount.h"
 #include "llsd.h"
 
+// common strings use for populating the context. basically 'request',
+// 'wildcard', and 'headers'.
+extern const std::string CONTEXT_HEADERS;
+extern const std::string CONTEXT_PATH;
+extern const std::string CONTEXT_QUERY_STRING;
+extern const std::string CONTEXT_REQUEST;
+extern const std::string CONTEXT_RESPONSE;
+extern const std::string CONTEXT_VERB;
+extern const std::string CONTEXT_WILDCARD;
+
+
 class LLChainIOFactory;
 
 /**
@@ -60,6 +71,8 @@ class LLChainIOFactory;
  */
 class LLHTTPNode
 {
+protected:
+    LOG_CLASS(LLHTTPNode);
 public:
 	LLHTTPNode();
 	virtual ~LLHTTPNode();
@@ -100,7 +113,12 @@ class LLHTTPNode
 		/**
 		 * @brief return status code and message with headers.
 		 */
-		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) = 0;
+		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0;
+
+		/**
+		 * @brief return status code and LLSD result with headers.
+		 */
+		virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0;
 
 		/**
 		 * @brief return status code and reason string on http header,
@@ -118,7 +136,7 @@ class LLHTTPNode
 		virtual void methodNotAllowed();
 
 		/**
-		* @breif Add a name: value http header.
+		* @brief Add a name: value http header.
 		*
 		* No effort is made to ensure the response is a valid http
 		* header.
@@ -187,15 +205,15 @@ class LLHTTPNode
 			 name, and return true if the name will construct to a valid url.
 			 For convenience, the <code>getChild()</code> method above will
 			 automatically insert the name in
-			 context["request"]["wildcard"][key] if this method returns true.
+			 context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true.
 			 For example, the node "agent/<agent_id>/detail" will set
-			 context["request"]["wildcard"]["agent_id"] eqaul to the value 
+			 context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value 
 			 found during traversal.
 		*/
 		
 	const LLHTTPNode* traverse(const std::string& path, LLSD& context) const;
 		/**< find a node, if any, that can service this path
-			 set up context["request"] information 
+			 set up context[CONTEXT_REQUEST] information 
  		*/
  	//@}
  
@@ -287,7 +305,7 @@ class LLSimpleResponse : public LLHTTPNode::Response
 	
 	void result(const LLSD& result);
 	void extendedResult(S32 code, const std::string& body, const LLSD& headers);
-	
+	void extendedResult(S32 code, const LLSD& result, const LLSD& headers);
 	void status(S32 code, const std::string& message);
 
 	void print(std::ostream& out) const;
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index 1236fc8b71c917c30a37bfdd7d9f3274241172d7..293e74d0da869acd63a8446546a58ffe22d131f9 100755
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -33,6 +33,7 @@
 #include "llapr.h"
 #include "llbuffer.h"
 #include "llbufferstream.h"
+#include "llhttpconstants.h"
 #include "llhttpnode.h"
 #include "lliopipe.h"
 #include "lliosocket.h"
@@ -49,15 +50,6 @@
 #include <boost/tokenizer.hpp>
 
 static const char HTTP_VERSION_STR[] = "HTTP/1.0";
-const std::string CONTEXT_REQUEST("request");
-const std::string CONTEXT_RESPONSE("response");
-const std::string CONTEXT_VERB("verb");
-const std::string CONTEXT_HEADERS("headers");
-const std::string HTTP_VERB_GET("GET");
-const std::string HTTP_VERB_PUT("PUT");
-const std::string HTTP_VERB_POST("POST");
-const std::string HTTP_VERB_DELETE("DELETE");
-const std::string HTTP_VERB_OPTIONS("OPTIONS");
 
 static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;
 static void* sTimingCallbackData = NULL;
@@ -102,7 +94,7 @@ class LLHTTPPipe : public LLIOPipe
 		// from LLHTTPNode::Response
 		virtual void result(const LLSD&);
 		virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers);
-		
+		virtual void extendedResult(S32 code, const LLSD& body, const LLSD& headers);
 		virtual void status(S32 code, const std::string& message);
 
 		void nullPipe();
@@ -122,7 +114,8 @@ class LLHTTPPipe : public LLIOPipe
 		STATE_LOCKED,
 		STATE_GOOD_RESULT,
 		STATE_STATUS_RESULT,
-		STATE_EXTENDED_RESULT
+		STATE_EXTENDED_RESULT,
+		STATE_EXTENDED_LLSD_RESULT
 	};
 	State mState;
 
@@ -132,7 +125,7 @@ class LLHTTPPipe : public LLIOPipe
 	void lockChain(LLPumpIO*);
 	void unlockChain();
 
-	LLSD mGoodResult;
+	LLSD mResult;
 	S32 mStatusCode;
 	std::string mStatusMessage;	
 	LLSD mHeaders;
@@ -193,7 +186,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 			}
 			else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
 			{
-				std::stringstream strstrm;
+				std::ostringstream strstrm;
 				strstrm << istr.rdbuf();
 				input = strstrm.str();
 			}
@@ -209,7 +202,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 			}
 			else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
 			{
-				std::stringstream strstrm;
+				std::ostringstream strstrm;
 				strstrm << istr.rdbuf();
 				input = strstrm.str();
 			}
@@ -244,12 +237,12 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		// Log all HTTP transactions.
 		// TODO: Add a way to log these to their own file instead of indra.log
 		// It is just too spammy to be in indra.log.
-		lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
+		lldebugs << verb << " " << context[CONTEXT_REQUEST][CONTEXT_PATH].asString()
 			<< " " << mStatusCode << " " <<  mStatusMessage << " " << delta
 			<< "s" << llendl;
 
 		// Log Internal Server Errors
-		//if(mStatusCode == 500)
+		//if(mStatusCode == HTTP_INTERNAL_SERVER_ERROR)
 		//{
 		//	llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" 
 		//			<< llendl;
@@ -271,10 +264,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		case STATE_GOOD_RESULT:
 		{
 			LLSD headers = mHeaders;
-			headers["Content-Type"] = "application/llsd+xml";
+			headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;
 			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
 			LLBufferStream ostr(channels, buffer.get());
-			LLSDSerialize::toXML(mGoodResult, ostr);
+			LLSDSerialize::toXML(mResult, ostr);
 
 			return STATUS_DONE;
 		}
@@ -282,7 +275,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 		case STATE_STATUS_RESULT:
 		{
 			LLSD headers = mHeaders;
-			headers["Content-Type"] = "text/plain";
+			headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN;
 			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
 			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
 			context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
@@ -300,6 +293,17 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
 
 			return STATUS_DONE;
 		}
+		case STATE_EXTENDED_LLSD_RESULT:
+		{
+			LLSD headers = mHeaders;
+			headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;
+			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
+			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
+			LLBufferStream ostr(channels, buffer.get());
+			LLSDSerialize::toXML(mResult, ostr);
+
+			return STATUS_DONE;
+		}
 		default:
 			llwarns << "LLHTTPPipe::process_impl: unexpected state "
 				<< mState << llendl;
@@ -335,19 +339,35 @@ void LLHTTPPipe::Response::result(const LLSD& r)
 		return;
 	}
 
-	mPipe->mStatusCode = 200;
+	mPipe->mStatusCode = HTTP_OK;
 	mPipe->mStatusMessage = "OK";
-	mPipe->mGoodResult = r;
+	mPipe->mResult = r;
 	mPipe->mState = STATE_GOOD_RESULT;
 	mPipe->mHeaders = mHeaders;
-	mPipe->unlockChain();	
+	mPipe->unlockChain();
+}
+
+void LLHTTPPipe::Response::extendedResult(S32 code, const LLSD& r, const LLSD& headers)
+{
+	if(! mPipe)
+	{
+		llwarns << "LLHTTPPipe::Response::extendedResult: NULL pipe" << llendl;
+		return;
+	}
+
+	mPipe->mStatusCode = code;
+	mPipe->mStatusMessage = "(LLSD)";
+	mPipe->mResult = r;
+	mPipe->mHeaders = headers;
+	mPipe->mState = STATE_EXTENDED_LLSD_RESULT;
+	mPipe->unlockChain();
 }
 
 void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers)
 {
 	if(! mPipe)
 	{
-		llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
+		llwarns << "LLHTTPPipe::Response::extendedResult: NULL pipe" << llendl;
 		return;
 	}
 
@@ -454,9 +474,9 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
 		std::string message = context[CONTEXT_RESPONSE]["statusMessage"];
 		
 		int code = context[CONTEXT_RESPONSE]["statusCode"];
-		if (code < 200)
+		if (code < HTTP_OK)
 		{
-			code = 200;
+			code = HTTP_OK;
 			message = "OK";
 		}
 		
@@ -465,7 +485,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
 		S32 content_length = buffer->countAfter(channels.in(), NULL);
 		if(0 < content_length)
 		{
-			ostr << "Content-Length: " << content_length << "\r\n";
+			ostr << HTTP_OUT_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n";
 		}
 		// *NOTE: This guard can go away once the LLSD static map
 		// iterator is available. Phoenix. 2008-05-09
@@ -771,7 +791,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 					std::string name(buf, pos_colon - buf);
 					std::string value(pos_colon + 2);
 					LLStringUtil::toLower(name);
-					if("content-length" == name)
+					if(HTTP_IN_HEADER_CONTENT_LENGTH == name)
 					{
 						lldebugs << "Content-Length: " << value << llendl;
 						mContentLength = atoi(value.c_str());
@@ -846,12 +866,12 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
 			// HTTP headers.
 			LLPumpIO::chain_t chain;
 			chain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
-			context[CONTEXT_REQUEST]["path"] = mPath;
-			context[CONTEXT_REQUEST]["query-string"] = mQuery;
-			context[CONTEXT_REQUEST]["remote-host"]
-				= mBuildContext["remote-host"];
-			context[CONTEXT_REQUEST]["remote-port"]
-				= mBuildContext["remote-port"];
+			context[CONTEXT_REQUEST][CONTEXT_PATH] = mPath;
+			context[CONTEXT_REQUEST][CONTEXT_QUERY_STRING] = mQuery;
+			context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST]
+				= mBuildContext[CONTEXT_REMOTE_HOST];
+			context[CONTEXT_REQUEST][CONTEXT_REMOTE_PORT]
+				= mBuildContext[CONTEXT_REMOTE_PORT];
 			context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders;
 
 			const LLChainIOFactory* protocolHandler
diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h
index 5c1b0531ff2693de45fd6b15147523e27f7e725f..a23eafe58a2c53cd3e5bd9b94681b7acbee89a3a 100755
--- a/indra/llmessage/lliohttpserver.h
+++ b/indra/llmessage/lliohttpserver.h
@@ -33,18 +33,6 @@
 
 class LLPumpIO;
 
-// common strings use for populating the context. bascally 'request',
-// 'wildcard', and 'headers'.
-extern const std::string CONTEXT_REQUEST;
-extern const std::string CONTEXT_RESPONSE;
-extern const std::string CONTEXT_VERB;
-extern const std::string CONTEXT_HEADERS;
-extern const std::string HTTP_VERB_GET;
-extern const std::string HTTP_VERB_PUT;
-extern const std::string HTTP_VERB_POST;
-extern const std::string HTTP_VERB_DELETE;
-extern const std::string HTTP_VERB_OPTIONS;
-
 class LLIOHTTPServer
 {
 public:
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index 2043bae5e7c0b6c8d42d0d5e9f7d75826577e6be..a60b8400679c9ea92af09fb8c2ebc5945f1eb23f 100755
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -39,6 +39,9 @@
 // constants
 //
 
+const std::string CONTEXT_REMOTE_HOST("remote-host");
+const std::string CONTEXT_REMOTE_PORT("remote-port");
+
 static const S32 LL_DEFAULT_LISTEN_BACKLOG = 10;
 static const S32 LL_SEND_BUFFER_SIZE = 40000;
 static const S32 LL_RECV_BUFFER_SIZE = 40000;
@@ -619,8 +622,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 		apr_sockaddr_ip_get(&remote_host_string, remote_addr);
 
 		LLSD context;
-		context["remote-host"] = remote_host_string;
-		context["remote-port"] = remote_addr->port;
+		context[CONTEXT_REMOTE_HOST] = remote_host_string;
+		context[CONTEXT_REMOTE_PORT] = remote_addr->port;
 
 		LLPumpIO::chain_t chain;
 		chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket)));
diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h
index be0f7dfcc655e1e47ac2ccdf8f967037ac4458a8..08c21a1b97dfa4b78c8c2c01741415e4a2aba2e1 100755
--- a/indra/llmessage/lliosocket.h
+++ b/indra/llmessage/lliosocket.h
@@ -42,6 +42,9 @@
 #include "apr_network_io.h"
 #include "llchainio.h"
 
+extern const std::string CONTEXT_REMOTE_HOST;
+extern const std::string CONTEXT_REMOTE_PORT;
+
 class LLHost;
 
 /** 
diff --git a/indra/llmessage/llmime.cpp b/indra/llmessage/llmime.cpp
deleted file mode 100755
index 9d9c4ebd6899f8eb0c4292ae5b9d8bb3ad94f649..0000000000000000000000000000000000000000
--- a/indra/llmessage/llmime.cpp
+++ /dev/null
@@ -1,629 +0,0 @@
-/** 
- * @file llmime.cpp
- * @author Phoenix
- * @date 2006-12-20
- * @brief Implementation of mime tools.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llmime.h"
-
-#include <vector>
-
-#include "llmemorystream.h"
-
-/**
- * Useful constants.
- */
-// Headers specified in rfc-2045 will be canonicalized below.
-static const std::string CONTENT_LENGTH("Content-Length");
-static const std::string CONTENT_TYPE("Content-Type");
-static const S32 KNOWN_HEADER_COUNT = 6;
-static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] =
-{
-	CONTENT_LENGTH,
-	CONTENT_TYPE,
-	std::string("MIME-Version"),
-	std::string("Content-Transfer-Encoding"),
-	std::string("Content-ID"),
-	std::string("Content-Description"),
-};
-
-// parser helpers
-static const std::string MULTIPART("multipart");
-static const std::string BOUNDARY("boundary");
-static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t");
-static const std::string SEPARATOR_PREFIX("--");
-//static const std::string SEPARATOR_SUFFIX("\r\n");
-
-/*
-Content-Type: multipart/mixed; boundary="segment"
-Content-Length: 24832
-
---segment
-Content-Type: image/j2c
-Content-Length: 23715
-
-<data>
-
---segment
-Content-Type: text/xml; charset=UTF-8
-
-<meta data>
-EOF
-
-*/
-
-/**
- * LLMimeIndex
- */
-
-/** 
- * @class LLMimeIndex::Impl
- * @brief Implementation details of the mime index class.
- * @see LLMimeIndex
- */
-class LLMimeIndex::Impl
-{
-public:
-	Impl() : mOffset(-1), mUseCount(1)
-	{}
-	Impl(LLSD headers, S32 offset) :
-		mHeaders(headers), mOffset(offset), mUseCount(1)
-	{}
-public:
-	LLSD mHeaders;
-	S32 mOffset;
-	S32 mUseCount;
-
-	typedef std::vector<LLMimeIndex> sub_part_t;
-	sub_part_t mAttachments;
-};
-
-LLSD LLMimeIndex::headers() const
-{
-	return mImpl->mHeaders;
-}
-
-S32 LLMimeIndex::offset() const
-{
-	return mImpl->mOffset;
-}
-
-S32 LLMimeIndex::contentLength() const
-{
-	// Find the content length in the headers.
-	S32 length = -1;
-	LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH];
-	if(content_length.isDefined())
-	{
-		length = content_length.asInteger();
-	}
-	return length;
-}
-
-std::string LLMimeIndex::contentType() const
-{
-	std::string type;
-	LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
-	if(content_type.isDefined())
-	{
-		type = content_type.asString();
-	}
-	return type;
-}
-
-bool LLMimeIndex::isMultipart() const
-{
-	bool multipart = false;
-	LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
-	if(content_type.isDefined())
-	{
-		std::string type = content_type.asString();
-		int comp = type.compare(0, MULTIPART.size(), MULTIPART);
-		if(0 == comp)
-		{
-			multipart = true;
-		}
-	}
-	return multipart;
-}
-
-S32 LLMimeIndex::subPartCount() const
-{
-	return mImpl->mAttachments.size();
-}
-
-LLMimeIndex LLMimeIndex::subPart(S32 index) const
-{
-	LLMimeIndex part;
-	if((index >= 0) && (index < (S32)mImpl->mAttachments.size()))
-	{
-		part = mImpl->mAttachments[index];
-	}
-	return part;
-}
-
-LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl)
-{
-}
-
-LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) :
-	mImpl(new LLMimeIndex::Impl(headers, content_offset))
-{
-}
-
-LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) :
-	mImpl(mime.mImpl)
-{
-	++mImpl->mUseCount;
-}
-
-LLMimeIndex::~LLMimeIndex()
-{
-	if(0 == --mImpl->mUseCount)
-	{
-		delete mImpl;
-	}
-}
-
-LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime)
-{
-	// Increment use count first so that we handle self assignment
-	// automatically.
-	++mime.mImpl->mUseCount;
-	if(0 == --mImpl->mUseCount)
-	{
-		delete mImpl;
-	}
-	mImpl = mime.mImpl;
-	return *this;
-}
-
-bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part)
-{
-	// *FIX: Should we check for multi-part?
-	if(mImpl->mAttachments.size() < S32_MAX)
-	{
-		mImpl->mAttachments.push_back(sub_part);
-		return true;
-	}
-	return false;
-}
-
-/**
- * LLMimeParser
- */
-/** 
- * @class LLMimeParser::Impl
- * @brief Implementation details of the mime parser class.
- * @see LLMimeParser
- */
-class LLMimeParser::Impl
-{
-public:
-	// @brief Constructor.
-	Impl();
-
-	// @brief Reset this for a new parse.
-	void reset();
-
-	/** 
-	 * @brief Parse a mime entity to find the index information.
-	 *
-	 * This method will scan the istr until a single complete mime
-	 * entity is read, an EOF, or limit bytes have been scanned. The
-	 * istr will be modified by this parsing, so pass in a temporary
-	 * stream or rewind/reset the stream after this call.
-	 * @param istr An istream which contains a mime entity.
-	 * @param limit The maximum number of bytes to scan.
-	 * @param separator The multipart separator if it is known.
-	 * @param is_subpart Set true if parsing a multipart sub part.
-	 * @param index[out] The parsed output.
-	 * @return Returns true if an index was parsed and no errors occurred.
-	 */
-	bool parseIndex(
-		std::istream& istr,
-		S32 limit,
-		const std::string& separator,
-		bool is_subpart,
-		LLMimeIndex& index);
-
-protected:
-	/**
-	 * @brief parse the headers.
-	 *
-	 * At the end of a successful parse, mScanCount will be at the
-	 * start of the content.
-	 * @param istr The input stream.
-	 * @param limit maximum number of bytes to process
-	 * @param headers[out] A map of the headers found.
-	 * @return Returns true if the parse was successful.
-	 */
-	bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers);
-
-	/**
-	 * @brief Figure out the separator string from a content type header.
-	 * 
-	 * @param multipart_content_type The content type value from the headers.
-	 * @return Returns the separator string.
-	 */
-	std::string findSeparator(std::string multipart_content_type);
-
-	/**
-	 * @brief Scan through istr past the separator.
-	 *
-	 * @param istr The input stream.
-	 * @param limit Maximum number of bytes to scan.
-	 * @param separator The multipart separator.
-	 */
-	void scanPastSeparator(
-		std::istream& istr,
-		S32 limit,
-		const std::string& separator);
-
-	/**
-	 * @brief Scan through istr past the content of the current mime part.
-	 *
-	 * @param istr The input stream.
-	 * @param limit Maximum number of bytes to scan.
-	 * @param headers The headers for this mime part.
-	 * @param separator The multipart separator if known.
-	 */
-	void scanPastContent(
-		std::istream& istr,
-		S32 limit,
-		LLSD headers,
-		const std::string separator);
-
-	/**
-	 * @brief Eat CRLF.
-	 *
-	 * This method has no concept of the limit, so ensure you have at
-	 * least 2 characters left to eat before hitting the limit. This
-	 * method will increment mScanCount as it goes.
-	 * @param istr The input stream.
-	 * @return Returns true if CRLF was found and consumed off of istr.
-	 */
-	bool eatCRLF(std::istream& istr);
-
-	// @brief Returns true if parsing should continue.
-	bool continueParse() const { return (!mError && mContinue); }
-
-	// @brief anonymous enumeration for parse buffer size.
-	enum
-	{
-		LINE_BUFFER_LENGTH = 1024
-	};
-
-protected:
-	S32 mScanCount;
-	bool mContinue;
-	bool mError;
-	char mBuffer[LINE_BUFFER_LENGTH];
-};
-
-LLMimeParser::Impl::Impl()
-{
-	reset();
-}
-
-void LLMimeParser::Impl::reset()
-{
-	mScanCount = 0;
-	mContinue = true;
-	mError = false;
-	mBuffer[0] = '\0';
-}
-
-bool LLMimeParser::Impl::parseIndex(
-	std::istream& istr,
-	S32 limit,
-	const std::string& separator,
-	bool is_subpart,
-	LLMimeIndex& index)
-{
-	LLSD headers;
-	bool parsed_something = false;
-	if(parseHeaders(istr, limit, headers))
-	{
-		parsed_something = true;
-		LLMimeIndex mime(headers, mScanCount);
-		index = mime;
-		if(index.isMultipart())
-		{
-			// Figure out the separator, scan past it, and recurse.
-			std::string ct = headers[CONTENT_TYPE].asString();
-			std::string sep = findSeparator(ct);
-			scanPastSeparator(istr, limit, sep);
-			while(continueParse() && parseIndex(istr, limit, sep, true, mime))
-			{
-				index.attachSubPart(mime);
-			}
-		}
-		else
-		{
-			// Scan to the end of content.
-			scanPastContent(istr, limit, headers, separator);
-			if(is_subpart)
-			{
-				scanPastSeparator(istr, limit, separator);
-			}
-		}
-	}
-	if(mError) return false;
-	return parsed_something;
-}
-
-bool LLMimeParser::Impl::parseHeaders(
-	std::istream& istr,
-	S32 limit,
-	LLSD& headers)
-{
-	while(continueParse())
-	{
-		// Get the next line.
-		// We subtract 1 from the limit so that we make sure
-		// not to read past limit when we get() the newline.
-		S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
-		istr.getline(mBuffer, max_get, '\r');
-		mScanCount += (S32)istr.gcount();
-		int c = istr.get();
-		if(EOF == c)
-		{
-			mContinue = false;
-			return false;
-		}
-		++mScanCount;
-		if(c != '\n')
-		{
-			mError = true;
-			return false;
-		}
-		if(mScanCount >= limit)
-		{
-			mContinue = false;
-		}
-
-		// Check if that's the end of headers.
-		if('\0' == mBuffer[0])
-		{
-			break;
-		}
-
-		// Split out the name and value.
-		// *NOTE: The use of strchr() here is safe since mBuffer is
-		// guaranteed to be NULL terminated from the call to getline()
-		// above.
-		char* colon = strchr(mBuffer, ':');
-		if(!colon)
-		{
-			mError = true;
-			return false;
-		}
-
-		// Cononicalize the name part, and store the name: value in
-		// the headers structure. We do this by iterating through
-		// 'known' headers and replacing the value found with the
-		// correct one.
-		// *NOTE: Not so efficient, but iterating through a small
-		// subset should not be too much of an issue.
-		std::string name(mBuffer, colon++ - mBuffer);
-		while(isspace(*colon)) ++colon;
-		std::string value(colon);
-		for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii)
-		{
-			if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii]))
-			{
-				name = KNOWN_HEADER[ii];
-				break;
-			}
-		}
-		headers[name] = value;
-	}
-	if(headers.isUndefined()) return false;
-	return true;
-}
-
-std::string LLMimeParser::Impl::findSeparator(std::string header)
-{
-	//                               01234567890
-	//Content-Type: multipart/mixed; boundary="segment"
-	std::string separator;
-	std::string::size_type pos = header.find(BOUNDARY);
-	if(std::string::npos == pos) return separator;
-	pos += BOUNDARY.size() + 1;
-	std::string::size_type end;
-	if(header[pos] == '"')
-	{
-		// the boundary is quoted, find the end from pos, and take the
-		// substring.
-		end = header.find('"', ++pos);
-		if(std::string::npos == end)
-		{
-			// poorly formed boundary.
-			mError = true;
-		}
-	}
-	else
-	{
-		// otherwise, it's every character until a whitespace, end of
-		// line, or another parameter begins.
-		end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos);
-		if(std::string::npos == end)
-		{
-			// it goes to the end of the string.
-			end = header.size();
-		}
-	}
-	if(!mError) separator = header.substr(pos, end - pos);
-	return separator;
-}
-
-void LLMimeParser::Impl::scanPastSeparator(
-	std::istream& istr,
-	S32 limit,
-	const std::string& sep)
-{
-	std::ostringstream ostr;
-	ostr << SEPARATOR_PREFIX << sep;
-	std::string separator = ostr.str();
-	bool found_separator = false;
-	while(!found_separator && continueParse())
-	{
-		// Subtract 1 from the limit so that we make sure not to read
-		// past limit when we get() the newline.
-		S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
-		istr.getline(mBuffer, max_get, '\r');
-		mScanCount += (S32)istr.gcount();
-		if(istr.gcount() >= LINE_BUFFER_LENGTH - 1)
-		{
-			// that's way too long to be a separator, so ignore it.
-			continue;
-		}
-		int c = istr.get();
-		if(EOF == c)
-		{
-			mContinue = false;
-			return;
-		}
-		++mScanCount;
-		if(c != '\n')
-		{
-			mError = true;
-			return;
-		}
-		if(mScanCount >= limit)
-		{
-			mContinue = false;
-		}
-		if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator))
-		{
-			found_separator = true;
-		}
-	}
-}
-
-void LLMimeParser::Impl::scanPastContent(
-	std::istream& istr,
-	S32 limit,
-	LLSD headers,
-	const std::string separator)
-{
-	if(headers.has(CONTENT_LENGTH))
-	{
-		S32 content_length = headers[CONTENT_LENGTH].asInteger();
-		// Subtract 2 here for the \r\n after the content.
-		S32 max_skip = llmin(content_length, limit - mScanCount - 2);
-		istr.ignore(max_skip);
-		mScanCount += max_skip;
-
-		// *NOTE: Check for hitting the limit and eof here before
-		// checking for the trailing EOF, because our mime parser has
-		// to gracefully handle incomplete mime entites.
-		if((mScanCount >= limit) || istr.eof())
-		{
-			mContinue = false;
-		}
-		else if(!eatCRLF(istr))
-		{
-			mError = true;
-			return;
-		}
-	}
-}
-
-bool LLMimeParser::Impl::eatCRLF(std::istream& istr)
-{
-	int c = istr.get();
-	++mScanCount;
-	if(c != '\r')
-	{
-		return false;
-	}
-	c = istr.get();
-	++mScanCount;
-	if(c != '\n')
-	{
-		return false;
-	}
-	return true;
-}
-	
-
-LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl)
-{
-}
-
-LLMimeParser::~LLMimeParser()
-{
-	delete & mImpl;
-}
-
-void LLMimeParser::reset()
-{
-	mImpl.reset();
-}
-
-bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index)
-{
-	std::string separator;
-	return mImpl.parseIndex(istr, S32_MAX, separator, false, index);
-}
-
-bool LLMimeParser::parseIndex(
-	const std::vector<U8>& buffer,
-	LLMimeIndex& index)
-{
-	LLMemoryStream mstr(&buffer[0], buffer.size());
-	return parseIndex(mstr, buffer.size() + 1, index);
-}
-
-bool LLMimeParser::parseIndex(
-	std::istream& istr,
-	S32 limit,
-	LLMimeIndex& index)
-{
-	std::string separator;
-	return mImpl.parseIndex(istr, limit, separator, false, index);
-}
-
-bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index)
-{
-	LLMemoryStream mstr(buffer, length);
-	return parseIndex(mstr, length + 1, index);
-}
-
-/*
-bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const
-{
-	return false;
-}
-
-bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const
-{
-	LLMemoryStream mstr(buffer, length);
-	return verify(mstr, index);
-}
-*/
diff --git a/indra/llmessage/llmime.h b/indra/llmessage/llmime.h
deleted file mode 100755
index e6617fb503b6e01d8e038cd93ddadc193b65a1e7..0000000000000000000000000000000000000000
--- a/indra/llmessage/llmime.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/** 
- * @file llmime.h
- * @author Phoenix
- * @date 2006-12-20
- * @brief Declaration of mime tools.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLMIME_H
-#define LL_LLMIME_H
-
-#include <string>
-#include "llsd.h"
-
-/**
- * This file declares various tools for parsing and creating MIME
- * objects as described in RFCs 2045, 2046, 2047, 2048, and 2049.
- */
-
-/** 
- * @class LLMimeIndex
- * @brief Skeletal information useful for handling mime packages.
- * @see LLMimeParser
- *
- * An instance of this class is the parsed output from a LLMimeParser
- * which then allows for easy access into a data stream to find and
- * get what you want out of it.
- *
- * This class meant as a tool to quickly find what you seek in a
- * parsed mime entity. As such, it does not have useful support for
- * modification of a mime entity and specializes the interface toward
- * querying data from a fixed mime entity. Modifying an instance of
- * LLMimeIndx does not alter a mime entity and changes to a mime
- * entity itself are not propogated into an instance of a LLMimeIndex.
- *
- * Usage:<br>
- *  LLMimeIndex mime_index;<br>
- *  std::ifstream fstr("package.mime", ios::binary);<br>
- *  LLMimeParser parser;<br>
- *  if(parser.parseIndex(fstr, mime_index))<br>
- *  {<br>
- *    std::vector<U8> content;<br>
- *    content.resize(mime_index.contentLength());<br>
- *    fstr.seekg(mime_index.offset(), ios::beg);<br>
- *    // ...do work on fstr and content<br>
- *  }<br>
- */
-class LLMimeIndex
-{
-public:
-	/* @name Client interface.
-	 */
-	//@{
-	/** 
-	 * @brief Get the full parsed headers for this.
-	 *
-	 * If there are any headers, it will be a map of header name to
-	 * the value found on the line. The name is everything before the
-	 * colon, and the value is the string found after the colon to the
-	 * end of the line after trimming leading whitespace. So, for
-	 * example:
-	 * Content-Type:  text/plain
-	 * would become an entry in the headers of:
-	 * headers["Content-Type"] == "text/plain"
-	 *
-	 * If this instance of an index was generated by the
-	 * LLMimeParser::parseIndex() call, all header names in rfc2045
-	 * will be capitalized as in rfc, eg Content-Length and
-	 * MIME-Version, not content-length and mime-version.
-	 * @return Returns an LLSD map of header name to value. Returns
-	 * undef if there are no headers.
-	 */
-	LLSD headers() const;
-
-	/** 
-	 * @brief Get the content offset.
-	 *
-	 * @return Returns the number of bytes to the start of the data
-	 * segment from the start of serialized mime entity. Returns -1 if
-	 * offset is not known.
-	 */
-	S32 offset() const;
-
-	/** 
-	 * @brief Get the length of the data segment for this mime part.
-	 *
-	 * @return Returns the content length in bytes. Returns -1 if
-	 * length is not known.
-	 */
-	S32 contentLength() const;
-
-	/** 
-	 * @brief Get the mime type associated with this node.
-	 *
-	 * @return Returns the mimetype.
-	 */
-	std::string contentType() const;
-
-	/** 
-	 * @brief Helper method which simplifies parsing the return from type()
-	 *
-	 * @return Returns true if this is a multipart mime, and therefore
-	 * getting subparts will succeed.
-	 */
-	bool isMultipart() const;
-
-	/** 
-	 * @brief Get the number of atachments.
-	 *
-	 * @return Returns the number of sub-parts for this.
-	 */
-	S32 subPartCount() const;
-
-	/** 
-	 * @brief Get the indicated attachment.
-	 *
-	 * @param index Value from 0 to (subPartCount() - 1).
-	 * @return Returns the indicated sub-part, or an invalid mime
-	 * index on failure.
-	 */
-	LLMimeIndex subPart(S32 index) const;
-	//@}
-
-	/* @name Interface for building, testing, and helpers for typical use.
-	 */
-	//@{
-	/**
-	 * @brief Default constructor - creates a useless LLMimeIndex.
-	 */
-	LLMimeIndex();
-
-	/**
-	 * @brief Full constructor.
-	 *
-	 * @param headers The complete headers.
-	 * @param content_offset The number of bytes to the start of the
-	 * data segment of this mime entity from the start of the stream
-	 * or buffer.
-	 */
-	LLMimeIndex(LLSD headers, S32 content_offset);
-
-	/**
-	 * @brief Copy constructor.
-	 *
-	 * @param mime The other mime object.
-	 */
-	LLMimeIndex(const LLMimeIndex& mime);
-
-	// @brief Destructor.
-	~LLMimeIndex();
-
-	/*
-	 * @breif Assignment operator.
-	 *
-	 * @param mime The other mime object.
-	 * @return Returns this after assignment.
-	 */
-	LLMimeIndex& operator=(const LLMimeIndex& mime);
-
-	/** 
-	 * @brief Add attachment information as a sub-part to a multipart mime.
-	 *
-	 * @param sub_part the part to attach.
-	 * @return Returns true on success, false on failure.
-	 */
-	bool attachSubPart(LLMimeIndex sub_part);
-	//@}
-
-protected:
-	// Implementation.
-	class Impl;
-	Impl* mImpl;
-};
-
-
-/** 
- * @class LLMimeParser
- * @brief This class implements a MIME parser and verifier.
- *
- * THOROUGH_DESCRIPTION
- */
-class LLMimeParser
-{
-public:
-	// @brief Make a new mime parser.
-	LLMimeParser();
-	
-	// @brief Mime parser Destructor.
-	~LLMimeParser();
-
-	// @brief Reset internal state of this parser.
-	void reset();
-
-	
-	/* @name Index generation interface.
-	 */
-	//@{
-	/** 
-	 * @brief Parse a stream to find the mime index information.
-	 *
-	 * This method will scan the istr until a single complete mime
-	 * entity is read or EOF. The istr will be modified by this
-	 * parsing, so pass in a temporary stream or rewind/reset the
-	 * stream after this call.
-	 * @param istr An istream which contains a mime entity.
-	 * @param index[out] The parsed output.
-	 * @return Returns true if an index was parsed and no errors occurred.
-	 */
-	bool parseIndex(std::istream& istr, LLMimeIndex& index);
-
-	/** 
-	 * @brief Parse a vector to find the mime index information.
-	 *
-	 * @param buffer A vector with data to parse.
-	 * @param index[out] The parsed output.
-	 * @return Returns true if an index was parsed and no errors occurred.
-	 */
-	bool parseIndex(const std::vector<U8>& buffer, LLMimeIndex& index);
-
-	/** 
-	 * @brief Parse a stream to find the mime index information.
-	 *
-	 * This method will scan the istr until a single complete mime
-	 * entity is read, an EOF, or limit bytes have been scanned. The
-	 * istr will be modified by this parsing, so pass in a temporary
-	 * stream or rewind/reset the stream after this call.
-	 * @param istr An istream which contains a mime entity.
-	 * @param limit The maximum number of bytes to scan.
-	 * @param index[out] The parsed output.
-	 * @return Returns true if an index was parsed and no errors occurred.
-	 */
-	bool parseIndex(std::istream& istr, S32 limit, LLMimeIndex& index);
-
-	/** 
-	 * @brief Parse a memory bufffer to find the mime index information.
-	 *
-	 * @param buffer The start of the buffer to parse.
-	 * @param buffer_length The length of the buffer.
-	 * @param index[out] The parsed output.
-	 * @return Returns true if an index was parsed and no errors occurred.
-	 */
-	bool parseIndex(const U8* buffer, S32 buffer_length, LLMimeIndex& index);
-	//@}
-
-	/** 
-	 * @brief 
-	 *
-	 * @return
-	 */
-	//bool verify(std::istream& istr, LLMimeIndex& index) const;
-
-	/** 
-	 * @brief 
-	 *
-	 * @return
-	 */
-	//bool verify(U8* buffer, S32 buffer_length, LLMimeIndex& index) const;
-
-protected:
-	// Implementation.
-	class Impl;
-	Impl& mImpl;
-
-private:
-	// @brief Not implemneted to prevent copy consturction.
-	LLMimeParser(const LLMimeParser& parser);
-
-	// @brief Not implemneted to prevent assignment.
-	LLMimeParser& operator=(const LLMimeParser& mime);
-};
-
-#endif // LL_LLMIME_H
diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp
deleted file mode 100755
index 932cbf375e3ec2a5e45d664a79f0810a642cc8bb..0000000000000000000000000000000000000000
--- a/indra/llmessage/llregionpresenceverifier.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/** 
- * @file llregionpresenceverifier.cpp
- * @brief 
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llregionpresenceverifier.h"
-#include "llhttpclientinterface.h"
-#include <sstream>
-#include "net.h"
-#include "message.h"
-
-namespace boost
-{
-	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p)
-	{
-		++p->mReferenceCount;
-	}
-	
-	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p)
-	{
-		if(p && 0 == --p->mReferenceCount)
-		{
-			delete p;
-		}
-	}
-};
-
-LLRegionPresenceVerifier::Response::~Response()
-{
-}
-
-LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string&
-														   uri,
-														   ResponsePtr data,
-														   S32 retry_count) :
-	mUri(uri),
-	mSharedData(data),
-	mRetryCount(retry_count)
-{
-}
-
-//virtual
-LLRegionPresenceVerifier::RegionResponder::~RegionResponder()
-{
-}
-
-void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content)
-{
-	std::string host = content["private_host"].asString();
-	U32 port = content["private_port"].asInteger();
-	LLHost destination(host, port);
-	LLUUID id = content["region_id"];
-
-	lldebugs << "Verifying " << destination.getString() << " is region " << id << llendl;
-
-	std::stringstream uri;
-	uri << "http://" << destination.getString() << "/state/basic/";
-	mSharedData->getHttpClient().get(
-		uri.str(),
-		new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount));
-}
-
-void LLRegionPresenceVerifier::RegionResponder::error(U32 status,
-													 const std::string& reason)
-{
-	// TODO: babbage: distinguish between region presence service and
-	// region verification errors?
-	mSharedData->onRegionVerificationFailed();
-}
-
-LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content,
-	S32 retry_count):
-	mUri(uri),
-	mSharedData(data),
-	mContent(content),
-	mRetryCount(retry_count) 
-{
-}
-
-//virtual
-LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder()
-{
-}
-
-void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content)
-{
-	LLUUID actual_region_id = content["region_id"];
-	LLUUID expected_region_id = mContent["region_id"];
-
-	lldebugs << "Actual region: " << content << llendl;
-	lldebugs << "Expected region: " << mContent << llendl;
-
-	if (mSharedData->checkValidity(content) &&
-		(actual_region_id == expected_region_id))
-	{
-		mSharedData->onRegionVerified(mContent);
-	}
-	else if (mRetryCount > 0)
-	{
-		retry();
-	}
-	else
-	{
-		llwarns << "Simulator verification failed. Region: " << mUri << llendl;
-		mSharedData->onRegionVerificationFailed();
-	}
-}
-
-void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry()
-{
-	LLSD headers;
-	headers["Cache-Control"] = "no-cache, max-age=0";
-	llinfos << "Requesting region information, get uncached for region "
-			<< mUri << llendl;
-	--mRetryCount;
-	mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers);
-}
-
-void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason)
-{
-	if(mRetryCount > 0)
-	{
-		retry();
-	}
-	else
-	{
-		llwarns << "Failed to contact simulator for verification. Region: " << mUri << llendl;
-		mSharedData->onRegionVerificationFailed();
-	}
-}
diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h
deleted file mode 100755
index 5e8251e519bc7b1a7b86adc2f592513935fbb0a8..0000000000000000000000000000000000000000
--- a/indra/llmessage/llregionpresenceverifier.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/** 
- * @file llregionpresenceverifier.cpp
- * @brief 
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-/* Macro Definitions */
-#ifndef LL_LLREGIONPRESENCEVERIFIER_H
-#define LL_LLREGIONPRESENCEVERIFIER_H
-
-#include "llhttpclient.h"
-#include <string>
-#include "llsd.h"
-#include <boost/intrusive_ptr.hpp>
-
-class LLHTTPClientInterface;
-
-class LLRegionPresenceVerifier
-{
-public:
-	class Response
-	{
-	public:
-		virtual ~Response() = 0;
-
-		virtual bool checkValidity(const LLSD& content) const = 0;
-		virtual void onRegionVerified(const LLSD& region_details) = 0;
-		virtual void onRegionVerificationFailed() = 0;
-
-		virtual LLHTTPClientInterface& getHttpClient() = 0;
-
-	public: /* but not really -- don't touch this */
-		U32 mReferenceCount;		
-	};
-
-	typedef boost::intrusive_ptr<Response> ResponsePtr;
-
-	class RegionResponder : public LLHTTPClient::Responder
-	{
-	public:
-		RegionResponder(const std::string& uri, ResponsePtr data,
-						S32 retry_count);
-		virtual ~RegionResponder(); 
-		virtual void result(const LLSD& content);
-		virtual void error(U32 status, const std::string& reason);
-
-	private:
-		ResponsePtr mSharedData;
-		std::string mUri;
-		S32 mRetryCount;
-	};
-
-	class VerifiedDestinationResponder : public LLHTTPClient::Responder
-	{
-	public:
-		VerifiedDestinationResponder(const std::string& uri, ResponsePtr data,
-									 const LLSD& content, S32 retry_count);
-		virtual ~VerifiedDestinationResponder();
-		virtual void result(const LLSD& content);
-		
-		virtual void error(U32 status, const std::string& reason);
-		
-	private:
-		void retry();
-		ResponsePtr mSharedData;
-		LLSD mContent;
-		std::string mUri;
-		S32 mRetryCount;
-	};
-};
-
-namespace boost
-{
-	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p);
-	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p);
-};
-
-#endif //LL_LLREGIONPRESENCEVERIFIER_H
diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp
index 8bab91b0c0c5009de96be465e744d8d5e91cd2b8..c593027802e2f67004d159d7c5036efa42068d9b 100755
--- a/indra/llmessage/llsdappservices.cpp
+++ b/indra/llmessage/llsdappservices.cpp
@@ -121,7 +121,7 @@ class LLHTTPConfigRuntimeSingleService : public LLHTTPNode
 	{
 		//llinfos << "validate: " << name << ", "
 		//	<< LLSDOStreamer<LLSDNotationFormatter>(context) << llendl;
-		if((std::string("PUT") == context["request"]["verb"].asString()) && !name.empty())
+		if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty())
 		{
 			return true;
 		}
@@ -139,7 +139,7 @@ class LLHTTPConfigRuntimeSingleService : public LLHTTPNode
 		LLHTTPNode::ResponsePtr response,
 		const LLSD& context) const
 	{
-		std::string name = context["request"]["wildcard"]["option-name"];
+		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
 		LLSD options = LLApp::instance()->getOptionData(
 			LLApp::PRIORITY_RUNTIME_OVERRIDE);
 		response->result(options[name]);
@@ -150,7 +150,7 @@ class LLHTTPConfigRuntimeSingleService : public LLHTTPNode
 		const LLSD& context,
 		const LLSD& input) const
 	{
-		std::string name = context["request"]["wildcard"]["option-name"];
+		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
 		LLSD options = LLApp::instance()->getOptionData(
 			LLApp::PRIORITY_RUNTIME_OVERRIDE);
 		options[name] = input;
@@ -164,7 +164,7 @@ class LLHTTPConfigRuntimeSingleService : public LLHTTPNode
 		LLHTTPNode::ResponsePtr response,
 		const LLSD& context) const
 	{
-		std::string name = context["request"]["wildcard"]["option-name"];
+		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
 		LLSD options = LLApp::instance()->getOptionData(
 			LLApp::PRIORITY_RUNTIME_OVERRIDE);
 		options.erase(name);
@@ -268,7 +268,7 @@ class LLHTTPLiveConfigSingleService : public LLHTTPNode
 		LLHTTPNode::ResponsePtr response,
 		const LLSD& context) const
 	{
-		std::string name = context["request"]["wildcard"]["option-name"];
+		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];
 		response->result(LLApp::instance()->getOption(name));
 	}
 };
diff --git a/indra/llmessage/llsdhttpserver.cpp b/indra/llmessage/llsdhttpserver.cpp
index 5c8fc7b2bb4e23608e9b09745a35cd709a23c9b4..8ac6b3cb12dcc2adc1a6e1d579b99623947e0f48 100755
--- a/indra/llmessage/llsdhttpserver.cpp
+++ b/indra/llmessage/llsdhttpserver.cpp
@@ -109,7 +109,7 @@ class LLAPIService : public LLHTTPNode
 
     virtual void get(ResponsePtr response, const LLSD& context) const
 	{
-		const LLSD& remainder = context["request"]["remainder"];
+		const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];
 		
 		if (remainder.size() > 0)
 		{
diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp
index 1c93c12d990a35ca97e9ae2d4b97db73f0c0ba4d..376f69ea36bbdc36394bb19b6a67c4186b09d7ae 100755
--- a/indra/llmessage/llsdmessage.cpp
+++ b/indra/llmessage/llsdmessage.cpp
@@ -92,14 +92,14 @@ bool LLSDMessage::httpListener(const LLSD& request)
     return false;
 }
 
-void LLSDMessage::EventResponder::result(const LLSD& data)
+void LLSDMessage::EventResponder::httpSuccess()
 {
     // If our caller passed an empty replyPump name, they're not
     // listening: this is a fire-and-forget message. Don't bother posting
     // to the pump whose name is "".
     if (! mReplyPump.empty())
     {
-        LLSD response(data);
+        LLSD response(getContent());
         mReqID.stamp(response);
         mPumps.obtain(mReplyPump).post(response);
     }
@@ -111,7 +111,7 @@ void LLSDMessage::EventResponder::result(const LLSD& data)
     }
 }
 
-void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLSDMessage::EventResponder::httpFailure()
 {
     // If our caller passed an empty errorPump name, they're not
     // listening: "default error handling is acceptable." Only post to an
@@ -121,19 +121,16 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string
         LLSD info(mReqID.makeResponse());
         info["target"]  = mTarget;
         info["message"] = mMessage;
-        info["status"]  = LLSD::Integer(status);
-        info["reason"]  = reason;
-        info["content"] = content;
+        info["status"]  = getStatus();
+        info["reason"]  = getReason();
+        info["content"] = getContent();
         mPumps.obtain(mErrorPump).post(info);
     }
     else                        // default error handling
     {
-        // convention seems to be to use llinfos, but that seems a bit casual?
         LL_WARNS("LLSDMessage::EventResponder")
             << "'" << mMessage << "' to '" << mTarget
-            << "' failed with code " << status << ": " << reason << '\n'
-            << ll_pretty_print_sd(content)
-            << LL_ENDL;
+            << "' failed " << dumpResponse() << LL_ENDL;
     }
 }
 
@@ -151,11 +148,11 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)
 {
     if (success)
     {
-        mResponder->result(payload);
+        mResponder->successResult(payload);
     }
     else
     {
-        mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
+        mResponder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"]);
     }
 
     /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/
diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h
index 0d34847ff2d75108784659dfcf364620aec04f87..e5d532d6a42c100823a36bd36d617e9e01f894f0 100755
--- a/indra/llmessage/llsdmessage.h
+++ b/indra/llmessage/llsdmessage.h
@@ -123,6 +123,7 @@ class LLSDMessage
     /// LLCapabilityListener. Others should use higher-level APIs.
     class EventResponder: public LLHTTPClient::Responder
     {
+        LOG_CLASS(EventResponder);
     public:
         /**
          * LLHTTPClient::Responder that dispatches via named LLEventPump instances.
@@ -149,8 +150,9 @@ class LLSDMessage
             mErrorPump(errorPump)
         {}
     
-        virtual void result(const LLSD& data);
-        virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+    protected:
+        virtual void httpSuccess();
+        virtual void httpFailure();
     
     private:
         LLEventPumps& mPumps;
diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h
index 0cecf4f68891cde2273abb9ddb5d22f440182cfe..dfd3b7e1d0b65bd2d3efb08a67d42decadb3ac80 100755
--- a/indra/llmessage/llsdrpcclient.h
+++ b/indra/llmessage/llsdrpcclient.h
@@ -240,7 +240,7 @@ class LLSDRPCClientFactory : public LLChainIOFactory
 	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
 	{
 		lldebugs << "LLSDRPCClientFactory::build" << llendl;
-		LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST));
+		LLURLRequest* http(new LLURLRequest(HTTP_POST));
 		if(!http->isValid())
 		{
 			llwarns << "Creating LLURLRequest failed." << llendl ;
@@ -251,7 +251,7 @@ class LLSDRPCClientFactory : public LLChainIOFactory
 		LLIOPipe::ptr_t service(new Client);
 		chain.push_back(service);		
 		LLIOPipe::ptr_t http_pipe(http);
-		http->addHeader("Content-Type: text/llsd");
+		http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD);
 		if(mURL.empty())
 		{
 			chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
@@ -291,7 +291,7 @@ class LLXMLSDRPCClientFactory : public LLChainIOFactory
 	{
 		lldebugs << "LLXMLSDRPCClientFactory::build" << llendl;
 
-		LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST));
+		LLURLRequest* http(new LLURLRequest(HTTP_POST));
 		if(!http->isValid())
 		{
 			llwarns << "Creating LLURLRequest failed." << llendl ;
@@ -301,7 +301,7 @@ class LLXMLSDRPCClientFactory : public LLChainIOFactory
 		LLIOPipe::ptr_t service(new Client);
 		chain.push_back(service);		
 		LLIOPipe::ptr_t http_pipe(http);
-		http->addHeader("Content-Type: text/xml");
+		http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
 		if(mURL.empty())
 		{
 			chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp
index fea7fc72c4903a5ff693f18f43ae7c0e84c848c6..a67ba35879d3b558dc0b4ea09cb76656461d943f 100755
--- a/indra/llmessage/lltrustedmessageservice.cpp
+++ b/indra/llmessage/lltrustedmessageservice.cpp
@@ -42,9 +42,9 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response,
 								   const LLSD& context,
 								   const LLSD& input) const
 {
-	std::string name = context["request"]["wildcard"]["message-name"];
-	std::string senderIP = context["request"]["remote-host"];
-	std::string senderPort = context["request"]["headers"]
+	std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"];
+	std::string senderIP = context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST];
+	std::string senderPort = context[CONTEXT_REQUEST][CONTEXT_HEADERS]
 		["x-secondlife-udp-listen-port"];
 
 	LLSD message_data;
@@ -64,7 +64,7 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response,
 		LL_WARNS("Messaging") << "trusted message POST to /trusted-message/" 
 				<< name << " from unknown or untrusted sender "
 				<< sender << llendl;
-		response->status(403, "Unknown or untrusted sender");
+		response->status(HTTP_FORBIDDEN, "Unknown or untrusted sender");
 	}
 	else
 	{
diff --git a/indra/llmessage/lltrustedmessageservice.h b/indra/llmessage/lltrustedmessageservice.h
index 688937ac2c242538d36bea2b39145f02b5ec38eb..12a37bb535254425e59a10c05c4391dda2d627ab 100755
--- a/indra/llmessage/lltrustedmessageservice.h
+++ b/indra/llmessage/lltrustedmessageservice.h
@@ -30,6 +30,10 @@
 #include "linden_common.h"
 #include "llhttpnode.h"
 
+// These are defined in lliosocket.h/lliosocket.cpp  
+extern const std::string CONTEXT_REMOTE_HOST;
+extern const std::string CONTEXT_REMOTE_PORT;
+
 class LLSD;
 
 class LLTrustedMessageService
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 627d5918392f94b9d307890d6e225d57dbbbab00..cadff49cb8d1cbef5589a110a9eb29935825e1fc 100755
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -40,7 +40,6 @@
 #include "llstring.h"
 #include "apr_env.h"
 #include "llapr.h"
-static const U32 HTTP_STATUS_PIPE_ERROR = 499;
 
 /**
  * String constants
@@ -48,11 +47,12 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
 const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
 const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
 
+// These are defined in llhttpnode.h/llhttpnode.cpp
+extern const std::string CONTEXT_REQUEST;
+extern const std::string CONTEXT_RESPONSE;
 
 static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
 
-
-
 /**
  * class LLURLRequestDetail
  */
@@ -130,34 +130,15 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
  * class LLURLRequest
  */
 
-// static
-std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
-{
-	static const std::string VERBS[] =
-	{
-		"(invalid)",
-		"HEAD",
-		"GET",
-		"PUT",
-		"POST",
-		"DELETE",
-		"MOVE"
-	};
-	if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT))
-	{
-		return VERBS[0];
-	}
-	return VERBS[action];
-}
 
-LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
+LLURLRequest::LLURLRequest(EHTTPMethod action) :
 	mAction(action)
 {
 	initialize();
 }
 
 LLURLRequest::LLURLRequest(
-	LLURLRequest::ERequestAction action,
+	EHTTPMethod action,
 	const std::string& url) :
 	mAction(action)
 {
@@ -180,12 +161,17 @@ void LLURLRequest::setURL(const std::string& url)
 	}
 }
 
-std::string LLURLRequest::getURL() const
+const std::string& LLURLRequest::getURL() const
 {
 	return mDetail->mURL;
 }
 
-void LLURLRequest::addHeader(const char* header)
+void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */)
+{
+	mDetail->mCurlRequest->slist_append(header, value);
+}
+
+void LLURLRequest::addHeaderRaw(const char* header)
 {
 	mDetail->mCurlRequest->slist_append(header);
 }
@@ -272,7 +258,7 @@ LLIOPipe::EStatus LLURLRequest::handleError(
 		LLURLRequestComplete* complete = NULL;
 		complete = (LLURLRequestComplete*)mCompletionCallback.get();
 		complete->httpStatus(
-			HTTP_STATUS_PIPE_ERROR,
+			HTTP_INTERNAL_ERROR,
 			LLIOPipe::lookupStatusString(status));
 		complete->responseStatus(status);
 		pump->respond(complete);
@@ -494,21 +480,32 @@ bool LLURLRequest::configure()
 	case HTTP_PUT:
 		// Disable the expect http 1.1 extension. POST and PUT default
 		// to turning this on, and I am not too sure what it means.
-		addHeader("Expect:");
+		addHeader(HTTP_OUT_HEADER_EXPECT);
+
+		mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
+		mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
+		rv = true;
+		break;
+
+	case HTTP_PATCH:
+		// Disable the expect http 1.1 extension. POST and PUT default
+		// to turning this on, and I am not too sure what it means.
+		addHeader(HTTP_OUT_HEADER_EXPECT);
 
 		mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
 		mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
+		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH");
 		rv = true;
 		break;
 
 	case HTTP_POST:
 		// Disable the expect http 1.1 extension. POST and PUT default
 		// to turning this on, and I am not too sure what it means.
-		addHeader("Expect:");
+		addHeader(HTTP_OUT_HEADER_EXPECT);
 
 		// Disable the content type http header.
 		// *FIX: what should it be?
-		addHeader("Content-Type:");
+		addHeader(HTTP_OUT_HEADER_CONTENT_TYPE);
 
 		// Set the handle for an http post
 		mDetail->mCurlRequest->setPost(NULL, bytes);
@@ -638,7 +635,7 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
 		S32 status_code = atoi(status.c_str());
 		if (status_code > 0)
 		{
-			complete->httpStatus((U32)status_code, reason);
+			complete->httpStatus(status_code, reason);
 			return header_len;
 		}
 	}
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
index 44d358d906f44485af8a193cdc2b092e305c429e..f3d32f541981f5e3555e663674e0ca5170b47212 100755
--- a/indra/llmessage/llurlrequest.h
+++ b/indra/llmessage/llurlrequest.h
@@ -42,9 +42,10 @@
 #include "llcurl.h"
 
 
-extern const std::string CONTEXT_REQUEST;
+/**
+ * External constants
+ */
 extern const std::string CONTEXT_DEST_URI_SD_LABEL;
-extern const std::string CONTEXT_RESPONSE;
 extern const std::string CONTEXT_TRANSFERED_BYTES;
 
 class LLURLRequestDetail;
@@ -68,42 +69,22 @@ class LLURLRequest : public LLIOPipe
 {
 	LOG_CLASS(LLURLRequest);
 public:
-
 	typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param);
-	/** 
-	 * @brief This enumeration is for specifying the type of request.
-	 */
-	enum ERequestAction
-	{
-		INVALID,
-		HTTP_HEAD,
-		HTTP_GET,
-		HTTP_PUT,
-		HTTP_POST,
-		HTTP_DELETE,
-		HTTP_MOVE, // Caller will need to set 'Destination' header
-		REQUEST_ACTION_COUNT
-	};
-
-	/**
-	 * @brief Turn the requst action into an http verb.
-	 */
-	static std::string actionAsVerb(ERequestAction action);
 
 	/** 
 	 * @brief Constructor.
 	 *
-	 * @param action One of the ERequestAction enumerations.
+	 * @param action One of the EHTTPMethod enumerations.
 	 */
-	LLURLRequest(ERequestAction action);
+	LLURLRequest(EHTTPMethod action);
 
 	/** 
 	 * @brief Constructor.
 	 *
-	 * @param action One of the ERequestAction enumerations.
+	 * @param action One of the EHTTPMethod enumerations.
 	 * @param url The url of the request. It should already be encoded.
 	 */
-	LLURLRequest(ERequestAction action, const std::string& url);
+	LLURLRequest(EHTTPMethod action, const std::string& url);
 
 	/** 
 	 * @brief Destructor.
@@ -123,17 +104,17 @@ class LLURLRequest : public LLIOPipe
 	 * 
 	 */
 	void setURL(const std::string& url);
-	std::string getURL() const;
+	const std::string& getURL() const;
 	/** 
 	 * @brief Add a header to the http post.
 	 *
-	 * The header must be correctly formatted for HTTP requests. This
-	 * provides a raw interface if you know what kind of request you
+	 * This provides a raw interface if you know what kind of request you
 	 * will be making during construction of this instance. All
 	 * required headers will be automatically constructed, so this is
 	 * usually useful for encoding parameters.
 	 */
-	void addHeader(const char* header);
+	void addHeader(const std::string& header, const std::string& value = "");
+	void addHeaderRaw(const char* header);
 
 	/**
 	 * @brief Check remote server certificate signed by a known root CA.
@@ -218,7 +199,7 @@ class LLURLRequest : public LLIOPipe
 		STATE_HAVE_RESPONSE,
 	};
 	EState mState;
-	ERequestAction mAction;
+	EHTTPMethod mAction;
 	LLURLRequestDetail* mDetail;
 	LLIOPipe::ptr_t mCompletionCallback;
 	 S32 mRequestTransferedBytes;
@@ -315,7 +296,7 @@ class LLURLRequestComplete : public LLIOPipe
 	// May be called more than once, particularly for redirects and proxy madness.
 	// Ex. a 200 for a connection to https through a proxy, followed by the "real" status
 	//     a 3xx for a redirect followed by a "real" status, or more redirects.
-	virtual void httpStatus(U32 status, const std::string& reason) { }
+	virtual void httpStatus(S32 status, const std::string& reason) { }
 
 	virtual void complete(
 		const LLChannelDescriptors& channels,
@@ -368,15 +349,8 @@ class LLURLRequestComplete : public LLIOPipe
 	//@}
 
 	// value to note if we actually got the response. This value
-	// depends on correct useage from the LLURLRequest instance.
+	// depends on correct usage from the LLURLRequest instance.
 	EStatus mRequestStatus;
 };
 
-
-
-/**
- * External constants
- */
-extern const std::string CONTEXT_DEST_URI_SD_LABEL;
-
 #endif // LL_LLURLREQUEST_H
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index ae95087377f4fe19197189c6e42c37c14429d536..5a63da628d381ff069a5a45170ef36e095b39641 100755
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -113,20 +113,20 @@ namespace
 		{
 		}
 
-		virtual void error(U32 status, const std::string& reason)
+	protected:
+		virtual void httpFailure()
 		{
 			// don't spam when agent communication disconnected already
-			if (status != 410)
+			if (HTTP_GONE != getStatus())
 			{
-				LL_WARNS("Messaging") << "error status " << status
-						<< " for message " << mMessageName
-						<< " reason " << reason << llendl;
+				LL_WARNS("Messaging") << "error for message " << mMessageName
+					<< " " << dumpResponse() << LL_ENDL;
 			}
 			// TODO: Map status in to useful error code.
 			if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT);
 		}
 		
-		virtual void result(const LLSD& content)
+		virtual void httpSuccess()
 		{
 			if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR);
 		}
@@ -152,7 +152,7 @@ class LLMessageHandlerBridge : public LLHTTPNode
 void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, 
 							const LLSD& context, const LLSD& input) const
 {
-	std::string name = context["request"]["wildcard"]["message-name"];
+	std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"];
 	char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str());
 	
 	lldebugs << "Setting mLastSender " << input["sender"].asString() << llendl;
diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp
index 9b298d0c049ef5177018393c3d200d3ea2e51957..b7fdf4f437b075ae07977d1bc107a05e6d32e5f9 100755
--- a/indra/llmessage/tests/llcurl_stub.cpp
+++ b/indra/llmessage/tests/llcurl_stub.cpp
@@ -24,55 +24,76 @@
  * $/LicenseInfo$
  */
 
+#ifndef LL_CURL_STUB_CPP
+#define LL_CURL_STUB_CPP
+
+
 #include "linden_common.h"
 #include "llcurl.h"
+#include "llhttpconstants.cpp"
 
 LLCurl::Responder::Responder()
 {
 }
 
-void LLCurl::Responder::completed(U32 status, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const &reason,
-								  LLSD const& mContent)
+void LLCurl::Responder::httpCompleted()
 {
-	if (isGoodStatus(status))
+	if (isGoodStatus())
 	{
-		result(mContent);
+		httpSuccess();
 	}
 	else
 	{
-		errorWithContent(status, reason, mContent);
+		httpFailure();
 	}
 }
 
-void LLCurl::Responder::completedHeader(unsigned,
-										std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&,
-										LLSD const&)
+void LLCurl::Responder::completedRaw(LLChannelDescriptors const&,
+									 boost::shared_ptr<LLBufferArray> const&)
 {
 }
 
-void LLCurl::Responder::completedRaw(unsigned,
-									 std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&,
-									 LLChannelDescriptors const&,
-									 boost::shared_ptr<LLBufferArray> const&)
+void LLCurl::Responder::httpFailure()
 {
 }
 
-void LLCurl::Responder::errorWithContent(unsigned,
-							  std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&,
-							  LLSD const&)
+LLCurl::Responder::~Responder ()
 {
 }
 
-LLCurl::Responder::~Responder ()
+void LLCurl::Responder::httpSuccess()
+{
+}
+
+std::string LLCurl::Responder::dumpResponse() const
+{
+	return "dumpResponse()";
+}
+
+void LLCurl::Responder::successResult(const LLSD& content)
 {
+	setResult(HTTP_OK, "", content);
+	httpSuccess();
 }
 
-void LLCurl::Responder::error(unsigned,
-							  std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
+void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content)
+{
+	setResult(status, reason, content);
+	httpFailure();
+}
+
+
+void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content)
 {
+	setResult(status, reason, content);
+	httpCompleted();
 }
 
-void LLCurl::Responder::result(LLSD const&)
+void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
 {
+	mStatus = status;
+	mReason = reason;
+	mContent = content;
 }
 
+#endif
diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp
index 87cbafa404c441e83a481e0302fbfe021c7096bf..43fac83c5772c5533d7a146369531fc7e67b530f 100755
--- a/indra/llmessage/tests/llhttpclient_test.cpp
+++ b/indra/llmessage/tests/llhttpclient_test.cpp
@@ -40,8 +40,6 @@
 #include "llproxy.h"
 #include "llpumpio.h"
 
-#include "llsdhttpserver.h"
-#include "lliohttpserver.h"
 #include "lliosocket.h"
 #include "stringize.h"
 
@@ -101,7 +99,7 @@ namespace tut
 			if (mSawError)
 			{
 				std::string msg =
-					llformat("error() called when not expected, status %d",
+					llformat("httpFailure() called when not expected, status %d",
 						mStatus);
 				fail(msg);
 			}
@@ -111,7 +109,7 @@ namespace tut
 		{
 			if (!mSawError)
 			{
-				fail("error() wasn't called");
+				fail("httpFailure() wasn't called");
 			}
 		}
 
@@ -153,33 +151,26 @@ namespace tut
 				mClient.mResultDeleted = true;
 			}
 
-			virtual void error(U32 status, const std::string& reason)
+		protected:
+			virtual void httpFailure()
 			{
 				mClient.mSawError = true;
-				mClient.mStatus = status;
-				mClient.mReason = reason;
+				mClient.mStatus = getStatus();
+				mClient.mReason = getReason();
 			}
 
-			virtual void result(const LLSD& content)
+			virtual void httpSuccess()
 			{
-				mClient.mResult = content;
+				mClient.mResult = getContent();
 			}
 
-			virtual void completed(
-							U32 status, const std::string& reason,
-							const LLSD& content)
+			virtual void httpCompleted()
 			{
-				LLHTTPClient::Responder::completed(status, reason, content);
-
+				LLHTTPClient::Responder::httpCompleted();
+				
 				mClient.mSawCompleted = true;
-			}
-
-			virtual void completedHeader(
-				U32 status, const std::string& reason,
-				const LLSD& content)
-			{
-				mClient.mHeader = content;
 				mClient.mSawCompletedHeader = true;
+				mClient.mHeader = getResponseHeaders();
 			}
 
 		private:
diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp
index 13ce0a0edd85638f296da15b021636d145010c96..cc7feeab4f1a143c3d9ff3678a8ac6276efe04bd 100755
--- a/indra/llmessage/tests/llhttpclientadapter_test.cpp
+++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp
@@ -1,6 +1,6 @@
 /** 
- * @file 
- * @brief 
+ * @file llhttpclientadapter_test.cpp
+ * @brief Tests for LLHTTPClientAdapter
  *
  * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -33,8 +33,8 @@
 float const HTTP_REQUEST_EXPIRY_SECS = 1.0F;
 
 std::vector<std::string> get_urls;
-std::vector<boost::intrusive_ptr<LLCurl::Responder> > get_responders;
-void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout)
+std::vector< LLCurl::ResponderPtr > get_responders;
+void LLHTTPClient::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout)
 {
 	get_urls.push_back(url);
 	get_responders.push_back(responder);
@@ -42,16 +42,30 @@ void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr<LLCurl::Resp
 
 std::vector<std::string> put_urls;
 std::vector<LLSD> put_body;
-std::vector<boost::intrusive_ptr<LLCurl::Responder> > put_responders;
+std::vector<LLSD> put_headers;
+std::vector<LLCurl::ResponderPtr> put_responders;
 
-void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout)
+void LLHTTPClient::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout)
 {
 	put_urls.push_back(url);
 	put_responders.push_back(responder);
 	put_body.push_back(body);
+	put_headers.push_back(headers);
 
 }
 
+std::vector<std::string> delete_urls;
+std::vector<LLCurl::ResponderPtr> delete_responders;
+
+void LLHTTPClient::del(
+	const std::string& url,
+	LLCurl::ResponderPtr responder,
+	const LLSD& headers,
+	const F32 timeout)
+{
+	delete_urls.push_back(url);
+	delete_responders.push_back(responder);
+}
 
 namespace tut
 {
@@ -64,6 +78,9 @@ namespace tut
 			put_urls.clear();
 			put_responders.clear();
 			put_body.clear();
+			put_headers.clear();
+			delete_urls.clear();
+			delete_responders.clear();
 		}
 	};
 
@@ -73,7 +90,7 @@ namespace tut
 
 namespace
 {
-	tut::factory tf("LLHTTPClientAdapterData test");
+	tut::factory tf("LLHTTPClientAdapterData");
 }
 
 namespace tut
@@ -91,7 +108,7 @@ namespace tut
 	{
 		LLHTTPClientAdapter adapter;
 
-		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
 
 		adapter.get("Made up URL", responder);
 		ensure_equals(get_urls.size(), 1);
@@ -103,7 +120,7 @@ namespace tut
 	void object::test<3>()
 	{
 		LLHTTPClientAdapter adapter;
-		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
 
 		adapter.get("Made up URL", responder);
 
@@ -117,7 +134,7 @@ namespace tut
 	{
 		LLHTTPClientAdapter adapter;
 
-		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
 
 		LLSD body;
 		body["TestBody"] = "Foobar";
@@ -133,7 +150,7 @@ namespace tut
 	{
 		LLHTTPClientAdapter adapter;
 
-		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
 
 		LLSD body;
 		body["TestBody"] = "Foobar";
@@ -150,7 +167,7 @@ namespace tut
 	{
 		LLHTTPClientAdapter adapter;
 
-		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder();
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
 
 		LLSD body;
 		body["TestBody"] = "Foobar";
@@ -160,5 +177,45 @@ namespace tut
 		ensure_equals(put_body.size(), 1);
 		ensure_equals(put_body[0]["TestBody"].asString(), "Foobar");
 	}
+
+	// Ensure that headers are passed through put properly
+	template<> template<>
+	void object::test<7>()
+	{
+		LLHTTPClientAdapter adapter;
+
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
+
+		LLSD body = LLSD::emptyMap();
+		body["TestBody"] = "Foobar";
+
+		LLSD headers = LLSD::emptyMap();
+		headers["booger"] = "omg";
+
+		adapter.put("Made up URL", body, responder, headers);
+
+		ensure_equals("Header count", put_headers.size(), 1);
+		ensure_equals(
+			"First header",
+			put_headers[0]["booger"].asString(),
+			"omg");
+	}
+
+	// Ensure that del() passes appropriate arguments to the LLHTTPClient
+	template<> template<>
+	void object::test<8>()
+	{
+		LLHTTPClientAdapter adapter;
+
+		LLCurl::ResponderPtr responder = new LLCurl::Responder();
+
+		adapter.del("Made up URL", responder);
+
+		ensure_equals("URL count", delete_urls.size(), 1);
+		ensure_equals("Received URL", delete_urls[0], "Made up URL");
+
+		ensure_equals("Responder count", delete_responders.size(), 1);
+		//ensure_equals("Responder", delete_responders[0], responder);
+	}
 }
 
diff --git a/indra/llmessage/tests/llhttpnode_stub.cpp b/indra/llmessage/tests/llhttpnode_stub.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cc2108fed523eaf56e615c14a6bc9b067ffd3c2b
--- /dev/null
+++ b/indra/llmessage/tests/llhttpnode_stub.cpp
@@ -0,0 +1,112 @@
+/** 
+ * @file llhttpnode_stub.cpp
+ * @brief STUB Implementation of classes for generic HTTP/LSL/REST handling.
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llhttpnode.h"
+
+const std::string CONTEXT_VERB("verb");
+const std::string CONTEXT_REQUEST("request");
+const std::string CONTEXT_WILDCARD("wildcard");
+const std::string CONTEXT_PATH("path");
+const std::string CONTEXT_QUERY_STRING("query-string");
+const std::string CONTEXT_REMOTE_HOST("remote-host");
+const std::string CONTEXT_REMOTE_PORT("remote-port");
+const std::string CONTEXT_HEADERS("headers");
+const std::string CONTEXT_RESPONSE("response");
+
+/**
+ * LLHTTPNode
+ */
+class LLHTTPNode::Impl
+{
+    // dummy
+};
+
+LLHTTPNode::LLHTTPNode(): impl(*new Impl) {}
+LLHTTPNode::~LLHTTPNode() {}
+LLSD LLHTTPNode::simpleGet() const { return LLSD(); }
+LLSD LLHTTPNode::simplePut(const LLSD& input) const { return LLSD(); }
+LLSD LLHTTPNode::simplePost(const LLSD& input) const { return LLSD(); }
+LLSD LLHTTPNode::simpleDel(const LLSD&) const { return LLSD(); }
+void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const {}
+void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {}
+void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {}
+void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const {}
+void  LLHTTPNode::options(ResponsePtr response, const LLSD& context) const {}
+LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const { return NULL; }
+bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const { return false; }
+bool LLHTTPNode::validate(const std::string& name, LLSD& context) const { return false; }
+const LLHTTPNode* LLHTTPNode::traverse(const std::string& path, LLSD& context) const { return NULL; }
+void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) { }
+LLSD LLHTTPNode::allNodePaths() const { return LLSD(); }
+const LLHTTPNode* LLHTTPNode::rootNode() const { return NULL; }
+const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { return NULL; }
+
+LLHTTPNode::Response::~Response(){}
+void LLHTTPNode::Response::notFound(const std::string& message)
+{
+	status(404, message);
+}
+void LLHTTPNode::Response::notFound()
+{
+	status(404, "Not Found");
+}
+void LLHTTPNode::Response::methodNotAllowed()
+{
+	status(405, "Method Not Allowed");
+}
+void LLHTTPNode::Response::statusUnknownError(S32 code)
+{
+	status(code, "Unknown Error");
+}
+
+void LLHTTPNode::Response::status(S32 code, const std::string& message)
+{
+}
+
+void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value) 
+{
+	mHeaders[name] = value;
+}
+void LLHTTPNode::describe(Description& desc) const { }
+
+
+const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const { return NULL; }
+
+
+LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
+
+void LLHTTPRegistrar::registerFactory(
+    const std::string& path, NodeFactory& factory) {}
+void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root) {}
+
+
diff --git a/indra/llmessage/tests/llmime_test.cpp b/indra/llmessage/tests/llmime_test.cpp
deleted file mode 100755
index aed5c4589cba1d567635351c7ed0ff77008924df..0000000000000000000000000000000000000000
--- a/indra/llmessage/tests/llmime_test.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-/** 
- * @file llmime_test.cpp
- * @author Phoenix
- * @date 2006-12-24
- * @brief BRIEF_DESC of llmime_test.cpp
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llsdserialize.h"
-
-#include "../llmime.h"
-
-#include "../test/lltut.h"
-
-namespace tut
-{
-	struct mime_index
-	{
-	};
-	typedef test_group<mime_index> mime_index_t;
-	typedef mime_index_t::object mime_index_object_t;
-	tut::mime_index_t tut_mime_index("LLMime");
-
-	template<> template<>
-	void mime_index_object_t::test<1>()
-	{
-		LLMimeIndex mime;
-		ensure("no headers", mime.headers().isUndefined());
-		ensure_equals("invalid offset", mime.offset(), -1);
-		ensure_equals("invalid content length", mime.contentLength(), -1);
-		ensure("no content type", mime.contentType().empty());
-		ensure("not multipart", !mime.isMultipart());
-		ensure_equals("no attachments", mime.subPartCount(), 0);
-	}
-
-	template<> template<>
-	void mime_index_object_t::test<2>()
-	{
-		const S32 CONTENT_LENGTH = 6000;
-		const S32 CONTENT_OFFSET = 100;
-		const std::string CONTENT_TYPE = std::string("image/j2c");
-		LLSD headers;
-		headers["Content-Length"] = CONTENT_LENGTH;
-		headers["Content-Type"] = CONTENT_TYPE;
-		LLMimeIndex mime(headers, CONTENT_OFFSET);
-		ensure("headers are map", mime.headers().isMap());
-		ensure_equals("offset", mime.offset(), CONTENT_OFFSET);
-		ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH);
-		ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE);
-		ensure("not multipart", !mime.isMultipart());
-		ensure_equals("no attachments", mime.subPartCount(), 0);
-	}
-
-	template<> template<>
-	void mime_index_object_t::test<3>()
-	{
-		const S32 MULTI_CONTENT_LENGTH = 8000;
-		const S32 MULTI_CONTENT_OFFSET = 100;
-		const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
-		LLSD headers;
-		headers["Content-Length"] = MULTI_CONTENT_LENGTH;
-		headers["Content-Type"] = MULTI_CONTENT_TYPE;
-		LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
-		llinfos << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers)
-			<< llendl;
-
-
-		const S32 META_CONTENT_LENGTH = 700;
-		const S32 META_CONTENT_OFFSET = 69;
-		const std::string META_CONTENT_TYPE = std::string(
-			"text/llsd+xml");
-		headers = LLSD::emptyMap();
-		headers["Content-Length"] = META_CONTENT_LENGTH;
-		headers["Content-Type"] = META_CONTENT_TYPE;
-		LLMimeIndex meta(headers, META_CONTENT_OFFSET);
-		mime.attachSubPart(meta);
-
-		const S32 IMAGE_CONTENT_LENGTH = 6000;
-		const S32 IMAGE_CONTENT_OFFSET = 200;
-		const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
-		headers = LLSD::emptyMap();
-		headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
-		headers["Content-Type"] = IMAGE_CONTENT_TYPE;
-		LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
-		mime.attachSubPart(image);
-
-		// make sure we have a valid multi-part
-		ensure("is multipart", mime.isMultipart());
-		ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
-		ensure_equals(
-			"multi content length",
-			mime.contentLength(),
-			MULTI_CONTENT_LENGTH);
-		ensure_equals("two attachments", mime.subPartCount(), 2);
-
-		// make sure ranged gets do the right thing with out of bounds
-		// sub-parts.
-		LLMimeIndex invalid_child(mime.subPart(-1));
-		ensure("no headers", invalid_child.headers().isUndefined());
-		ensure_equals("invalid offset", invalid_child.offset(), -1);
-		ensure_equals(
-			"invalid content length", invalid_child.contentLength(), -1);
-		ensure("no content type", invalid_child.contentType().empty());
-		ensure("not multipart", !invalid_child.isMultipart());
-		ensure_equals("no attachments", invalid_child.subPartCount(), 0);
-
-		invalid_child = mime.subPart(2);
-		ensure("no headers", invalid_child.headers().isUndefined());
-		ensure_equals("invalid offset", invalid_child.offset(), -1);
-		ensure_equals(
-			"invalid content length", invalid_child.contentLength(), -1);
-		ensure("no content type", invalid_child.contentType().empty());
-		ensure("not multipart", !invalid_child.isMultipart());
-		ensure_equals("no attachments", invalid_child.subPartCount(), 0);
-	}
-
-	template<> template<>
-	void mime_index_object_t::test<4>()
-	{
-		const S32 MULTI_CONTENT_LENGTH = 8000;
-		const S32 MULTI_CONTENT_OFFSET = 100;
-		const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
-		LLSD headers;
-		headers["Content-Length"] = MULTI_CONTENT_LENGTH;
-		headers["Content-Type"] = MULTI_CONTENT_TYPE;
-		LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
-
-		const S32 META_CONTENT_LENGTH = 700;
-		const S32 META_CONTENT_OFFSET = 69;
-		const std::string META_CONTENT_TYPE = std::string(
-			"application/llsd+xml");
-		headers = LLSD::emptyMap();
-		headers["Content-Length"] = META_CONTENT_LENGTH;
-		headers["Content-Type"] = META_CONTENT_TYPE;
-		LLMimeIndex meta(headers, META_CONTENT_OFFSET);
-		mime.attachSubPart(meta);
-
-		const S32 IMAGE_CONTENT_LENGTH = 6000;
-		const S32 IMAGE_CONTENT_OFFSET = 200;
-		const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
-		headers = LLSD::emptyMap();
-		headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
-		headers["Content-Type"] = IMAGE_CONTENT_TYPE;
-		LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
-		mime.attachSubPart(image);
-
-		// check what we have
-		ensure("is multipart", mime.isMultipart());
-		ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
-		ensure_equals(
-			"multi content length",
-			mime.contentLength(),
-			MULTI_CONTENT_LENGTH);
-		ensure_equals("two attachments", mime.subPartCount(), 2);
-
-		LLMimeIndex actual_meta = mime.subPart(0);
-		ensure_equals(
-			"meta type", actual_meta.contentType(), META_CONTENT_TYPE);
-		ensure_equals(
-			"meta offset", actual_meta.offset(), META_CONTENT_OFFSET);
-		ensure_equals(
-			"meta content length",
-			actual_meta.contentLength(),
-			META_CONTENT_LENGTH);
-
-		LLMimeIndex actual_image = mime.subPart(1);
-		ensure_equals(
-			"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE);
-		ensure_equals(
-			"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET);
-		ensure_equals(
-			"image content length",
-			actual_image.contentLength(),
-			IMAGE_CONTENT_LENGTH);
-	}
-
-/*
-	template<> template<>
-	void mime_index_object_t::test<5>()
-	{
-	}
-	template<> template<>
-	void mime_index_object_t::test<6>()
-	{
-	}
-	template<> template<>
-	void mime_index_object_t::test<7>()
-	{
-	}
-	template<> template<>
-	void mime_index_object_t::test<8>()
-	{
-	}
-	template<> template<>
-	void mime_index_object_t::test<>()
-	{
-	}
-*/
-}
-
-
-namespace tut
-{
-	struct mime_parse
-	{
-	};
-	typedef test_group<mime_parse> mime_parse_t;
-	typedef mime_parse_t::object mime_parse_object_t;
-	tut::mime_parse_t tut_mime_parse("LLMimeParse");
-
-	template<> template<>
-	void mime_parse_object_t::test<1>()
-	{
-		// parse one mime object
-		const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n");
-		std::stringstream istr;
-		istr.str(SERIALIZED_MIME);
-		LLMimeIndex mime;
-		LLMimeParser parser;
-		bool ok = parser.parseIndex(istr, mime);
-		ensure("Parse successful.", ok);
-		ensure_equals("content type", mime.contentType(), "text/plain");
-		ensure_equals("content length", mime.contentLength(), 200);
-		ensure_equals("offset", mime.offset(), 49);
- 	}
-
-	template<> template<>
-	void mime_parse_object_t::test<2>()
-	{
-		// make sure we only parse one.
-		const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n");
-		std::stringstream istr;
-		istr.str(SERIALIZED_MIME);
-		LLMimeIndex mime;
-		LLMimeParser parser;
-		bool ok = parser.parseIndex(istr, mime);
-		ensure("Parse successful.", ok);
-		ensure("not multipart.", !mime.isMultipart());
-		ensure_equals("content type", mime.contentType(), "text/plain");
-		ensure_equals("content length", mime.contentLength(), 200);
-		ensure_equals("offset", mime.offset(), 49);
-	}
-
-	template<> template<>
-	void mime_parse_object_t::test<3>()
-	{
-		// test multi-part and lack of content length for some of it.
-		/*
-Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
-		 */
-		const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
-		std::stringstream istr;
-		istr.str(SERIALIZED_MIME);
-		LLMimeIndex mime;
-		LLMimeParser parser;
-		bool ok = parser.parseIndex(istr, mime);
-		ensure("Parse successful.", ok);
-		ensure("is multipart.", mime.isMultipart());
-		ensure_equals("sub-part count", mime.subPartCount(), 2);
-		ensure_equals("content length", mime.contentLength(), 150);
-		ensure_equals("data offset for multipart", mime.offset(), 74);
-
-		LLMimeIndex mime_plain(mime.subPart(0));
-		ensure_equals(
-			"first part type",
-			mime_plain.contentType(),
-			"text/plain");
-		ensure_equals(
-			"first part content length not known.",
-			mime_plain.contentLength(),
-			-1);
-		ensure_equals("first part offset", mime_plain.offset(), 113);
-
-		LLMimeIndex mime_xml(mime.subPart(1));
-		ensure_equals(
-			"second part type",
-			mime_xml.contentType(),
-			"text/xml; charset=UTF-8");
-		ensure_equals(
-			"second part content length",
-			mime_xml.contentLength(),
-			22);
-		ensure_equals("second part offset", mime_xml.offset(), 198);
-	}
-
-	template<> template<>
-	void mime_parse_object_t::test<4>()
-	{
-		// test multi-part, unquoted separator, and premature eof conditions
-		/*
-Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn		 */
-		const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
-		std::stringstream istr;
-		istr.str(SERIALIZED_MIME);
-		LLMimeIndex mime;
-		LLMimeParser parser;
-		bool ok = parser.parseIndex(istr, mime);
-		ensure("Parse successful.", ok);
-		ensure("is multipart.", mime.isMultipart());
-		ensure_equals("sub-part count", mime.subPartCount(), 2);
-		ensure_equals("content length", mime.contentLength(), 220);
-		ensure_equals("data offset for multipart", mime.offset(), 72);
-
-		LLMimeIndex mime_plain(mime.subPart(0));
-		ensure_equals(
-			"first part type",
-			mime_plain.contentType(),
-			"text/plain");
-		ensure_equals(
-			"first part content length",
-			mime_plain.contentLength(),
-			55);
-		ensure_equals("first part offset", mime_plain.offset(), 131);
-
-		LLMimeIndex mime_xml(mime.subPart(1));
-		ensure_equals(
-			"second part type",
-			mime_xml.contentType(),
-			"text/xml; charset=UTF-8");
-		ensure_equals(
-			"second part content length",
-			mime_xml.contentLength(),
-			22);
-		ensure_equals("second part offset", mime_xml.offset(), 262);
-	}
-
-	template<> template<>
-	void mime_parse_object_t::test<5>()
-	{
-		// test multi-part with multiple params
-		const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
-		std::stringstream istr;
-		istr.str(SERIALIZED_MIME);
-		LLMimeIndex mime;
-		LLMimeParser parser;
-		bool ok = parser.parseIndex(istr, mime);
-		ensure("Parse successful.", ok);
-		ensure("is multipart.", mime.isMultipart());
-		ensure_equals("sub-part count", mime.subPartCount(), 2);
-		ensure_equals("content length", mime.contentLength(), 220);
-
-		LLMimeIndex mime_plain(mime.subPart(0));
-		ensure_equals(
-			"first part type",
-			mime_plain.contentType(),
-			"text/plain");
-		ensure_equals(
-			"first part content length",
-			mime_plain.contentLength(),
-			55);
-
-		LLMimeIndex mime_xml(mime.subPart(1));
-		ensure_equals(
-			"second part type",
-			mime_xml.contentType(),
-			"text/xml; charset=UTF-8");
-		ensure_equals(
-			"second part content length",
-			mime_xml.contentLength(),
-			22);
-	}
-
-	template<> template<>
-	void mime_parse_object_t::test<6>()
-	{
-		// test multi-part with no specified boundary and eof
-/*
-Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
-*/
-		const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
-		std::stringstream istr;
-		istr.str(SERIALIZED_MIME);
-		LLMimeIndex mime;
-		LLMimeParser parser;
-		bool ok = parser.parseIndex(istr, mime);
-		ensure("Parse successful.", ok);
-		ensure("is multipart.", mime.isMultipart());
-		ensure_equals("sub-part count", mime.subPartCount(), 2);
-		ensure_equals("content length", mime.contentLength(), 500);
-		ensure_equals("data offset for multipart", mime.offset(), 56);
-
-		LLMimeIndex mime_plain(mime.subPart(0));
-		ensure_equals(
-			"first part type",
-			mime_plain.contentType(),
-			"text/plain");
-		ensure_equals(
-			"first part content length",
-			mime_plain.contentLength(),
-			55);
-		ensure_equals("first part offset", mime_plain.offset(), 108);
-
-		LLMimeIndex mime_xml(mime.subPart(1));
-		ensure_equals(
-			"second part type",
-			mime_xml.contentType(),
-			"text/xml; charset=UTF-8");
-		ensure_equals(
-			"second part content length",
-			mime_xml.contentLength(),
-			22);
-		ensure_equals("second part offset", mime_xml.offset(), 232);
-	}
-
-/*
-	template<> template<>
-	void mime_parse_object_t::test<>()
-	{
-	}
-	template<> template<>
-	void mime_parse_object_t::test<>()
-	{
-	}
-	template<> template<>
-	void mime_parse_object_t::test<>()
-	{
-	}
-	template<> template<>
-	void mime_parse_object_t::test<>()
-	{
-	}
-*/
-}
diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp
deleted file mode 100755
index 5b89f2a8c672d2a089d59497c4c9a2981aa9ca79..0000000000000000000000000000000000000000
--- a/indra/llmessage/tests/llregionpresenceverifier_test.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/** 
- * @file 
- * @brief 
- *
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "../test/lltut.h"
-#include "llregionpresenceverifier.h"
-#include "llcurl_stub.cpp"
-#include "llhost.cpp"
-#include "net.cpp"
-#include "lltesthttpclientadapter.cpp"
-
-class LLTestResponse : public LLRegionPresenceVerifier::Response
-{
-public:
-
-	virtual bool checkValidity(const LLSD& content) const
-	{
-		return true;
-	}
-
-	virtual void onRegionVerified(const LLSD& region_details)
-	{
-	}
-
-	virtual void onRegionVerificationFailed()
-	{
-	}
-	
-	virtual LLHTTPClientInterface& getHttpClient()
-	{
-		return mHttpInterface;
-	}
-
-	LLTestHTTPClientAdapter mHttpInterface;
-};
-
-namespace tut
-{
-	struct LLRegionPresenceVerifierData
-	{
-		LLRegionPresenceVerifierData() :
-			mResponse(new LLTestResponse()),
-			mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse),
-					   LLSD(), 3)
-		{
-		}
-		
-		LLTestResponse* mResponse;
-		LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder;
-	};
-
-	typedef test_group<LLRegionPresenceVerifierData> factory;
-	typedef factory::object object;
-}
-
-namespace
-{
-	tut::factory tf("LLRegionPresenceVerifier");
-}
-
-namespace tut
-{
-	// Test that VerifiedDestinationResponder does retry
-    // on error when shouldRetry returns true.
-	template<> template<>
-	void object::test<1>()
-	{
-		mResponder.error(500, "Internal server error");
-		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1);
-	}
-
-	// Test that VerifiedDestinationResponder only retries
-	// on error until shouldRetry returns false.
-	template<> template<>
-	void object::test<2>()
-	{
-		mResponder.error(500, "Internal server error");
-		mResponder.error(500, "Internal server error");
-		mResponder.error(500, "Internal server error");
-		mResponder.error(500, "Internal server error");
-		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3);
-	}
-}
-
diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp
index b287a2984199429f4f7b3d4904dd319f560b4187..55748ad27e36d2c4fc0c34fea63bea8bd6995f09 100755
--- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp
+++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp
@@ -32,6 +32,7 @@
 
 #include "message.h"
 #include "llmessageconfig.h"
+#include "llhttpnode_stub.cpp"
 
 LLMessageSystem* gMessageSystem = NULL;
 
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 6c798aa4ed081b7bdce3cde61d6d6539802ed727..1b1799aaa2a14af6502ee9b46bcae21acdcad9c4 100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -597,6 +597,7 @@ bool LLGLManager::initGL()
 	if (mGLVendor.substr(0,4) == "ATI ")
 	{
 		mGLVendorShort = "ATI";
+		// *TODO: Fix this?
 		mIsATI = TRUE;
 
 #if LL_WINDOWS && !LL_MESA_HEADLESS
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 09e27a264aa151399208526cf86d02ee21d7ba2d..0807b497a7016dfcd369443f0ac4b316b4fcaf63 100755
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1621,7 +1621,7 @@ void LLFloater::bringToFront( S32 x, S32 y )
 
 
 // virtual
-void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key)
+void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key)
 {
 	LLMultiFloater* hostp = getHost();
 	if (hostp)
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 4dba1e645f5bdcf3d6319180c24efa89879c8170..1d0d3cb050161a9b3caf3941c491eca86dac5d38 100755
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -305,7 +305,7 @@ class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>
 	/*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override
 	
 	void			setFrontmost(BOOL take_focus = TRUE);
-    virtual void	setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());    
+     virtual void	setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
 	
 	// Defaults to false.
 	virtual BOOL	canSaveAs() const { return FALSE; }
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 227644f14f08322388c7eed0a92e8dbc45426f4e..d35180afc9d812f229f35c0f63fe8afe13b59940 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -98,6 +98,7 @@ include_directories(SYSTEM
 set(viewer_SOURCE_FILES
     groupchatlistener.cpp
     llaccountingcostmanager.cpp
+    llaisapi.cpp
     llagent.cpp
     llagentaccess.cpp
     llagentcamera.cpp
@@ -303,6 +304,7 @@ set(viewer_SOURCE_FILES
     llhasheduniqueid.cpp
     llhints.cpp
     llhomelocationresponder.cpp
+    llhttpretrypolicy.cpp
     llhudeffect.cpp
     llhudeffectbeam.cpp
     llhudeffectlookat.cpp
@@ -678,6 +680,7 @@ set(viewer_HEADER_FILES
     ViewerInstall.cmake
     groupchatlistener.h
     llaccountingcostmanager.h
+    llaisapi.h
     llagent.h
     llagentaccess.h
     llagentcamera.h
@@ -882,6 +885,7 @@ set(viewer_HEADER_FILES
     llgroupmgr.h
     llhasheduniqueid.h
     llhints.h
+    llhttpretrypolicy.h
     llhomelocationresponder.h
     llhudeffect.h
     llhudeffectbeam.h
@@ -2130,10 +2134,21 @@ if (LL_TESTS)
     #llviewertexturelist.cpp
   )
 
+  set(test_libs
+    ${JSONCPP_LIBRARIES}
+    ${CURL_LIBRARIES}
+    )
+
   set_source_files_properties(
     lltranslate.cpp
     PROPERTIES
-    LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}"
+    LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}"
+  )
+
+  set_source_files_properties(
+    llmediadataclient.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"
   )
 
   set_source_files_properties(
@@ -2180,6 +2195,7 @@ if (LL_TESTS)
 
   set(test_libs
     ${LLMESSAGE_LIBRARIES}
+    ${LLCOREHTTP_LIBRARIES}
     ${WINDOWS_LIBRARIES}
     ${LLVFS_LIBRARIES}
     ${LLMATH_LIBRARIES}
@@ -2225,6 +2241,8 @@ if (LL_TESTS)
     "${test_libs}"
     )
 
+  LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}")
+
   #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
   #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
   #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index 92a241857e02e055ce8c0ba7a71d06257b86e635..6594fdb249a2d5a7eaa3e0e9d6bd33f1242b3473 100755
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -43,6 +43,7 @@
 					<key>tags</key>
 						<array>
 						<!-- sample entry for debugging specific items	
+						     <string>Inventory</string>
 						     <string>Avatar</string>
 						     <string>Voice</string>		
 						-->
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f356cff9d89fd3cb1b610e5656189116a79b5f23..bb12cd59bcc78fde01cbd973a2965697954cfe4a 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11152,6 +11152,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>TextureFetchFakeFailureRate</key>
+  <map>
+    <key>Comment</key>
+    <string>Simulate HTTP fetch failures for some server bake textures.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <integer>0.0</integer>
+  </map>
     <key>TextureFetchSource</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp
index 7662a9689daa0849a6a22146c722bb27dc48a9de..55d453cdcceb784f4e136de12f5702281dc2038d 100755
--- a/indra/newview/llaccountingcostmanager.cpp
+++ b/indra/newview/llaccountingcostmanager.cpp
@@ -36,6 +36,7 @@ LLAccountingCostManager::LLAccountingCostManager()
 //===============================================================================
 class LLAccountingCostResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLAccountingCostResponder);
 public:
 	LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle )
 	: mObjectIDs( objectIDs ),
@@ -56,24 +57,27 @@ class LLAccountingCostResponder : public LLCurl::Responder
 		}
 	}
 	
-	void errorWithContent( U32 statusNum, const std::string& reason, const LLSD& content )
+protected:
+	void httpFailure()
 	{
-		llwarns << "Transport error [status:" << statusNum << "]: " << content <<llendl;
+		llwarns << dumpResponse() << llendl;
 		clearPendingRequests();
 
 		LLAccountingCostObserver* observer = mObserverHandle.get();
 		if (observer && observer->getTransactionID() == mTransactionID)
 		{
-			observer->setErrorStatus(statusNum, reason);
+			observer->setErrorStatus(getStatus(), getReason());
 		}
 	}
 	
-	void result( const LLSD& content )
+	void httpSuccess()
 	{
+		const LLSD& content = getContent();
 		//Check for error
 		if ( !content.isMap() || content.has("error") )
 		{
-			llwarns	<< "Error on fetched data"<< llendl;
+			failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content);
+			return;
 		}
 		else if (content.has("selected"))
 		{
diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h
index 0bca1f54ef76a7b078c72d63dd5405bdb27c0bba..3ade34c81d0a6c7a1be2faa010e7ffd06df4427c 100755
--- a/indra/newview/llaccountingcostmanager.h
+++ b/indra/newview/llaccountingcostmanager.h
@@ -38,7 +38,7 @@ class LLAccountingCostObserver
 	LLAccountingCostObserver() { mObserverHandle.bind(this); }
 	virtual ~LLAccountingCostObserver() {}
 	virtual void onWeightsUpdate(const SelectionCost& selection_cost) = 0;
-	virtual void setErrorStatus(U32 status, const std::string& reason) = 0;
+	virtual void setErrorStatus(S32 status, const std::string& reason) = 0;
 	const LLHandle<LLAccountingCostObserver>& getObserverHandle() const { return mObserverHandle; }
 	const LLUUID& getTransactionID() { return mTransactionID; }
 
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 8c42defa73f25bc7a47871ffd8911b7b54848403..21625815b99aa9bf6d01f7522a9bc7d78f68dbc6 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2526,17 +2526,19 @@ int LLAgent::convertTextToMaturity(char text)
 
 class LLMaturityPreferencesResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLMaturityPreferencesResponder);
 public:
 	LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity);
 	virtual ~LLMaturityPreferencesResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
+protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 protected:
 
 private:
-	U8 parseMaturityFromServerResponse(const LLSD &pContent);
+	U8 parseMaturityFromServerResponse(const LLSD &pContent) const;
 
 	LLAgent                                  *mAgent;
 	U8                                       mPreferredMaturity;
@@ -2555,39 +2557,43 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()
 {
 }
 
-void LLMaturityPreferencesResponder::result(const LLSD &pContent)
+void LLMaturityPreferencesResponder::httpSuccess()
 {
-	U8 actualMaturity = parseMaturityFromServerResponse(pContent);
+	U8 actualMaturity = parseMaturityFromServerResponse(getContent());
 
 	if (actualMaturity != mPreferredMaturity)
 	{
-		llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity)
-			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '"
-			<< LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:"
-			<< pContent << "]" << llendl;
+		llwarns << "while attempting to change maturity preference from '"
+				<< LLViewerRegion::accessToString(mPreviousMaturity)
+				<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) 
+				<< "', the server responded with '"
+				<< LLViewerRegion::accessToString(actualMaturity) 
+				<< "' [value:" << static_cast<U32>(actualMaturity) 
+				<< "], " << dumpResponse() << llendl;
 	}
 	mAgent->handlePreferredMaturityResult(actualMaturity);
 }
 
-void LLMaturityPreferencesResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent)
+void LLMaturityPreferencesResponder::httpFailure()
 {
-	llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity)
-		<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error with [status:"
-		<< pStatus << "]: " << (pContent.isDefined() ? pContent : LLSD(pReason)) << llendl;
+	llwarns << "while attempting to change maturity preference from '" 
+			<< LLViewerRegion::accessToString(mPreviousMaturity)
+			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) 
+			<< "', " << dumpResponse() << llendl;
 	mAgent->handlePreferredMaturityError();
 }
 
-U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent)
+U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const
 {
 	U8 maturity = SIM_ACCESS_MIN;
 
-	llassert(!pContent.isUndefined());
+	llassert(pContent.isDefined());
 	llassert(pContent.isMap());
 	llassert(pContent.has("access_prefs"));
 	llassert(pContent.get("access_prefs").isMap());
 	llassert(pContent.get("access_prefs").has("max"));
 	llassert(pContent.get("access_prefs").get("max").isString());
-	if (!pContent.isUndefined() && pContent.isMap() && pContent.has("access_prefs")
+	if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs")
 		&& pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max")
 		&& pContent.get("access_prefs").get("max").isString())
 	{
@@ -2733,7 +2739,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
 		// If we don't have a region, report it as an error
 		if (getRegion() == NULL)
 		{
-			responderPtr->errorWithContent(0U, "region is not defined", LLSD());
+			responderPtr->failureResult(0U, "region is not defined", LLSD());
 		}
 		else
 		{
@@ -2743,7 +2749,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
 			// If the capability is not defined, report it as an error
 			if (url.empty())
 			{
-				responderPtr->errorWithContent(0U, 
+				responderPtr->failureResult(0U, 
 							"capability 'UpdateAgentInformation' is not defined for region", LLSD());
 			}
 			else
@@ -3242,8 +3248,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode
 			!input.has("body") )
 		{
 			//what to do with badly formed message?
-			response->statusUnknownError(400);
-			response->result(LLSD("Invalid message parameters"));
+			response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters"));
 		}
 
 		LLSD body = input["body"];
@@ -3312,8 +3317,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode
 		else
 		{
 			//what to do with badly formed message?
-			response->statusUnknownError(400);
-			response->result(LLSD("Invalid message parameters"));
+			response->extendedResult(HTTP_BAD_REQUEST, LLSD("Invalid message parameters"));
 		}
 	}
 };
@@ -4292,7 +4296,7 @@ void LLAgent::sendAgentSetAppearance()
 		return;
 	}
 
-	if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return;
+	if (!isAgentAvatarValid() || gAgentAvatarp->isEditingAppearance() || (getRegion() && getRegion()->getCentralBakeVersion())) return;
 
 	// At this point we have a complete appearance to send and are in a non-baking region.
 	// DRANO FIXME
@@ -4333,7 +4337,9 @@ void LLAgent::sendAgentSetAppearance()
 	// to compensate for the COLLISION_TOLERANCE ugliness we will have 
 	// to tweak this number again
 	const LLVector3 body_size = gAgentAvatarp->mBodySize + gAgentAvatarp->mAvatarOffset;
-	msg->addVector3Fast(_PREHASH_Size, body_size);	
+	msg->addVector3Fast(_PREHASH_Size, body_size);
+	
+	LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Sent AgentSetAppearance with height: " << body_size.mV[VZ] << " base: " << gAgentAvatarp->mBodySize.mV[VZ] << " hover: " << gAgentAvatarp->mAvatarOffset.mV[VZ] << LL_ENDL;	
 
 	// To guard against out of order packets
 	// Note: always start by sending 1.  This resets the server's count. 0 on the server means "uninitialized"
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
old mode 100755
new mode 100644
index c88694ef76b9054cfbe20543c33027a4681c0d07..80c83642230392e664632b35335c60038fe5c460
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -69,7 +69,7 @@ void wear_and_edit_cb(const LLUUID& inv_item)
 	gAgentWearables.requestEditingWearable(inv_item);
 	
 	// Wear it.
-	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item);
+	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -239,7 +239,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i
 	}
 	if (mTodo & CALL_RECOVERDONE)
 	{
-		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false);
+		LLAppearanceMgr::instance().addCOFItemLink(inv_item);
 		gAgentWearables.recoverMissingWearableDone();
 	}
 	/*
@@ -247,7 +247,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i
 	 */
 	if (mTodo & CALL_CREATESTANDARDDONE)
 	{
-		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false);
+		LLAppearanceMgr::instance().addCOFItemLink(inv_item);
 		gAgentWearables.createStandardWearablesDone(mType, mIndex);
 	}
 	if (mTodo & CALL_MAKENEWOUTFITDONE)
@@ -256,7 +256,8 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i
 	}
 	if (mTodo & CALL_WEARITEM)
 	{
-		LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription);
+		LLAppearanceMgr::instance().addCOFItemLink(inv_item, 
+			new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription);
 	}
 }
 
@@ -1896,6 +1897,7 @@ bool LLAgentWearables::changeInProgress() const
 void LLAgentWearables::notifyLoadingStarted()
 {
 	mCOFChangeInProgress = true;
+	mCOFChangeTimer.reset();
 	mLoadingStartedSignal();
 }
 
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 5be4648636792a5c883750c57b635b1ea5abb46a..0adf545aab016533ca7f79a39309ee893358e802 100755
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -77,6 +77,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	BOOL			isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const;
 	BOOL			areWearablesLoaded() const;
 	bool			isCOFChangeInProgress() const { return mCOFChangeInProgress; }
+	F32				getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); }
 	void			updateWearablesLoaded();
 	void			checkWearablesLoaded() const;
 	bool			canMoveWearable(const LLUUID& item_id, bool closer_to_body) const;
@@ -237,6 +238,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	 * True if agent's outfit is being changed now.
 	 */
 	BOOL			mCOFChangeInProgress;
+	LLTimer			mCOFChangeTimer;
 	
 	//--------------------------------------------------------------------------------
 	// Support classes
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..21f6482a06ffb8421513fee0f86f91c2321df22e
--- /dev/null
+++ b/indra/newview/llaisapi.cpp
@@ -0,0 +1,484 @@
+/** 
+ * @file llaisapi.cpp
+ * @brief classes and functions for interfacing with the v3+ ais inventory service. 
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ *
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llaisapi.h"
+
+#include "llagent.h"
+#include "llcallbacklist.h"
+#include "llinventorymodel.h"
+#include "llsdutil.h"
+#include "llviewerregion.h"
+
+///----------------------------------------------------------------------------
+/// Classes for AISv3 support.
+///----------------------------------------------------------------------------
+
+// AISCommand - base class for retry-able HTTP requests using the AISv3 cap.
+AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback):
+	mCallback(callback)
+{
+	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
+}
+
+void AISCommand::run_command()
+{
+	mCommandFunc();
+}
+
+void AISCommand::setCommandFunc(command_func_type command_func)
+{
+	mCommandFunc = command_func;
+}
+	
+// virtual
+bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id)
+{
+	return false;
+}
+	
+/* virtual */
+void AISCommand::httpSuccess()
+{
+	// Command func holds a reference to self, need to release it
+	// after a success or final failure.
+	setCommandFunc(no_op);
+		
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
+	mRetryPolicy->onSuccess();
+		
+	gInventory.onAISUpdateReceived("AISCommand", content);
+
+	if (mCallback)
+	{
+		LLUUID item_id; // will default to null if parse fails.
+		getResponseUUID(content,item_id);
+		mCallback->fire(item_id);
+	}
+}
+
+/*virtual*/
+void AISCommand::httpFailure()
+{
+	const LLSD& content = getContent();
+	S32 status = getStatus();
+	const std::string& reason = getReason();
+	const LLSD& headers = getResponseHeaders();
+	if (!content.isMap())
+	{
+		LL_DEBUGS("Inventory") << "Malformed response contents " << content
+							   << " status " << status << " reason " << reason << llendl;
+	}
+	else
+	{
+		LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content)
+							   << " status " << status << " reason " << reason << llendl;
+	}
+	mRetryPolicy->onFailure(status, headers);
+	F32 seconds_to_wait;
+	if (mRetryPolicy->shouldRetry(seconds_to_wait))
+	{
+		doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait);
+	}
+	else
+	{
+		// Command func holds a reference to self, need to release it
+		// after a success or final failure.
+		setCommandFunc(no_op);
+	}
+}
+
+//static
+bool AISCommand::getCap(std::string& cap)
+{
+	if (gAgent.getRegion())
+	{
+		cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
+	}
+	if (!cap.empty())
+	{
+		return true;
+	}
+	return false;
+}
+
+RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id,
+									 LLPointer<LLInventoryCallback> callback):
+	AISCommand(callback)
+{
+	std::string cap;
+	if (!getCap(cap))
+	{
+		llwarns << "No cap found" << llendl;
+		return;
+	}
+	std::string url = cap + std::string("/item/") + item_id.asString();
+	LL_DEBUGS("Inventory") << "url: " << url << llendl;
+	LLHTTPClient::ResponderPtr responder = this;
+	LLSD headers;
+	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+	setCommandFunc(cmd);
+}
+
+RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id,
+											 LLPointer<LLInventoryCallback> callback):
+	AISCommand(callback)
+{
+	std::string cap;
+	if (!getCap(cap))
+	{
+		llwarns << "No cap found" << llendl;
+		return;
+	}
+	std::string url = cap + std::string("/category/") + item_id.asString();
+	LL_DEBUGS("Inventory") << "url: " << url << llendl;
+	LLHTTPClient::ResponderPtr responder = this;
+	LLSD headers;
+	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+	setCommandFunc(cmd);
+}
+
+PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id,
+												 LLPointer<LLInventoryCallback> callback):
+	AISCommand(callback)
+{
+	std::string cap;
+	if (!getCap(cap))
+	{
+		llwarns << "No cap found" << llendl;
+		return;
+	}
+	std::string url = cap + std::string("/category/") + item_id.asString() + "/children";
+	LL_DEBUGS("Inventory") << "url: " << url << llendl;
+	LLCurl::ResponderPtr responder = this;
+	LLSD headers;
+	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+	setCommandFunc(cmd);
+}
+
+UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id,
+									 const LLSD& updates,
+									 LLPointer<LLInventoryCallback> callback):
+	mUpdates(updates),
+	AISCommand(callback)
+{
+	std::string cap;
+	if (!getCap(cap))
+	{
+		llwarns << "No cap found" << llendl;
+		return;
+	}
+	std::string url = cap + std::string("/item/") + item_id.asString();
+	LL_DEBUGS("Inventory") << "url: " << url << llendl;
+	LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << llendl;
+	LLCurl::ResponderPtr responder = this;
+	LLSD headers;
+	headers["Content-Type"] = "application/llsd+xml";
+	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
+	setCommandFunc(cmd);
+}
+
+UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& item_id,
+											 const LLSD& updates,
+											 LLPointer<LLInventoryCallback> callback):
+	mUpdates(updates),
+	AISCommand(callback)
+{
+	std::string cap;
+	if (!getCap(cap))
+	{
+		llwarns << "No cap found" << llendl;
+		return;
+	}
+	std::string url = cap + std::string("/category/") + item_id.asString();
+	LL_DEBUGS("Inventory") << "url: " << url << llendl;
+	LLCurl::ResponderPtr responder = this;
+	LLSD headers;
+	headers["Content-Type"] = "application/llsd+xml";
+	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
+	setCommandFunc(cmd);
+}
+
+SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback):
+	mContents(contents),
+	AISCommand(callback)
+{
+	std::string cap;
+	if (!getCap(cap))
+	{
+		llwarns << "No cap found" << llendl;
+		return;
+	}
+	LLUUID tid;
+	tid.generate();
+	std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString();
+	llinfos << url << llendl;
+	LLCurl::ResponderPtr responder = this;
+	LLSD headers;
+	headers["Content-Type"] = "application/llsd+xml";
+	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+	command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout);
+	setCommandFunc(cmd);
+}
+
+AISUpdate::AISUpdate(const LLSD& update)
+{
+	parseUpdate(update);
+}
+
+void AISUpdate::parseUpdate(const LLSD& update)
+{
+	// parse _categories_removed -> mObjectsDeleted
+	uuid_vec_t cat_ids;
+	parseUUIDArray(update,"_categories_removed",cat_ids);
+	for (uuid_vec_t::const_iterator it = cat_ids.begin();
+		 it != cat_ids.end(); ++it)
+	{
+		LLViewerInventoryCategory *cat = gInventory.getCategory(*it);
+		mCatDeltas[cat->getParentUUID()]--;
+		mObjectsDeleted.insert(*it);
+	}
+
+	// parse _categories_items_removed -> mObjectsDeleted
+	uuid_vec_t item_ids;
+	parseUUIDArray(update,"_category_items_removed",item_ids);
+	for (uuid_vec_t::const_iterator it = item_ids.begin();
+		 it != item_ids.end(); ++it)
+	{
+		LLViewerInventoryItem *item = gInventory.getItem(*it);
+		mCatDeltas[item->getParentUUID()]--;
+		mObjectsDeleted.insert(*it);
+	}
+
+	// parse _broken_links_removed -> mObjectsDeleted
+	uuid_vec_t broken_link_ids;
+	parseUUIDArray(update,"_broken_links_removed",broken_link_ids);
+	for (uuid_vec_t::const_iterator it = broken_link_ids.begin();
+		 it != broken_link_ids.end(); ++it)
+	{
+		LLViewerInventoryItem *item = gInventory.getItem(*it);
+		mCatDeltas[item->getParentUUID()]--;
+		mObjectsDeleted.insert(*it);
+	}
+
+	// parse _created_items
+	parseUUIDArray(update,"_created_items",mItemsCreatedIds);
+
+	if (update.has("_embedded"))
+	{
+		const LLSD& embedded = update["_embedded"];
+		for(LLSD::map_const_iterator it = embedded.beginMap(),
+				end = embedded.endMap();
+				it != end; ++it)
+		{
+			const std::string& field = (*it).first;
+			
+			// parse created links
+			if (field == "link")
+			{
+				const LLSD& links = embedded["link"];
+				parseCreatedLinks(links);
+			}
+			else
+			{
+				llwarns << "unrecognized embedded field " << field << llendl;
+			}
+		}
+		
+	}
+
+	// Parse item update at the top level.
+	if (update.has("item_id"))
+	{
+		LLUUID item_id = update["item_id"].asUUID();
+		LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
+		BOOL rv = new_item->unpackMessage(update);
+		if (rv)
+		{
+			mItemsUpdated[item_id] = new_item;
+			// This statement is here to cause a new entry with 0
+			// delta to be created if it does not already exist;
+			// otherwise has no effect.
+			mCatDeltas[new_item->getParentUUID()];
+		}
+		else
+		{
+			llerrs << "unpack failed" << llendl;
+		}
+	}
+
+	// Parse updated category versions.
+	const std::string& ucv = "_updated_category_versions";
+	if (update.has(ucv))
+	{
+		for(LLSD::map_const_iterator it = update[ucv].beginMap(),
+				end = update[ucv].endMap();
+			it != end; ++it)
+		{
+			const LLUUID id((*it).first);
+			S32 version = (*it).second.asInteger();
+			mCatVersions[id] = version;
+		}
+	}
+}
+
+void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_vec_t& ids)
+{
+	ids.clear();
+	if (content.has(name))
+	{
+		for(LLSD::array_const_iterator it = content[name].beginArray(),
+				end = content[name].endArray();
+				it != end; ++it)
+		{
+			ids.push_back((*it).asUUID());
+		}
+	}
+}
+
+void AISUpdate::parseLink(const LLUUID& link_id, const LLSD& link_map)
+{
+	LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem);
+	BOOL rv = new_link->unpackMessage(link_map);
+	if (rv)
+	{
+		LLPermissions default_perms;
+		default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null);
+		default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE);
+		new_link->setPermissions(default_perms);
+		LLSaleInfo default_sale_info;
+		new_link->setSaleInfo(default_sale_info);
+		//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << llendl;
+		mItemsCreated[link_id] = new_link;
+		const LLUUID& parent_id = new_link->getParentUUID();
+		mCatDeltas[parent_id]++;
+	}
+	else
+	{
+		llwarns << "failed to parse" << llendl;
+	}
+}
+
+void AISUpdate::parseCreatedLinks(const LLSD& links)
+{
+	for(LLSD::map_const_iterator linkit = links.beginMap(),
+			linkend = links.endMap();
+		linkit != linkend; ++linkit)
+	{
+		const LLUUID link_id((*linkit).first);
+		const LLSD& link_map = (*linkit).second;
+		uuid_vec_t::const_iterator pos =
+			std::find(mItemsCreatedIds.begin(),
+					  mItemsCreatedIds.end(),link_id);
+		if (pos != mItemsCreatedIds.end())
+		{
+			parseLink(link_id,link_map);
+		}
+		else
+		{
+			LL_DEBUGS("Inventory") << "Ignoring link not in created items list " << link_id << llendl;
+		}
+	}
+}
+
+void AISUpdate::doUpdate()
+{
+	// Do descendent/version accounting.
+	// Can remove this if/when we use the version info directly.
+	for (std::map<LLUUID,S32>::const_iterator catit = mCatDeltas.begin();
+		 catit != mCatDeltas.end(); ++catit)
+	{
+		const LLUUID cat_id(catit->first);
+		S32 delta = catit->second;
+		LLInventoryModel::LLCategoryUpdate up(cat_id, delta);
+		gInventory.accountForUpdate(up);
+	}
+	
+	// TODO - how can we use this version info? Need to be sure all
+	// changes are going through AIS first, or at least through
+	// something with a reliable responder.
+	for (uuid_int_map_t::iterator ucv_it = mCatVersions.begin();
+		 ucv_it != mCatVersions.end(); ++ucv_it)
+	{
+		const LLUUID id = ucv_it->first;
+		S32 version = ucv_it->second;
+		LLViewerInventoryCategory *cat = gInventory.getCategory(id);
+		if (cat->getVersion() != version)
+		{
+			llwarns << "Possible version mismatch, viewer " << cat->getVersion()
+					<< " server " << version << llendl;
+		}
+	}
+
+	// CREATE ITEMS
+	for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin();
+		 create_it != mItemsCreated.end(); ++create_it)
+	{
+		LLUUID item_id(create_it->first);
+		LLPointer<LLViewerInventoryItem> new_item = create_it->second;
+
+		// FIXME risky function since it calls updateServer() in some
+		// cases.  Maybe break out the update/create cases, in which
+		// case this is create.
+		LL_DEBUGS("Inventory") << "created item " << item_id << llendl;
+		gInventory.updateItem(new_item);
+	}
+	
+	// UPDATE ITEMS
+	for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin();
+		 update_it != mItemsUpdated.end(); ++update_it)
+	{
+		LLUUID item_id(update_it->first);
+		LLPointer<LLViewerInventoryItem> new_item = update_it->second;
+		// FIXME risky function since it calls updateServer() in some
+		// cases.  Maybe break out the update/create cases, in which
+		// case this is update.
+		LL_DEBUGS("Inventory") << "updated item " << item_id << llendl;
+		gInventory.updateItem(new_item);
+	}
+
+	// DELETE OBJECTS
+	for (std::set<LLUUID>::const_iterator del_it = mObjectsDeleted.begin();
+		 del_it != mObjectsDeleted.end(); ++del_it)
+	{
+		LL_DEBUGS("Inventory") << "deleted item " << *del_it << llendl;
+		gInventory.onObjectDeletedFromServer(*del_it, false, false, false);
+	}
+
+	gInventory.notifyObservers();
+}
+
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
new file mode 100755
index 0000000000000000000000000000000000000000..1f9555f004947c11db9a7c96033d2f532583b1b6
--- /dev/null
+++ b/indra/newview/llaisapi.h
@@ -0,0 +1,143 @@
+/** 
+ * @file llaisapi.h
+ * @brief classes and functions for interfacing with the v3+ ais inventory service. 
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAISAPI_H
+#define LL_LLAISAPI_H
+
+#include "lluuid.h"
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include "llcurl.h"
+#include "llhttpclient.h"
+#include "llhttpretrypolicy.h"
+#include "llviewerinventory.h"
+
+class AISCommand: public LLHTTPClient::Responder
+{
+public:
+	typedef boost::function<void()> command_func_type;
+
+	AISCommand(LLPointer<LLInventoryCallback> callback);
+
+	virtual ~AISCommand() {}
+
+	void run_command();
+
+	void setCommandFunc(command_func_type command_func);
+	
+	// Need to do command-specific parsing to get an id here, for
+	// LLInventoryCallback::fire().  May or may not need to bother,
+	// since most LLInventoryCallbacks do their work in the
+	// destructor.
+	virtual bool getResponseUUID(const LLSD& content, LLUUID& id);
+	
+	/* virtual */ void httpSuccess();
+
+	/*virtual*/ void httpFailure();
+
+	static bool getCap(std::string& cap);
+
+private:
+	command_func_type mCommandFunc;
+	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
+	LLPointer<LLInventoryCallback> mCallback;
+};
+
+class RemoveItemCommand: public AISCommand
+{
+public:
+	RemoveItemCommand(const LLUUID& item_id,
+					  LLPointer<LLInventoryCallback> callback);
+};
+
+class RemoveCategoryCommand: public AISCommand
+{
+public:
+	RemoveCategoryCommand(const LLUUID& item_id,
+						  LLPointer<LLInventoryCallback> callback);
+};
+
+class PurgeDescendentsCommand: public AISCommand
+{
+public:
+	PurgeDescendentsCommand(const LLUUID& item_id,
+							LLPointer<LLInventoryCallback> callback);
+};
+
+class UpdateItemCommand: public AISCommand
+{
+public:
+	UpdateItemCommand(const LLUUID& item_id,
+					  const LLSD& updates,
+					  LLPointer<LLInventoryCallback> callback);
+private:
+	LLSD mUpdates;
+};
+
+class UpdateCategoryCommand: public AISCommand
+{
+public:
+	UpdateCategoryCommand(const LLUUID& item_id,
+						  const LLSD& updates,
+						  LLPointer<LLInventoryCallback> callback);
+private:
+	LLSD mUpdates;
+};
+
+class SlamFolderCommand: public AISCommand
+{
+public:
+	SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback);
+	
+private:
+	LLSD mContents;
+};
+
+class AISUpdate
+{
+public:
+	AISUpdate(const LLSD& update);
+	void parseUpdate(const LLSD& update);
+	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_vec_t& ids);
+	void parseLink(const LLUUID& link_id, const LLSD& link_map);
+	void parseCreatedLinks(const LLSD& links);
+	void doUpdate();
+private:
+	typedef std::map<LLUUID,S32> uuid_int_map_t;
+	uuid_int_map_t mCatDeltas;
+	uuid_int_map_t mCatVersions;
+
+	typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t;
+	deferred_item_map_t mItemsCreated;
+	deferred_item_map_t mItemsUpdated;
+
+	std::set<LLUUID> mObjectsDeleted;
+	uuid_vec_t mItemsCreatedIds;
+};
+
+#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 652f199e2835686dbe4426cd4a47ac41bbe782b4..f5f6faf6b6901a8f8df81e1a115d2ba57f82f63e 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -52,6 +52,7 @@
 #include "llwearablelist.h"
 #include "llsdutil.h"
 #include "llsdserialize.h"
+#include "llhttpretrypolicy.h"
 
 #if LL_MSVC
 // disable boost::lexical_cast warning
@@ -396,6 +397,12 @@ class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr
 		LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)
 	{
 		addItems(src_items);
+		sInstanceCount++;
+	}
+
+	~LLCallAfterInventoryCopyMgr()
+	{
+		sInstanceCount--;
 	}
 	
 	virtual bool requestOperation(const LLUUID& item_id)
@@ -418,95 +425,36 @@ class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr
 			);
 		return true;
 	}
-};
-
-class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr
-{
-public:
-	LLCallAfterInventoryLinkMgr(LLInventoryModel::item_array_t& src_items,
-								const LLUUID& dst_cat_id,
-								const std::string& phase_name,
-								nullary_func_t on_completion_func,
-								nullary_func_t on_failure_func = no_op,
-								 F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL,
-								 S32 max_retries = DEFAULT_MAX_RETRIES
-		):
-		LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)
-	{
-		addItems(src_items);
-	}
-	
-	virtual bool requestOperation(const LLUUID& item_id)
-	{
-		bool request_sent = false;
-		LLViewerInventoryItem *item = gInventory.getItem(item_id);
-		if (item)
-		{
-			if (item->getParentUUID() == mDstCatID)
-			{
-				LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << llendl;
-				return false;
-			}
-			LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << llendl;
-			// create an inventory item link.
-			if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
-			{
-				LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl;
-				return true;
-			}
-			link_inventory_item(gAgent.getID(),
-								item->getLinkedUUID(),
-								mDstCatID,
-								item->getName(),
-								item->getActualDescription(),
-								LLAssetType::AT_LINK,
-								new LLBoostFuncInventoryCallback(
-									boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())));
-			return true;
-		}
-		else
-		{
-			// create a base outfit link if appropriate.
-			LLViewerInventoryCategory *catp = gInventory.getCategory(item_id);
-			if (!catp)
-			{
-				llwarns << "link request failed, id not found as inventory item or category " << item_id << llendl;
-				return false;
-			}
-			const LLUUID cof = LLAppearanceMgr::instance().getCOF();
-			std::string new_outfit_name = "";
 
-			LLAppearanceMgr::instance().purgeBaseOutfitLink(cof);
-
-			if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
-			{
-				if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
-				{
-					LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl;
-					return true;
-				}
-				LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << llendl;
-				link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "",
-									LLAssetType::AT_LINK_FOLDER, 
-									new LLBoostFuncInventoryCallback(
-										boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer())));
-				new_outfit_name = catp->getName();
-				request_sent = true;
-			}
+	static S32 getInstanceCount() { return sInstanceCount; }
 	
-			LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name);
-		}
-		return request_sent;
-	}
+private:
+	static S32 sInstanceCount;
 };
 
-LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering):
+S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0;
+
+LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering,
+														 bool enforce_item_restrictions,
+														 bool enforce_ordering):
 	mFireCount(0),
-	mUpdateBaseOrder(update_base_outfit_ordering)
+	mUpdateBaseOrder(update_base_outfit_ordering),
+	mEnforceItemRestrictions(enforce_item_restrictions),
+	mEnforceOrdering(enforce_ordering)
 {
 	selfStartPhase("update_appearance_on_destroy");
 }
 
+void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item)
+{
+	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item);
+	const std::string item_name = item ? item->getName() : "ITEM NOT FOUND";
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL;
+#endif
+	mFireCount++;
+}
+
 LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
 {
 	if (!LLApp::isExiting())
@@ -516,20 +464,39 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
 
 		selfStopPhase("update_appearance_on_destroy");
 
-		LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder);
+		LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder, mEnforceItemRestrictions, mEnforceOrdering);
 	}
 }
 
-void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item)
+LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id):
+	mItemID(item_id)
 {
-	LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item);
-	const std::string item_name = item ? item->getName() : "ITEM NOT FOUND";
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL;
-#endif
-	mFireCount++;
 }
 
+LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy()
+{
+	if (!LLApp::isExiting())
+	{
+		LLAppearanceMgr::instance().updateAppearanceFromCOF();
+		
+		// Start editing the item if previously requested.
+		gAgentWearables.editWearableIfRequested(mItemID);
+		
+		// TODO: camera mode may not be changed if a debug setting is tweaked
+		if( gAgentCamera.cameraCustomizeAvatar() )
+		{
+			// If we're in appearance editing mode, the current tab may need to be refreshed
+			LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(
+				LLFloaterSidePanelContainer::getPanel("appearance"));
+			if (panel)
+			{
+				panel->showDefaultSubpart();
+			}
+		}
+	}
+}
+
+
 struct LLFoundData
 {
 	LLFoundData() :
@@ -593,6 +560,7 @@ class LLWearableHoldingPattern
 	bool isMostRecent();
 	void handleLateArrivals();
 	void resetTime(F32 timeout);
+	static S32 countActive() { return sActiveHoldingPatterns.size(); }
 	
 private:
 	found_list_t mFoundList;
@@ -1203,8 +1171,7 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
 									cat_array,
 									item_array,
 									false,
-									is_category,
-									false);
+									is_category);
 	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
 		 iter != item_array.end();
 		 iter++)
@@ -1270,8 +1237,12 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)
 	}
 }
 
-bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer<LLInventoryCallback> cb)
+bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear,
+									   bool do_update,
+									   bool replace,
+									   LLPointer<LLInventoryCallback> cb)
 {
+
 	if (item_id_to_wear.isNull()) return false;
 
 	// *TODO: issue with multi-wearable should be fixed:
@@ -1310,15 +1281,22 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
 	switch (item_to_wear->getType())
 	{
 	case LLAssetType::AT_CLOTHING:
-		if (gAgentWearables.areWearablesLoaded())
+	if (gAgentWearables.areWearablesLoaded())
 		{
+			if (!cb && do_update)
+			{
+				cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
+			}
 			S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType());
 			if ((replace && wearable_count != 0) ||
 				(wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) )
 			{
-				removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1));
+				LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
+																   wearable_count-1);
+				removeCOFItemLinks(item_id, cb);
 			}
-			addCOFItemLink(item_to_wear, do_update, cb);
+
+			addCOFItemLink(item_to_wear, cb);
 		} 
 		break;
 	case LLAssetType::AT_BODYPART:
@@ -1327,8 +1305,11 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
 		// Remove the existing wearables of the same type.
 		// Remove existing body parts anyway because we must not be able to wear e.g. two skins.
 		removeCOFLinksOfType(item_to_wear->getWearableType());
-
-		addCOFItemLink(item_to_wear, do_update, cb);
+		if (!cb && do_update)
+		{
+			cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear);
+		}
+		addCOFItemLink(item_to_wear, cb);
 		break;
 	case LLAssetType::AT_OBJECT:
 		rez_attachment(item_to_wear, NULL, replace);
@@ -1582,15 +1563,13 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id)
 // static
 bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id)
 {
-	LLInventoryModel::cat_array_t cats;
-	LLInventoryModel::item_array_t items;
+	if (gAgentWearables.isCOFChangeInProgress())
+	{
+		return false;
+	}
+
 	LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false);
-	gInventory.collectDescendentsIf(outfit_cat_id,
-		cats,
-		items,
-		LLInventoryModel::EXCLUDE_TRASH,
-		is_worn);
-	return items.size() > 0;
+	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, is_worn);
 }
 
 // static
@@ -1601,15 +1580,8 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id)
 		return false;
 	}
 
-	LLInventoryModel::cat_array_t cats;
-	LLInventoryModel::item_array_t items;
 	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false);
-	gInventory.collectDescendentsIf(outfit_cat_id,
-		cats,
-		items,
-		LLInventoryModel::EXCLUDE_TRASH,
-		not_worn);
-	return items.size() > 0;
+	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn);
 }
 
 bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
@@ -1627,18 +1599,11 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id)
 	}
 
 	// Check whether the outfit contains any wearables we aren't wearing already (STORM-702).
-	LLInventoryModel::cat_array_t cats;
-	LLInventoryModel::item_array_t items;
-	LLFindWearablesEx is_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
-	gInventory.collectDescendentsIf(outfit_cat_id,
-		cats,
-		items,
-		LLInventoryModel::EXCLUDE_TRASH,
-		is_worn);
-	return items.size() > 0;
+	LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ true);
+	return gInventory.hasMatchingDirectDescendent(outfit_cat_id, not_worn);
 }
 
-void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
+void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb)
 {
 	LLInventoryModel::cat_array_t cats;
 	LLInventoryModel::item_array_t items;
@@ -1649,43 +1614,11 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)
 		LLViewerInventoryItem *item = items.get(i);
 		if (item->getActualType() != LLAssetType::AT_LINK_FOLDER)
 			continue;
-		if (item->getIsLinkType())
-		{
-			LLViewerInventoryCategory* catp = item->getLinkedCategory();
-			if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
-			{
-				gInventory.purgeObject(item->getUUID());
-			}
-		}
-	}
-}
-
-void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items)
-{
-	LLInventoryModel::cat_array_t cats;
-	LLInventoryModel::item_array_t items;
-	gInventory.collectDescendents(category, cats, items,
-								  LLInventoryModel::EXCLUDE_TRASH);
-	for (S32 i = 0; i < items.count(); ++i)
-	{
-		LLViewerInventoryItem *item = items.get(i);
-		if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER))
-			continue;
-		if (item->getIsLinkType())
+		LLViewerInventoryCategory* catp = item->getLinkedCategory();
+		if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
 		{
-#if 0
-			if (keep_items && keep_items->find(item) != LLInventoryModel::item_array_t::FAIL)
-			{
-				llinfos << "preserved item" << llendl;
-			}
-			else
-			{
-				gInventory.purgeObject(item->getUUID());
-			}
-#else
-			gInventory.purgeObject(item->getUUID());
+			remove_inventory_item(item->getUUID(), cb);
 		}
-#endif
 	}
 }
 
@@ -1737,9 +1670,26 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
 	}
 }
 
+void LLAppearanceMgr::removeAll(LLInventoryModel::item_array_t& items_to_kill,
+							   LLPointer<LLInventoryCallback> cb)
+{
+	for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin();
+		 it != items_to_kill.end();
+		 ++it)
+	{
+		LLViewerInventoryItem *item = *it;
+		remove_inventory_item(item->getUUID(), cb);
+	}
+}
+
 void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 {
 	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
+	if (!pcat)
+	{
+		llwarns << "no category found for id " << category << llendl;
+		return;
+	}
 	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;
 
 	const LLUUID cof = getCOF();
@@ -1748,7 +1698,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	if (!append)
 	{
 		LLInventoryModel::item_array_t gest_items;
-		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false);
+		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);
 		for(S32 i = 0; i  < gest_items.count(); ++i)
 		{
 			LLViewerInventoryItem *gest_item = gest_items.get(i);
@@ -1765,8 +1715,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	// required parts are missing.
 	// Preserve body parts from COF if appending.
 	LLInventoryModel::item_array_t body_items;
-	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false);
-	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false);
+	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART);
+	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART);
 	if (append)
 		reverse(body_items.begin(), body_items.end());
 	// Reduce body items to max of one per type.
@@ -1776,8 +1726,8 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	// - Wearables: include COF contents only if appending.
 	LLInventoryModel::item_array_t wear_items;
 	if (append)
-		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false);
-	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
+		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING);
+	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING);
 	// Reduce wearables to max of one per type.
 	removeDuplicateItems(wear_items);
 	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
@@ -1785,15 +1735,15 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	// - Attachments: include COF contents only if appending.
 	LLInventoryModel::item_array_t obj_items;
 	if (append)
-		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false);
-	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false);
+		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
+	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT);
 	removeDuplicateItems(obj_items);
 
 	// - Gestures: include COF contents only if appending.
 	LLInventoryModel::item_array_t gest_items;
 	if (append)
-		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false);
-	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false);
+		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE);
+	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE);
 	removeDuplicateItems(gest_items);
 	
 	// Create links to new COF contents.
@@ -1805,6 +1755,7 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 
 	// Will link all the above items.
 	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+#if 0
 	linkAll(cof,all_items,link_waiter);
 
 	// Add link to outfit if category is an outfit. 
@@ -1817,9 +1768,41 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	// the link_waiter so links can be followed for any items that get
 	// carried over (e.g. keeping old shape if the new outfit does not
 	// contain one)
-	bool keep_outfit_links = append;
-	purgeCategory(cof, keep_outfit_links, &all_items);
-	gInventory.notifyObservers();
+
+	// even in the non-append case, createBaseOutfitLink() already
+	// deletes the existing link, don't need to do it again here.
+	bool keep_outfit_links = true;
+	remove_folder_contents(cof, keep_outfit_links, link_waiter);
+#else
+	LLSD contents = LLSD::emptyArray();
+	for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin();
+		 it != all_items.end(); ++it)
+	{
+		LLSD item_contents;
+		LLInventoryItem *item = *it;
+		item_contents["name"] = item->getName();
+		item_contents["desc"] = item->getActualDescription();
+		item_contents["linked_id"] = item->getLinkedUUID();
+		item_contents["type"] = LLAssetType::AT_LINK; 
+		contents.append(item_contents);
+	}
+	const LLUUID& base_id = append ? getBaseOutfitUUID() : category;
+	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id);
+	if (base_cat)
+	{
+		LLSD base_contents;
+		base_contents["name"] = base_cat->getName();
+		base_contents["desc"] = "";
+		base_contents["linked_id"] = base_cat->getLinkedUUID();
+		base_contents["type"] = LLAssetType::AT_LINK_FOLDER; 
+		contents.append(base_contents);
+	}
+	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+	{
+		dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents);
+	}
+	slam_inventory_folder(getCOF(), contents, link_waiter);
+#endif
 
 	LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;
 }
@@ -1840,7 +1823,7 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointer<LLI
 	LLViewerInventoryCategory* catp = gInventory.getCategory(category);
 	std::string new_outfit_name = "";
 
-	purgeBaseOutfitLink(cof);
+	purgeBaseOutfitLink(cof, link_waiter);
 
 	if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
 	{
@@ -1884,6 +1867,11 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
 	}
 }
 
+S32 LLAppearanceMgr::countActiveHoldingPatterns()
+{
+	return LLWearableHoldingPattern::countActive();
+}
+
 static void remove_non_link_items(LLInventoryModel::item_array_t &items)
 {
 	LLInventoryModel::item_array_t pruned_items;
@@ -1937,7 +1925,7 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
 	S32 to_kill_count = 0;
 
 	LLInventoryModel::item_array_t items;
-	getDescendentsOfAssetType(cat_id, items, type, false);
+	getDescendentsOfAssetType(cat_id, items, type);
 	LLInventoryModel::item_array_t curr_items = items;
 	removeDuplicateItems(items);
 	if (max_items > 0)
@@ -1956,34 +1944,34 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
 	return to_kill_count;
 }
 	
-												 
-void LLAppearanceMgr::enforceItemRestrictions()
-{
-	S32 purge_count = 0;
-	LLInventoryModel::item_array_t items_to_kill;
 
-	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART,
-											  1, items_to_kill);
-	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING,
-											  LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
-	purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT,
-											  -1, items_to_kill);
+void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id,
+													LLInventoryModel::item_array_t& items_to_kill)
+{
+	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART,
+							   1, items_to_kill);
+	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING,
+							   LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
+	findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT,
+							   -1, items_to_kill);
+}
 
+void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb)
+{
+	LLInventoryModel::item_array_t items_to_kill;
+	findAllExcessOrDuplicateItems(getCOF(), items_to_kill);
 	if (items_to_kill.size()>0)
 	{
-		for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin();
-			 it != items_to_kill.end();
-			 ++it)
-		{
-			LLViewerInventoryItem *item = *it;
-			LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL;
-			gInventory.purgeObject(item->getUUID());
-		}
-		gInventory.notifyObservers();
+		// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
+		// this should catch anything that gets through.
+		removeAll(items_to_kill, cb);
+		return;
 	}
 }
 
-void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
+void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering,
+											  bool enforce_item_restrictions,
+											  bool enforce_ordering)
 {
 	if (mIsInUpdateAppearanceFromCOF)
 	{
@@ -1991,19 +1979,38 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
 		return;
 	}
 
-	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
-	selfStartPhase("update_appearance_from_cof");
-
 	LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
 
-	//checking integrity of the COF in terms of ordering of wearables, 
-	//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
-	updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering);
+	if (enforce_item_restrictions)
+	{
+		// The point here is just to call
+		// updateAppearanceFromCOF() again after excess items
+		// have been removed. That time we will set
+		// enforce_item_restrictions to false so we don't get
+		// caught in a perpetual loop.
+		LLPointer<LLInventoryCallback> cb(
+			new LLUpdateAppearanceOnDestroy(update_base_outfit_ordering, false, enforce_ordering));
+		enforceCOFItemRestrictions(cb);
+		return;
+	}
+
+	if (enforce_ordering)
+	{
+		//checking integrity of the COF in terms of ordering of wearables, 
+		//checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
+
+		// As with enforce_item_restrictions handling above, we want
+		// to wait for the update callbacks, then (finally!) call
+		// updateAppearanceFromCOF() with no additional COF munging needed.
+		LLPointer<LLInventoryCallback> cb(
+			new LLUpdateAppearanceOnDestroy(false, false, false));
+		updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering, cb);
+		return;
+	}
+
+	BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
+	selfStartPhase("update_appearance_from_cof");
 
-	// Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
-	// this should catch anything that gets through.
-	enforceItemRestrictions();
-	
 	// update dirty flag to see if the state of the COF matches
 	// the saved outfit stored as a folder link
 	updateIsDirty();
@@ -2013,13 +2020,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
 	{
 		requestServerAppearanceUpdate();
 	}
-	// DRANO really should wait for the appearance message to set this.
-	// verify that deleting this line doesn't break anything.
-	//gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion());
-	
-	//dumpCat(getCOF(),"COF, start");
 
-	bool follow_folder_links = false;
 	LLUUID current_outfit_id = getCOF();
 
 	// Find all the wearables that are in the COF's subtree.
@@ -2027,7 +2028,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
 	LLInventoryModel::item_array_t wear_items;
 	LLInventoryModel::item_array_t obj_items;
 	LLInventoryModel::item_array_t gest_items;
-	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links);
+	getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items);
 	// Get rid of non-links in case somehow the COF was corrupted.
 	remove_non_link_items(wear_items);
 	remove_non_link_items(obj_items);
@@ -2123,8 +2124,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
 
 void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,
 													LLInventoryModel::item_array_t& items,
-													LLAssetType::EType type,
-													bool follow_folder_links)
+													LLAssetType::EType type)
 {
 	LLInventoryModel::cat_array_t cats;
 	LLIsType is_of_type(type);
@@ -2132,15 +2132,13 @@ void LLAppearanceMgr::getDescendentsOfAssetType(const LLUUID& category,
 									cats,
 									items,
 									LLInventoryModel::EXCLUDE_TRASH,
-									is_of_type,
-									follow_folder_links);
+									is_of_type);
 }
 
 void LLAppearanceMgr::getUserDescendents(const LLUUID& category, 
 											 LLInventoryModel::item_array_t& wear_items,
 											 LLInventoryModel::item_array_t& obj_items,
-											 LLInventoryModel::item_array_t& gest_items,
-											 bool follow_folder_links)
+											 LLInventoryModel::item_array_t& gest_items)
 {
 	LLInventoryModel::cat_array_t wear_cats;
 	LLFindWearables is_wearable;
@@ -2148,8 +2146,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,
 									wear_cats,
 									wear_items,
 									LLInventoryModel::EXCLUDE_TRASH,
-									is_wearable,
-									follow_folder_links);
+									is_wearable);
 
 	LLInventoryModel::cat_array_t obj_cats;
 	LLIsType is_object( LLAssetType::AT_OBJECT );
@@ -2157,8 +2154,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,
 									obj_cats,
 									obj_items,
 									LLInventoryModel::EXCLUDE_TRASH,
-									is_object,
-									follow_folder_links);
+									is_object);
 
 	// Find all gestures in this folder
 	LLInventoryModel::cat_array_t gest_cats;
@@ -2167,8 +2163,7 @@ void LLAppearanceMgr::getUserDescendents(const LLUUID& category,
 									gest_cats,
 									gest_items,
 									LLInventoryModel::EXCLUDE_TRASH,
-									is_gesture,
-									follow_folder_links);
+									is_gesture);
 }
 
 void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append)
@@ -2189,6 +2184,11 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
 														   category->getUUID(), copy, append));
 }
 
+S32 LLAppearanceMgr::getActiveCopyOperations() const
+{
+	return LLCallAfterInventoryCopyMgr::getInstanceCount(); 
+}
+
 void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append)
 {
 	LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL;
@@ -2287,6 +2287,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
 	LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append);
 }
 
+// FIXME do we really want to search entire inventory for matching name?
 void LLAppearanceMgr::wearOutfitByName(const std::string& name)
 {
 	LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL;
@@ -2340,9 +2341,8 @@ bool areMatchingWearables(const LLViewerInventoryItem *a, const LLViewerInventor
 class LLDeferredCOFLinkObserver: public LLInventoryObserver
 {
 public:
-	LLDeferredCOFLinkObserver(const LLUUID& item_id, bool do_update, LLPointer<LLInventoryCallback> cb = NULL, std::string description = ""):
+	LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, const std::string& description):
 		mItemID(item_id),
-		mDoUpdate(do_update),
 		mCallback(cb),
 		mDescription(description)
 	{
@@ -2358,14 +2358,13 @@ class LLDeferredCOFLinkObserver: public LLInventoryObserver
 		if (item)
 		{
 			gInventory.removeObserver(this);
-			LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback);
+			LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription);
 			delete this;
 		}
 	}
 
 private:
 	const LLUUID mItemID;
-	bool mDoUpdate;
 	std::string mDescription;
 	LLPointer<LLInventoryCallback> mCallback;
 };
@@ -2373,42 +2372,26 @@ class LLDeferredCOFLinkObserver: public LLInventoryObserver
 
 // BAP - note that this runs asynchronously if the item is not already loaded from inventory.
 // Dangerous if caller assumes link will exist after calling the function.
-void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description)
+void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id,
+									 LLPointer<LLInventoryCallback> cb,
+									 const std::string description)
 {
 	const LLInventoryItem *item = gInventory.getItem(item_id);
 	if (!item)
 	{
-		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb, description);
+		LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description);
 		gInventory.addObserver(observer);
 	}
 	else
 	{
-		addCOFItemLink(item, do_update, cb, description);
-	}
-}
-
-void modified_cof_cb(const LLUUID& inv_item)
-{
-	LLAppearanceMgr::instance().updateAppearanceFromCOF();
-
-	// Start editing the item if previously requested.
-	gAgentWearables.editWearableIfRequested(inv_item);
-
-	// TODO: camera mode may not be changed if a debug setting is tweaked
-	if( gAgentCamera.cameraCustomizeAvatar() )
-	{
-		// If we're in appearance editing mode, the current tab may need to be refreshed
-		LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(LLFloaterSidePanelContainer::getPanel("appearance"));
-		if (panel)
-		{
-			panel->showDefaultSubpart();
-		}
+		addCOFItemLink(item, cb, description);
 	}
 }
 
-void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer<LLInventoryCallback> cb, const std::string description)
+void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
+									 LLPointer<LLInventoryCallback> cb,
+									 const std::string description)
 {		
-	std::string link_description = description;
 	const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
 	if (!vitem)
 	{
@@ -2448,30 +2431,19 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
 			++count;
 			if (is_body_part && inv_item->getIsLinkType()  && (vitem->getWearableType() == wearable_type))
 			{
-				gInventory.purgeObject(inv_item->getUUID());
+				remove_inventory_item(inv_item->getUUID(), cb);
 			}
 			else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
 			{
 				// MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE
-				gInventory.purgeObject(inv_item->getUUID());
+				remove_inventory_item(inv_item->getUUID(), cb);
 			}
 		}
 	}
 
-	if (linked_already)
-	{
-		if (do_update)
-		{	
-			LLAppearanceMgr::updateAppearanceFromCOF();
-		}
-		return;
-	}
-	else
+	if (!linked_already)
 	{
-		if(do_update && cb.isNull())
-		{
-			cb = new LLBoostFuncInventoryCallback(modified_cof_cb);
-		}
+		std::string link_description = description;
 		if (vitem->getIsLinkType())
 		{
 			link_description = vitem->getActualDescription();
@@ -2484,7 +2456,6 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
 							 LLAssetType::AT_LINK,
 							 cb);
 	}
-	return;
 }
 
 LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id)
@@ -2524,8 +2495,7 @@ void LLAppearanceMgr::removeAllClothesFromAvatar()
 									dummy,
 									clothing_items,
 									LLInventoryModel::EXCLUDE_TRASH,
-									is_clothing,
-									false);
+									is_clothing);
 	uuid_vec_t item_ids;
 	for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin();
 		it != clothing_items.end(); ++it)
@@ -2569,7 +2539,7 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar()
 	removeItemsFromAvatar(ids_to_remove);
 }
 
-void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id)
+void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb)
 {
 	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
 
@@ -2584,12 +2554,12 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id)
 		const LLInventoryItem* item = item_array.get(i).get();
 		if (item->getIsLinkType() && item->getLinkedUUID() == item_id)
 		{
-			gInventory.purgeObject(item->getUUID());
+			remove_inventory_item(item->getUUID(), cb);
 		}
 	}
 }
 
-void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type)
+void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb)
 {
 	LLFindWearablesOfType filter_wearables_of_type(type);
 	LLInventoryModel::cat_array_t cats;
@@ -2602,7 +2572,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type)
 		const LLViewerInventoryItem* item = *it;
 		if (item->getIsLinkType()) // we must operate on links only
 		{
-			gInventory.purgeObject(item->getUUID());
+			remove_inventory_item(item->getUUID(), cb);
 		}
 	}
 }
@@ -2641,7 +2611,7 @@ void LLAppearanceMgr::updateIsDirty()
 
 	if (base_outfit.notNull())
 	{
-		LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK);
+		LLIsValidItemLink collector;
 
 		LLInventoryModel::cat_array_t cof_cats;
 		LLInventoryModel::item_array_t cof_items;
@@ -2655,6 +2625,7 @@ void LLAppearanceMgr::updateIsDirty()
 
 		if(outfit_items.count() != cof_items.count())
 		{
+			LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.count() << " cof " << cof_items.count() << llendl;
 			// Current outfit folder should have one more item than the outfit folder.
 			// this one item is the link back to the outfit folder itself.
 			mOutfitIsDirty = true;
@@ -2674,11 +2645,29 @@ void LLAppearanceMgr::updateIsDirty()
 				item1->getName() != item2->getName() ||
 				item1->getActualDescription() != item2->getActualDescription())
 			{
+				if (item1->getLinkedUUID() != item2->getLinkedUUID())
+				{
+					LL_DEBUGS("Avatar") << "link id different " << llendl;
+				}
+				else
+				{
+					if (item1->getName() != item2->getName())
+					{
+						LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << llendl;
+					}
+					if (item1->getActualDescription() != item2->getActualDescription())
+					{
+						LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription()
+											<< " " << item2->getActualDescription() << llendl;
+					}
+				}
 				mOutfitIsDirty = true;
 				return;
 			}
 		}
 	}
+	llassert(!mOutfitIsDirty);
+	LL_DEBUGS("Avatar") << "clean" << llendl;
 }
 
 // *HACK: Must match name in Library or agent inventory
@@ -2823,7 +2812,7 @@ bool LLAppearanceMgr::updateBaseOutfit()
 	updateClothingOrderingInfo();
 
 	// in a Base Outfit we do not remove items, only links
-	purgeCategory(base_outfit_id, false);
+	remove_folder_contents(base_outfit_id, false, NULL);
 
 	LLPointer<LLInventoryCallback> dirty_state_updater =
 		new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state);
@@ -2896,14 +2885,18 @@ struct WearablesOrderComparator
 		//items with ordering information but not for the associated wearables type
 		if (!item1_valid && item2_valid) 
 			return false;
+		else if (item1_valid && !item2_valid)
+			return true;
 
-		return true;
+		return item1->getName() < item2->getName();
 	}
 
 	U32 mControlSize;
 };
 
-void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering)
+void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,
+												 bool update_base_outfit_ordering,
+												 LLPointer<LLInventoryCallback> cb)
 {
 	if (cat_id.isNull())
 	{
@@ -2913,19 +2906,18 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
 			const LLUUID base_outfit_id = getBaseOutfitUUID();
 			if (base_outfit_id.notNull())
 			{
-				updateClothingOrderingInfo(base_outfit_id,false);
+				updateClothingOrderingInfo(base_outfit_id,false,cb);
 			}
 		}
 	}
 
 	// COF is processed if cat_id is not specified
 	LLInventoryModel::item_array_t wear_items;
-	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false);
+	getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING);
 
 	wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);
 	divvyWearablesByType(wear_items, items_by_type);
 
-	bool inventory_changed = false;
 	for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
 	{
 		
@@ -2944,126 +2936,77 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
 			std::string new_order_str = build_order_string((LLWearableType::EType)type, i);
 			if (new_order_str == item->getActualDescription()) continue;
 
-			item->setDescription(new_order_str);
-			item->setComplete(TRUE);
- 			item->updateServer(FALSE);
-			gInventory.updateItem(item);
-			
-			inventory_changed = true;
+			LLSD updates;
+			updates["desc"] = new_order_str;
+			update_inventory_item(item->getUUID(),updates,cb);
 		}
 	}
-
-	//*TODO do we really need to notify observers?
-	if (inventory_changed) gInventory.notifyObservers();
 }
 
-// This is intended for use with HTTP Clients/Responders, but is not
-// specifically coupled with those classes.
-class LLHTTPRetryPolicy: public LLThreadSafeRefCount
-{
-public:
-	LLHTTPRetryPolicy() {}
-	virtual ~LLHTTPRetryPolicy() {}
-	virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0;
-};
-
-// Example of simplest possible policy, not necessarily recommended.
-class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy
-{
-public:
-	LLAlwaysRetryImmediatelyPolicy() {}
-	bool shouldRetry(U32 status, F32& seconds_to_wait)
-	{
-		seconds_to_wait = 0.0;
-		return true;
-	}
-};
-
-// Very general policy with geometric back-off after failures,
-// up to a maximum delay, and maximum number of retries.
-class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy
-{
-public:
-	LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries):
-		mMinDelay(min_delay),
-		mMaxDelay(max_delay),
-		mBackoffFactor(backoff_factor),
-		mMaxRetries(max_retries),
-		mDelay(min_delay),
-		mRetryCount(0)
-	{
-	}
-
-	bool shouldRetry(U32 status, F32& seconds_to_wait)
-	{
-		seconds_to_wait = mDelay;
-		mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay);
-		mRetryCount++;
-		return (mRetryCount<=mMaxRetries);
-	}
-
-private:
-	F32 mMinDelay; // delay never less than this value
-	F32 mMaxDelay; // delay never exceeds this value
-	F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay.
-	U32 mMaxRetries; // maximum number of times shouldRetry will return true.
-	F32 mDelay; // current delay.
-	U32 mRetryCount; // number of times shouldRetry has been called.
-};
-
 class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
 {
+	LOG_CLASS(RequestAgentUpdateAppearanceResponder);
 public:
 	RequestAgentUpdateAppearanceResponder()
 	{
-		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
+		bool retry_on_4xx = true;
+		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx);
 	}
 
 	virtual ~RequestAgentUpdateAppearanceResponder()
 	{
 	}
 
+protected:
 	// Successful completion.
-	/* virtual */ void result(const LLSD& content)
+	/* virtual */ void httpSuccess()
 	{
-		LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL;
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		if (content["success"].asBoolean())
 		{
-			LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
+			//LL_DEBUGS("Avatar") << dumpResponse() << LL_ENDL;
 			if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 			{
-				dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
+				dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
 			}
 		}
 		else
 		{
-			onFailure(200);
+			failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content);
 		}
 	}
 
 	// Error
-	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	/*virtual*/ void httpFailure()
 	{
-		llwarns << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << llendl;
+		LL_WARNS("Avatar") << "appearance update request failed, status "
+						   << getStatus() << " reason " << getReason() << LL_ENDL;
+
 		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 		{
-			dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
+			const LLSD& content = getContent();
+			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
 			debugCOF(content);
-		
 		}
-		onFailure(status);
-	}	
+		onFailure();
+	}
 
-	void onFailure(U32 status)
+	void onFailure()
 	{
 		F32 seconds_to_wait;
-		if (mRetryPolicy->shouldRetry(status,seconds_to_wait))
+		mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
+		if (mRetryPolicy->shouldRetry(seconds_to_wait))
 		{
 			llinfos << "retrying" << llendl;
 			doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate,
 										LLAppearanceMgr::getInstance(),
-										LLCurl::ResponderPtr(this)),
-							seconds_to_wait);
+										LLHTTPClient::ResponderPtr(this)),
+										seconds_to_wait);
 		}
 		else
 		{
@@ -3071,18 +3014,10 @@ class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
 		}
 	}	
 
-	void dumpContents(const std::string outprefix, const LLSD& content)
-	{
-		std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml");
-		std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
-		std::ofstream ofs(fullpath.c_str(), std::ios_base::out);
-		ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY);
-		LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL;
-	}
-
 	void debugCOF(const LLSD& content)
 	{
-		LL_DEBUGS("Avatar") << "AIS COF, version found: " << content["expected"].asInteger() << llendl;
+		LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
+						   << " ================================= " << llendl;
 		std::set<LLUUID> ais_items, local_items;
 		const LLSD& cof_raw = content["cof_raw"];
 		for (LLSD::array_const_iterator it = cof_raw.beginArray();
@@ -3094,30 +3029,32 @@ class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
 				ais_items.insert(item["item_id"].asUUID());
 				if (item["type"].asInteger() == 24) // link
 				{
-					LL_DEBUGS("Avatar") << "Link: item_id: " << item["item_id"].asUUID()
-										<< " linked_item_id: " << item["asset_id"].asUUID()
-										<< " name: " << item["name"].asString()
-										<< llendl; 
+					LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID()
+									   << " linked_item_id: " << item["asset_id"].asUUID()
+									   << " name: " << item["name"].asString()
+									   << llendl; 
 				}
 				else if (item["type"].asInteger() == 25) // folder link
 				{
-					LL_DEBUGS("Avatar") << "Folder link: item_id: " << item["item_id"].asUUID()
-										<< " linked_item_id: " << item["asset_id"].asUUID()
-										<< " name: " << item["name"].asString()
-										<< llendl; 
+					LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID()
+									   << " linked_item_id: " << item["asset_id"].asUUID()
+									   << " name: " << item["name"].asString()
+									   << llendl; 
 					
 				}
 				else
 				{
-					LL_DEBUGS("Avatar") << "Other: item_id: " << item["item_id"].asUUID()
-										<< " linked_item_id: " << item["asset_id"].asUUID()
-										<< " name: " << item["name"].asString()
-										<< llendl; 
+					LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID()
+									   << " linked_item_id: " << item["asset_id"].asUUID()
+									   << " name: " << item["name"].asString()
+									   << " type: " << item["type"].asInteger()
+									   << llendl; 
 				}
 			}
 		}
-		LL_DEBUGS("Avatar") << llendl;
-		LL_DEBUGS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() << llendl;
+		LL_INFOS("Avatar") << llendl;
+		LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() 
+						   << " ================================= " << llendl;
 		LLInventoryModel::cat_array_t cat_array;
 		LLInventoryModel::item_array_t item_array;
 		gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
@@ -3126,26 +3063,37 @@ class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
 		{
 			const LLViewerInventoryItem* inv_item = item_array.get(i).get();
 			local_items.insert(inv_item->getUUID());
-			LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID()
-								<< " linked_item_id: " << inv_item->getLinkedUUID()
-								<< " name: " << inv_item->getName()
-								<< llendl;
-		}
-		LL_DEBUGS("Avatar") << llendl;
+			LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID()
+							   << " linked_item_id: " << inv_item->getLinkedUUID()
+							   << " name: " << inv_item->getName()
+							   << " parent: " << inv_item->getParentUUID()
+							   << llendl;
+		}
+		LL_INFOS("Avatar") << " ================================= " << llendl;
+		S32 local_only = 0, ais_only = 0;
 		for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
 		{
 			if (ais_items.find(*it) == ais_items.end())
 			{
-				LL_DEBUGS("Avatar") << "LOCAL ONLY: " << *it << llendl;
+				LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << llendl;
+				local_only++;
 			}
 		}
 		for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
 		{
 			if (local_items.find(*it) == local_items.end())
 			{
-				LL_DEBUGS("Avatar") << "AIS ONLY: " << *it << llendl;
+				LL_INFOS("Avatar") << "AIS ONLY: " << *it << llendl;
+				ais_only++;
 			}
 		}
+		if (local_only==0 && ais_only==0)
+		{
+			LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req "
+							   << content["observed"].asInteger()
+							   << " rcv " << content["expected"].asInteger()
+							   << ")" << llendl;
+		}
 	}
 
 	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
@@ -3254,7 +3202,6 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond
 	}
 	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl;
 	
-	//LLCurl::ResponderPtr responder_ptr;
 	if (!responder_ptr.get())
 	{
 		responder_ptr = new RequestAgentUpdateAppearanceResponder;
@@ -3266,6 +3213,7 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond
 
 class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLIncrementCofVersionResponder);
 public:
 	LLIncrementCofVersionResponder() : LLHTTPClient::Responder()
 	{
@@ -3276,22 +3224,31 @@ class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
 	{
 	}
 
-	virtual void result(const LLSD &pContent)
+protected:
+	virtual void httpSuccess()
 	{
 		llinfos << "Successfully incremented agent's COF." << llendl;
-		S32 new_version = pContent["category"]["version"].asInteger();
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
+		S32 new_version = content["category"]["version"].asInteger();
 
 		// cof_version should have increased
 		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion);
 
 		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version;
 	}
-	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& content)
+
+	virtual void httpFailure()
 	{
-		llwarns << "While attempting to increment the agent's cof we got an error with [status:"
-				<< pStatus << "]: " << content << llendl;
+		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error "
+				<< dumpResponse() << LL_ENDL;
 		F32 seconds_to_wait;
-		if (mRetryPolicy->shouldRetry(pStatus,seconds_to_wait))
+		mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
+		if (mRetryPolicy->shouldRetry(seconds_to_wait))
 		{
 			llinfos << "retrying" << llendl;
 			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion,
@@ -3305,6 +3262,7 @@ class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
 		}
 	}
 
+private:
 	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
 };
 
@@ -3337,6 +3295,15 @@ void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_p
 	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);
 }
 
+U32 LLAppearanceMgr::getNumAttachmentsInCOF()
+{
+	const LLUUID cof = getCOF();
+	LLInventoryModel::item_array_t obj_items;
+	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
+	return obj_items.size();
+}
+
+
 std::string LLAppearanceMgr::getAppearanceServiceURL() const
 {
 	if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty())
@@ -3373,6 +3340,13 @@ void show_created_outfit(LLUUID& folder_id, bool show_panel = true)
 	LLAppearanceMgr::getInstance()->updateIsDirty();
 	gAgentWearables.notifyLoadingFinished(); // New outfit is saved.
 	LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
+
+	// For SSB, need to update appearance after we add a base outfit
+	// link, since, the COF version has changed. There is a race
+	// condition in initial outfit setup which can lead to rez
+	// failures - SH-3860.
+	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
+	LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb);
 }
 
 LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
@@ -3393,7 +3367,6 @@ LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, b
 	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(no_op_inventory_func,
 																		 boost::bind(show_created_outfit,folder_id,show_panel));
 	shallowCopyCategoryContents(getCOF(),folder_id, cb);
-	createBaseOutfitLink(folder_id, cb);
 
 	dumpCat(folder_id,"COF, new outfit");
 
@@ -3413,21 +3386,22 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
 	if (ids_to_remove.empty())
 	{
 		llwarns << "called with empty list, nothing to do" << llendl;
+		return;
 	}
+	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
 	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
 	{
 		const LLUUID& id_to_remove = *it;
 		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
-		removeCOFItemLinks(linked_item_id);
+		removeCOFItemLinks(linked_item_id, cb);
 	}
-	updateAppearanceFromCOF();
 }
 
 void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
 {
 	LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove);
-	removeCOFItemLinks(linked_item_id);
-	updateAppearanceFromCOF();
+	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
+	removeCOFItemLinks(linked_item_id, cb);
 }
 
 bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
@@ -3586,7 +3560,7 @@ void LLAppearanceMgr::registerAttachment(const LLUUID& item_id)
 		   // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF.
 		   // it will trigger gAgentWariables.notifyLoadingFinished()
 		   // But it is not acceptable solution. See EXT-7777
-		   LLAppearanceMgr::addCOFItemLink(item_id, false);  // Add COF link for item.
+		   LLAppearanceMgr::addCOFItemLink(item_id);  // Add COF link for item.
 	   }
 	   else
 	   {
@@ -3610,22 +3584,21 @@ void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id)
 
 BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
 {
-	return gInventory.isObjectDescendentOf(obj_id, getCOF());
+	const LLUUID& cof = getCOF();
+	if (obj_id == cof)
+		return TRUE;
+	const LLInventoryObject* obj = gInventory.getObject(obj_id);
+	if (obj && obj->getParentUUID() == cof)
+		return TRUE;
+	return FALSE;
 }
 
 // static
 bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id)
 {
-	 LLInventoryModel::cat_array_t cats;
-	 LLInventoryModel::item_array_t items;
-	 LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id));
-	 gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(),
-									 cats,
-									 items,
-	 LLInventoryModel::EXCLUDE_TRASH,
-	 find_links);
-
-	 return !items.empty();
+	const LLUUID& target_id = gInventory.getLinkedItemID(obj_id);
+	LLLinkedItemIDMatches find_links(target_id);
+	return gInventory.hasMatchingDirectDescendent(LLAppearanceMgr::instance().getCOF(), find_links);
 }
 
 BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
@@ -3642,18 +3615,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
 	// For now, don't allow direct deletion from the COF.  Instead, force users
 	// to choose "Detach" or "Take Off".
 	return TRUE;
-	/*
-	const LLInventoryObject *obj = gInventory.getObject(obj_id);
-	if (!obj) return FALSE;
-
-	// Can't delete bodyparts, since this would be equivalent to removing the item.
-	if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE;
-
-	// Can't delete the folder link, since this is saved for bookkeeping.
-	if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE;
-
-	return FALSE;
-	*/
 }
 
 class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 46252afbde14799662de45582dbf63150c1f819d..9eb26767c4711553ff1ff9db08d9eb9d20192e89 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -49,7 +49,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 public:
 	typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
 
-	void updateAppearanceFromCOF(bool update_base_outfit_ordering = false);
+	void updateAppearanceFromCOF(bool update_base_outfit_ordering = false,
+								 bool enforce_item_restrictions = true,
+								 bool enforce_ordering = true);
 	bool needToSaveCOF();
 	void updateCOF(const LLUUID& category, bool append = false);
 	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
@@ -65,8 +67,12 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 								   LLAssetType::EType type,
 								   S32 max_items,
 								   LLInventoryModel::item_array_t& items_to_kill);
-	void enforceItemRestrictions();
+	void findAllExcessOrDuplicateItems(const LLUUID& cat_id,
+									  LLInventoryModel::item_array_t& items_to_kill);
+	void enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb);
 
+	S32 getActiveCopyOperations() const;
+	
 	// Copy all items and the src category itself.
 	void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
 							 LLPointer<LLInventoryCallback> cb);
@@ -105,16 +111,19 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 	const LLUUID getBaseOutfitUUID();
 
 	// Wear/attach an item (from a user's inventory) on the agent
-	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer<LLInventoryCallback> cb = NULL);
+	bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false,
+						  LLPointer<LLInventoryCallback> cb = NULL);
 
 	// Update the displayed outfit name in UI.
 	void updatePanelOutfitName(const std::string& name);
 
-	void purgeBaseOutfitLink(const LLUUID& category);
+	void purgeBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> cb = NULL);
 	void createBaseOutfitLink(const LLUUID& category, LLPointer<LLInventoryCallback> link_waiter);
 
 	void updateAgentWearables(LLWearableHoldingPattern* holder, bool append);
 
+	S32 countActiveHoldingPatterns();
+
 	// For debugging - could be moved elsewhere.
 	void dumpCat(const LLUUID& cat_id, const std::string& msg);
 	void dumpItemArray(const LLInventoryModel::item_array_t& items, const std::string& msg);
@@ -129,16 +138,20 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 				 LLInventoryModel::item_array_t& items,
 				 LLPointer<LLInventoryCallback> cb);
 
+	// And bulk removal.
+	void removeAll(LLInventoryModel::item_array_t& items,
+				   LLPointer<LLInventoryCallback> cb);
+
 	// Add COF link to individual item.
-	void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");
-	void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");
+	void addCOFItemLink(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");
+	void addCOFItemLink(const LLInventoryItem *item, LLPointer<LLInventoryCallback> cb = NULL, const std::string description = "");
 
 	// Find COF entries referencing the given item.
 	LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id);
 
 	// Remove COF entries
-	void removeCOFItemLinks(const LLUUID& item_id);
-	void removeCOFLinksOfType(LLWearableType::EType type);
+	void removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb = NULL);
+	void removeCOFLinksOfType(LLWearableType::EType type, LLPointer<LLInventoryCallback> cb = NULL);
 	void removeAllClothesFromAvatar();
 	void removeAllAttachmentsFromAvatar();
 
@@ -183,7 +196,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 
 	//Check ordering information on wearables stored in links' descriptions and update if it is invalid
 	// COF is processed if cat_id is not specified
-	void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false);
+	void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null,
+									bool update_base_outfit_ordering = false,
+									LLPointer<LLInventoryCallback> cb = NULL);
 
 	bool isOutfitLocked() { return mOutfitLocked; }
 
@@ -193,6 +208,8 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 
 	void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL);
 
+	U32 getNumAttachmentsInCOF();
+
 	// *HACK Remove this after server side texture baking is deployed on all sims.
 	void incrementCofVersionLegacy();
 
@@ -213,16 +230,13 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 	
 	void getDescendentsOfAssetType(const LLUUID& category, 
 										  LLInventoryModel::item_array_t& items,
-										  LLAssetType::EType type,
-										  bool follow_folder_links);
+										  LLAssetType::EType type);
 
 	void getUserDescendents(const LLUUID& category, 
 								   LLInventoryModel::item_array_t& wear_items,
 								   LLInventoryModel::item_array_t& obj_items,
-								   LLInventoryModel::item_array_t& gest_items,
-								   bool follow_folder_links);
+								   LLInventoryModel::item_array_t& gest_items);
 
-	void purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items = NULL);
 	static void onOutfitRename(const LLSD& notification, const LLSD& response);
 
 	void setOutfitLocked(bool locked);
@@ -256,15 +270,33 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 class LLUpdateAppearanceOnDestroy: public LLInventoryCallback
 {
 public:
-	LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false);
+	LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false,
+								bool enforce_item_restrictions = true,
+								bool enforce_ordering = true);
 	virtual ~LLUpdateAppearanceOnDestroy();
 	/* virtual */ void fire(const LLUUID& inv_item);
 
 private:
 	U32 mFireCount;
 	bool mUpdateBaseOrder;
+	bool mEnforceItemRestrictions;
+	bool mEnforceOrdering;
+};
+
+class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback
+{
+public:
+	LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id);
+
+	/* virtual */ void fire(const LLUUID& item_id) {}
+
+	~LLUpdateAppearanceAndEditWearableOnDestroy();
+	
+private:
+	LLUUID mItemID;
 };
 
+class 
 
 #define SUPPORT_ENSEMBLES 0
 
diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp
index 4bdb690225d6b871876ceb0e5a33de65fcf81086..cde9bc9dc08b77a3deb52da853afabd32c702584 100755
--- a/indra/newview/llassetuploadqueue.cpp
+++ b/indra/newview/llassetuploadqueue.cpp
@@ -36,6 +36,7 @@
 
 class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder
 {
+	LOG_CLASS(LLAssetUploadChainResponder);
 public:
 	
 	LLAssetUploadChainResponder(const LLSD& post_data,
@@ -51,52 +52,54 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder
 		mDataSize(data_size),
 		mScriptName(script_name)
 	{
- 	}
+	}
 
 	virtual ~LLAssetUploadChainResponder() 
-   	{
-   		if(mSupplier)
-   		{
-   			LLAssetUploadQueue *queue = mSupplier->get();
-   			if (queue)
-   			{
-   				// Give ownership of supplier back to queue.
-   				queue->mSupplier = mSupplier;
-   				mSupplier = NULL;
-   			}
-   		}
-   		delete mSupplier;
+	{
+		if(mSupplier)
+		{
+			LLAssetUploadQueue *queue = mSupplier->get();
+			if (queue)
+			{
+				// Give ownership of supplier back to queue.
+				queue->mSupplier = mSupplier;
+				mSupplier = NULL;
+			}
+		}
+		delete mSupplier;
 		delete mData;
-   	}
+	}
 	
-	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
-   	{
-		llwarns << "LLAssetUploadChainResponder Error [status:" 
-				<< statusNum << "]: " << content << llendl;
-		LLUpdateTaskInventoryResponder::errorWithContent(statusNum, reason, content);
-   		LLAssetUploadQueue *queue = mSupplier->get();
-   		if (queue)
+protected:
+	virtual void httpFailure()
+	{
+		// Parent class will spam the failure.
+		//llwarns << dumpResponse() << llendl;
+		LLUpdateTaskInventoryResponder::httpFailure();
+		LLAssetUploadQueue *queue = mSupplier->get();
+		if (queue)
+		{
+			queue->request(&mSupplier);
+		}
+	}
+
+	virtual void httpSuccess()
+	{
+		LLUpdateTaskInventoryResponder::httpSuccess();
+		LLAssetUploadQueue *queue = mSupplier->get();
+		if (queue)
 		{
-   			queue->request(&mSupplier);
-   		}
-   	}
-
-	virtual void result(const LLSD& content)
-   	{
-		LLUpdateTaskInventoryResponder::result(content);
-   		LLAssetUploadQueue *queue = mSupplier->get();
-   		if (queue)
-   		{
-   			// Responder is reused across 2 phase upload,
-   			// so only start next upload after 2nd phase complete.
-   			std::string state = content["state"];
-   			if(state == "complete")
-   			{
-   				queue->request(&mSupplier);
-   			}
-   		}	
-   	}
+			// Responder is reused across 2 phase upload,
+			// so only start next upload after 2nd phase complete.
+			const std::string& state = getContent()["state"].asStringRef();
+			if(state == "complete")
+			{
+				queue->request(&mSupplier);
+			}
+		}
+	}
 	
+public:
 	virtual void uploadUpload(const LLSD& content)
 	{
 		std::string uploader = content["uploader"];
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index 25648023879a9ee2e99ddd17f04df74292e4fcd7..ea511b18e2de5d8dfb74619018e9206778c8eb48 100755
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -225,37 +225,41 @@ LLAssetUploadResponder::~LLAssetUploadResponder()
 }
 
 // virtual
-void LLAssetUploadResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+void LLAssetUploadResponder::httpFailure()
 {
-	llinfos << "LLAssetUploadResponder::error [status:" 
-			<< statusNum << "]: " << content << llendl;
+	// *TODO: Add adaptive retry policy?
+	llwarns << dumpResponse() << llendl;
 	LLSD args;
-	switch(statusNum)
+	if (isHttpClientErrorStatus(getStatus()))
 	{
-		case 400:
-			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
-			args["REASON"] = "Error in upload request.  Please visit "
-				"http://secondlife.com/support for help fixing this problem.";
-			LLNotificationsUtil::add("CannotUploadReason", args);
-			break;
-		case 500:
-		default:
-			args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
-			args["REASON"] = "The server is experiencing unexpected "
-				"difficulties.";
-			LLNotificationsUtil::add("CannotUploadReason", args);
-			break;
+		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
+		args["REASON"] = "Error in upload request.  Please visit "
+			"http://secondlife.com/support for help fixing this problem.";
+		LLNotificationsUtil::add("CannotUploadReason", args);
+	}
+	else
+	{
+		args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
+		args["REASON"] = "The server is experiencing unexpected "
+			"difficulties.";
+		LLNotificationsUtil::add("CannotUploadReason", args);
 	}
 	LLUploadDialog::modalUploadFinished();
 	LLFilePicker::instance().reset();  // unlock file picker when bulk upload fails
 }
 
 //virtual 
-void LLAssetUploadResponder::result(const LLSD& content)
+void LLAssetUploadResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
 
-	std::string state = content["state"];
+	const std::string& state = content["state"].asStringRef();
 
 	if (state == "upload")
 	{
@@ -280,7 +284,7 @@ void LLAssetUploadResponder::result(const LLSD& content)
 
 void LLAssetUploadResponder::uploadUpload(const LLSD& content)
 {
-	std::string uploader = content["uploader"];
+	const std::string& uploader = content["uploader"].asStringRef();
 	if (mFileName.empty())
 	{
 		LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this);
@@ -293,6 +297,7 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content)
 
 void LLAssetUploadResponder::uploadFailure(const LLSD& content)
 {
+	llwarns << dumpResponse() << llendl;
 	// remove the "Uploading..." message
 	LLUploadDialog::modalUploadFinished();
 	LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
@@ -301,7 +306,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content)
 		floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory")));
 	}
 	
-	std::string reason = content["state"];
+	const std::string& reason = content["state"].asStringRef();
 	// deal with L$ errors
 	if (reason == "insufficient funds")
 	{
@@ -340,9 +345,9 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
 }
 
 // virtual
-void LLNewAgentInventoryResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+void LLNewAgentInventoryResponder::httpFailure()
 {
-	LLAssetUploadResponder::errorWithContent(statusNum, reason, content);
+	LLAssetUploadResponder::httpFailure();
 	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);
 }
 
@@ -487,10 +492,9 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
 	}
 }
 
-void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+void LLSendTexLayerResponder::httpFailure()
 {
-	llinfos << "LLSendTexLayerResponder error [status:"
-			<< statusNum << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 	
 	// Invoke the original callback with an error result
 	LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
@@ -1009,19 +1013,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp
 	delete mImpl;
 }
 
-void LLNewAgentInventoryVariablePriceResponder::errorWithContent(
-	U32 statusNum,
-	const std::string& reason,
-	const LLSD& content)
+void LLNewAgentInventoryVariablePriceResponder::httpFailure()
 {
-	lldebugs 
-		<< "LLNewAgentInventoryVariablePrice::error " << statusNum 
-		<< " reason: " << reason << llendl;
+	const LLSD& content = getContent();
+	LL_WARNS("Upload") << dumpResponse() << LL_ENDL;
 
-	if ( content.has("error") )
+	static const std::string _ERROR = "error";
+	if ( content.has(_ERROR) )
 	{
-		static const std::string _ERROR = "error";
-
 		mImpl->onTransportError(content[_ERROR]);
 	}
 	else
@@ -1030,8 +1029,14 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent(
 	}
 }
 
-void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)
+void LLNewAgentInventoryVariablePriceResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	// Parse out application level errors and the appropriate
 	// responses for them
 	static const std::string _ERROR = "error";
@@ -1047,6 +1052,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)
 	// Check for application level errors
 	if ( content.has(_ERROR) )
 	{
+		LL_WARNS("Upload") << dumpResponse() << LL_ENDL;
 		onApplicationLevelError(content[_ERROR]);
 		return;
 	}
@@ -1090,6 +1096,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)
 	}
 	else
 	{
+		LL_WARNS("Upload") << dumpResponse() << LL_ENDL;
 		onApplicationLevelError("");
 	}
 }
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index a6d1016136c6a49f86578e4077bf1acc010a822d..abfdc4ca7712e84a2555d48dd78032d7f3a9aab3 100755
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -33,6 +33,8 @@
 // via capabilities
 class LLAssetUploadResponder : public LLHTTPClient::Responder
 {
+protected:
+	LOG_CLASS(LLAssetUploadResponder);
 public:
 	LLAssetUploadResponder(const LLSD& post_data,
 							const LLUUID& vfile_id,
@@ -42,8 +44,11 @@ class LLAssetUploadResponder : public LLHTTPClient::Responder
 							LLAssetType::EType asset_type);
 	~LLAssetUploadResponder();
 
-    virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content);
-	virtual void result(const LLSD& content);
+protected:
+	virtual void httpFailure();
+	virtual void httpSuccess();
+
+public:
 	virtual void uploadUpload(const LLSD& content);
 	virtual void uploadComplete(const LLSD& content);
 	virtual void uploadFailure(const LLSD& content);
@@ -58,6 +63,7 @@ class LLAssetUploadResponder : public LLHTTPClient::Responder
 // TODO*: Remove this once deprecated
 class LLNewAgentInventoryResponder : public LLAssetUploadResponder
 {
+	LOG_CLASS(LLNewAgentInventoryResponder);
 public:
 	LLNewAgentInventoryResponder(
 		const LLSD& post_data,
@@ -67,9 +73,10 @@ class LLNewAgentInventoryResponder : public LLAssetUploadResponder
 		const LLSD& post_data,
 		const std::string& file_name,
 		LLAssetType::EType asset_type);
-    virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content);
 	virtual void uploadComplete(const LLSD& content);
 	virtual void uploadFailure(const LLSD& content);
+protected:
+	virtual void httpFailure();
 };
 
 // A base class which goes through and performs some default
@@ -79,6 +86,7 @@ class LLNewAgentInventoryResponder : public LLAssetUploadResponder
 class LLNewAgentInventoryVariablePriceResponder :
 	public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLNewAgentInventoryVariablePriceResponder);
 public:
 	LLNewAgentInventoryVariablePriceResponder(
 		const LLUUID& vfile_id,
@@ -91,12 +99,11 @@ class LLNewAgentInventoryVariablePriceResponder :
 		const LLSD& inventory_info);
 	virtual ~LLNewAgentInventoryVariablePriceResponder();
 
-	void errorWithContent(
-		U32 statusNum,
-		const std::string& reason,
-		const LLSD& content);
-	void result(const LLSD& content);
+private:
+	/* virtual */ void httpFailure();
+	/* virtual */ void httpSuccess();
 
+public:
 	virtual void onApplicationLevelError(
 		const LLSD& error);
 	virtual void showConfirmationDialog(
@@ -122,8 +129,11 @@ class LLSendTexLayerResponder : public LLAssetUploadResponder
 	~LLSendTexLayerResponder();
 
 	virtual void uploadComplete(const LLSD& content);
-	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content);
 
+protected:
+	virtual void httpFailure();
+
+private:
 	LLBakedUploadData * mBakedUploadData;
 };
 
diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp
index e3cd83e174211bc4bcd997285adf96c93fedf899..923662e8872539f8da86368114b33fbb1e17c633 100755
--- a/indra/newview/llclassifiedstatsresponder.cpp
+++ b/indra/newview/llclassifiedstatsresponder.cpp
@@ -44,8 +44,14 @@ mClassifiedID(classified_id)
 }
 
 /*virtual*/
-void LLClassifiedStatsResponder::result(const LLSD& content)
+void LLClassifiedStatsResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	S32 teleport = content["teleport_clicks"].asInteger();
 	S32 map = content["map_clicks"].asInteger();
 	S32 profile = content["profile_clicks"].asInteger();
@@ -62,7 +68,8 @@ void LLClassifiedStatsResponder::result(const LLSD& content)
 }
 
 /*virtual*/
-void LLClassifiedStatsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLClassifiedStatsResponder::httpFailure()
 {
-	llinfos << "LLClassifiedStatsResponder::error [status:" << status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 }
+
diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h
index 06dcb62fd055e6ad4fadf8ccdae343e01602c920..efa4d82411d2df7dd4d598476a02ef107ed206d9 100755
--- a/indra/newview/llclassifiedstatsresponder.h
+++ b/indra/newview/llclassifiedstatsresponder.h
@@ -33,13 +33,15 @@
 
 class LLClassifiedStatsResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLClassifiedStatsResponder);
 public:
 	LLClassifiedStatsResponder(LLUUID classified_id);
+
+protected:
 	//If we get back a normal response, handle it here
-	virtual void result(const LLSD& content);
+	virtual void httpSuccess();
 	//If we get back an error (not found, etc...), handle it here
-	
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+	virtual void httpFailure();
 
 protected:
 	LLUUID mClassifiedID;
diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp
index 2669b0340fbef96ce1b72b8114fda1c77326d13a..db2c15a4444a0351ab198321cbceabbf5dc6b86a 100755
--- a/indra/newview/llestateinfomodel.cpp
+++ b/indra/newview/llestateinfomodel.cpp
@@ -112,19 +112,19 @@ void LLEstateInfoModel::notifyCommit()
 
 class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
 {
-public:
-
+	LOG_CLASS(LLEstateChangeInfoResponder);
+protected:
 	// if we get a normal response, handle it here
-	virtual void result(const LLSD& content)
+	virtual void httpSuccesss()
 	{
 		llinfos << "Committed estate info" << llendl;
 		LLEstateInfoModel::instance().notifyCommit();
 	}
 
 	// if we get an error response
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	virtual void httpFailure()
 	{
-		llwarns << "Failed to commit estate info [status:" << status << "]: " << content << llendl;
+		llwarns << "Failed to commit estate info " << dumpResponse() << llendl;
 	}
 };
 
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index e0f7223a8ce745949d1ee8c60df93da53f322f74..c3b53d5e4aa617fbfd9f820a50190af0258fd9a0 100755
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -31,7 +31,7 @@
 #include "llagent.h"
 
 #include "llhttpclient.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 #include "llsdserialize.h"
 #include "lleventtimer.h"
 #include "llviewerregion.h"
@@ -49,6 +49,7 @@ namespace
 
 	class LLEventPollResponder : public LLHTTPClient::Responder
 	{
+		LOG_CLASS(LLEventPollResponder);
 	public:
 		
 		static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
@@ -56,19 +57,19 @@ namespace
 		
 		void makeRequest();
 
+		/* virtual */ void completedRaw(const LLChannelDescriptors& channels,
+								  const LLIOPipe::buffer_ptr_t& buffer);
+
 	private:
 		LLEventPollResponder(const std::string&	pollURL, const LLHost& sender);
 		~LLEventPollResponder();
 
 		
 		void handleMessage(const LLSD& content);
-		virtual	void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-		virtual	void result(const LLSD&	content);
 
-		virtual void completedRaw(U32 status,
-									const std::string& reason,
-									const LLChannelDescriptors& channels,
-									const LLIOPipe::buffer_ptr_t& buffer);
+		/* virtual */ void httpFailure();
+		/* virtual */ void httpSuccess();
+
 	private:
 
 		bool	mDone;
@@ -149,20 +150,18 @@ namespace
 	}
 
 	// virtual 
-	void LLEventPollResponder::completedRaw(U32 status,
-									const std::string& reason,
-									const LLChannelDescriptors& channels,
-									const LLIOPipe::buffer_ptr_t& buffer)
+	void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels,
+											const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		if (status == HTTP_BAD_GATEWAY)
+		if (getStatus() == HTTP_BAD_GATEWAY)
 		{
 			// These errors are not parsable as LLSD, 
 			// which LLHTTPClient::Responder::completedRaw will try to do.
-			completed(status, reason, LLSD());
+			httpCompleted();
 		}
 		else
 		{
-			LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer);
+			LLHTTPClient::Responder::completedRaw(channels,buffer);
 		}
 	}
 
@@ -187,13 +186,13 @@ namespace
 	}
 
 	//virtual
-	void LLEventPollResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	void LLEventPollResponder::httpFailure()
 	{
 		if (mDone) return;
 
 		// A HTTP_BAD_GATEWAY (502) error is our standard timeout response
 		// we get this when there are no events.
-		if ( status == HTTP_BAD_GATEWAY )	
+		if ( getStatus() == HTTP_BAD_GATEWAY )
 		{
 			mErrorCount = 0;
 			makeRequest();
@@ -207,12 +206,12 @@ namespace
 										+ mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
 									, this);
 
-			llwarns << "LLEventPollResponder error [status:" << status << "]: " << content << llendl;
+			llwarns << dumpResponse() << llendl;
 		}
 		else
 		{
-			llwarns << "LLEventPollResponder error <" << mCount 
-					<< "> [status:" << status << "]: " << content
+			llwarns << dumpResponse()
+					<< " [count:" << mCount << "] "
 					<< (mDone ? " -- done" : "") << llendl;
 			stop();
 
@@ -234,7 +233,7 @@ namespace
 	}
 
 	//virtual
-	void LLEventPollResponder::result(const LLSD& content)
+	void LLEventPollResponder::httpSuccess()
 	{
 		lldebugs <<	"LLEventPollResponder::result <" << mCount	<< ">"
 				 <<	(mDone ? " -- done"	: "") << llendl;
@@ -243,10 +242,12 @@ namespace
 
 		mErrorCount = 0;
 
-		if (!content.get("events") ||
+		const LLSD& content = getContent();
+		if (!content.isMap() ||
+			!content.get("events") ||
 			!content.get("id"))
 		{
-			llwarns << "received event poll with no events or id key" << llendl;
+			llwarns << "received event poll with no events or id key: " << dumpResponse() << llendl;
 			makeRequest();
 			return;
 		}
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index ddb9d3bc4369ab4d03c2dcbd41884776158e5488..691a24e2dfd8a94dccffad61274378eb5713f1a6 100755
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -39,6 +39,7 @@
 #include "llsecondlifeurls.h"
 
 #include "llappviewer.h"
+#include "llbufferstream.h"
 #include "llhttpclient.h"
 #include "llnotificationsutil.h"
 #include "llviewercontrol.h"
@@ -509,6 +510,7 @@ void LLFeatureManager::parseGPUTable(std::string filename)
 // responder saves table into file
 class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLHTTPFeatureTableResponder);
 public:
 
 	LLHTTPFeatureTableResponder(std::string filename) :
@@ -517,11 +519,10 @@ class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
 	}
 
 	
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		if (isGoodStatus(status))
+		if (isGoodStatus())
 		{
 			// write to file
 
@@ -540,7 +541,18 @@ class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
 				out.close();
 			}
 		}
-		
+		else
+		{
+			char body[1025]; 
+			body[1024] = '\0';
+			LLBufferStream istr(channels, buffer.get());
+			istr.get(body,1024);
+			if (strlen(body) > 0)
+			{
+				mContent["body"] = body;
+			}
+			llwarns << dumpResponse() << llendl;
+		}
 	}
 	
 private:
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index d13f85baa2ec0b2fd309dee63d6b2dcd67ffe2f9..89d74666f7437401414c7d2f72d25506f6cc2f7c 100755
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -1240,9 +1240,9 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
 {
 	GtkFileFilter *gfilter = gtk_file_filter_new();
 	gtk_file_filter_add_pattern(gfilter, "*.tga");
-	gtk_file_filter_add_mime_type(gfilter, "image/jpeg");
-	gtk_file_filter_add_mime_type(gfilter, "image/png");
-	gtk_file_filter_add_mime_type(gfilter, "image/bmp");
+	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_JPEG.c_str());
+	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_PNG.c_str());
+	gtk_file_filter_add_mime_type(gfilter, HTTP_CONTENT_IMAGE_BMP.c_str());
 	std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)";
 	add_common_filters_to_gtkchooser(gfilter, picker, filtername);
 	return filtername;
@@ -1250,13 +1250,13 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
  
 static std::string add_script_filter_to_gtkchooser(GtkWindow *picker)
 {
-	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain",
+	return add_simple_mime_filter_to_gtkchooser(picker,  HTTP_CONTENT_TEXT_PLAIN,
 							LLTrans::getString("script_files") + " (*.lsl)");
 }
 
 static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker)
 {
-	return add_simple_mime_filter_to_gtkchooser(picker,  "text/plain",
+	return add_simple_mime_filter_to_gtkchooser(picker, HTTP_CONTENT_TEXT_PLAIN,
 							LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)");
 }
 
@@ -1294,7 +1294,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 			break;
 		case FFSAVE_BMP:
 			caption += add_simple_mime_filter_to_gtkchooser
-				(picker, "image/bmp", LLTrans::getString("bitmap_image_files") + " (*.bmp)");
+				(picker, HTTP_CONTENT_IMAGE_BMP, LLTrans::getString("bitmap_image_files") + " (*.bmp)");
 			suggest_ext = ".bmp";
 			break;
 		case FFSAVE_AVI:
@@ -1319,6 +1319,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 			suggest_ext = ".raw";
 			break;
 		case FFSAVE_J2C:
+			// *TODO: Should this be 'image/j2c' ?
 			caption += add_simple_mime_filter_to_gtkchooser
 				(picker, "images/jp2",
 				 LLTrans::getString("compressed_image_files") + " (*.j2c)");
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 83fb887d81b3e2ad2c19fa193886d19e7ba3aa3e..801a24f472c95b2ceef35abcc9dd68d1e09202b8 100755
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -77,14 +77,9 @@ class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder
 {
 	LOG_CLASS(LLServerReleaseNotesURLFetcher);
 public:
-
 	static void startFetch();
-	/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content);
-	/*virtual*/ void completedRaw(
-		U32 status,
-		const std::string& reason,
-		const LLChannelDescriptors& channels,
-		const LLIOPipe::buffer_ptr_t& buffer);
+private:
+	/* virtual */ void httpCompleted();
 };
 
 ///----------------------------------------------------------------------------
@@ -471,32 +466,26 @@ void LLServerReleaseNotesURLFetcher::startFetch()
 }
 
 // virtual
-void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content)
+void LLServerReleaseNotesURLFetcher::httpCompleted()
 {
-	lldebugs << "Status: " << status << llendl;
-	lldebugs << "Reason: " << reason << llendl;
-	lldebugs << "Headers: " << content << llendl;
+	LL_DEBUGS("ServerReleaseNotes") << dumpResponse() 
+		<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
 
 	LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about");
 	if (floater_about)
 	{
-		std::string location = content["location"].asString();
+		const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
 		if (location.empty())
 		{
-			location = floater_about->getString("ErrorFetchingServerReleaseNotesURL");
+			LL_WARNS("ServerReleaseNotes") << "Missing Location header "
+				<< dumpResponse() << " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
+			floater_about->updateServerReleaseNotesURL(
+						floater_about->getString("ErrorFetchingServerReleaseNotesURL"));
+		}
+		else
+		{
+			floater_about->updateServerReleaseNotesURL(location);
 		}
-		floater_about->updateServerReleaseNotesURL(location);
 	}
 }
 
-// virtual
-void LLServerReleaseNotesURLFetcher::completedRaw(
-	U32 status,
-	const std::string& reason,
-	const LLChannelDescriptors& channels,
-	const LLIOPipe::buffer_ptr_t& buffer)
-{
-	// Do nothing.
-	// We're overriding just because the base implementation tries to
-	// deserialize LLSD which triggers warnings.
-}
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 113aa9a8f2596c48e56f17f333a0be52e454742c..0844a70e25d37f7f7d3f9449034a98c8e1dfbbf1 100755
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -458,13 +458,15 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const
 
 class LLAvatarPickerResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLAvatarPickerResponder);
 public:
 	LLUUID mQueryID;
     std::string mName;
 
 	LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { }
 
-	/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
+protected:
+	/*virtual*/ void httpCompleted()
 	{
 		//std::ostringstream ss;
 		//LLSDSerialize::toPrettyXML(content, ss);
@@ -472,19 +474,18 @@ class LLAvatarPickerResponder : public LLHTTPClient::Responder
 
 		// in case of invalid characters, the avatar picker returns a 400
 		// just set it to process so it displays 'not found'
-		if (isGoodStatus(status) || status == 400)
+		if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST)
 		{
 			LLFloaterAvatarPicker* floater =
 				LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName);
 			if (floater)
 			{
-				floater->processResponse(mQueryID, content);
+				floater->processResponse(mQueryID, getContent());
 			}
 		}
 		else
 		{
-			llwarns << "avatar picker failed [status:" << status << "]: " << content << llendl;
-			
+			llwarns << "avatar picker failed " << dumpResponse() << llendl;
 		}
 	}
 };
diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp
index 013cf74c7bab3ee8260090ba21d204943a0134df..6e641e7d40bca94ff2584fedae7bfed82198da6e 100755
--- a/indra/newview/llfloaterbuycurrencyhtml.cpp
+++ b/indra/newview/llfloaterbuycurrencyhtml.cpp
@@ -27,6 +27,7 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llfloaterbuycurrencyhtml.h"
+#include "llhttpconstants.h"
 #include "llstatusbar.h"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -85,7 +86,7 @@ void LLFloaterBuyCurrencyHTML::navigateToFinalURL()
 	llinfos << "Buy currency HTML parsed URL is " << buy_currency_url << llendl;
 
 	// kick off the navigation
-	mBrowser->navigateTo( buy_currency_url, "text/html" );
+	mBrowser->navigateTo( buy_currency_url, HTTP_CONTENT_TEXT_HTML );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index 56051ff68458f5cbd589ae833028116bbad3be41..af5c11e12cf585aa68dc320b851691bf5626b1f8 100755
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -617,9 +617,10 @@ void LLFloaterGesture::addToCurrentOutFit()
 	uuid_vec_t ids;
 	getSelectedIds(ids);
 	LLAppearanceMgr* am = LLAppearanceMgr::getInstance();
+	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
 	for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
 	{
-		am->addCOFItemLink(*it);
+		am->addCOFItemLink(*it, cb);
 	}
 }
 
diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp
index 4cb632bd6abf0c16b905d86aa9601e75c385b45a..c0bb2135405a1eae0414479714b48146b2637e3f 100755
--- a/indra/newview/llfloaterhelpbrowser.cpp
+++ b/indra/newview/llfloaterhelpbrowser.cpp
@@ -29,6 +29,7 @@
 #include "llfloaterhelpbrowser.h"
 
 #include "llfloaterreg.h"
+#include "llhttpconstants.h"
 #include "llpluginclassmedia.h"
 #include "llmediactrl.h"
 #include "llviewerwindow.h"
@@ -37,7 +38,6 @@
 #include "llui.h"
 
 #include "llurlhistory.h"
-#include "llmediactrl.h"
 #include "llviewermedia.h"
 #include "llviewerhelp.h"
 
@@ -148,7 +148,7 @@ void LLFloaterHelpBrowser::openMedia(const std::string& media_url)
 {
 	// explicitly make the media mime type for this floater since it will
 	// only ever display one type of content (Web).
-	mBrowser->setHomePageUrl(media_url, "text/html");
-	mBrowser->navigateTo(media_url, "text/html");
+	mBrowser->setHomePageUrl(media_url, HTTP_CONTENT_TEXT_HTML);
+	mBrowser->navigateTo(media_url, HTTP_CONTENT_TEXT_HTML);
 	setCurrentURL(media_url);
 }
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 8ec85e11602709d7791b9d95c9d08251b8152960..7b72c1e93079237c5bc5b27683db89bb99d9f09d 100755
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -1149,16 +1149,17 @@ BOOL LLFloaterIMSession::isInviteAllowed() const
 
 class LLSessionInviteResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLSessionInviteResponder);
 public:
 	LLSessionInviteResponder(const LLUUID& session_id)
 	{
 		mSessionID = session_id;
 	}
 
-	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+protected:
+	void httpFailure()
 	{
-		llwarns << "Error inviting all agents to session [status:" 
-				<< statusNum << "]: " << content << llendl;
+		llwarns << "Error inviting all agents to session " << dumpResponse() << llendl;
 		//throw something back to the viewer here?
 	}
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 100f1d580b96e0ea05ed425a62e03d799b8cc717..5830156fdd6797d387a3fd53deeafefb39ca6393 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -5839,7 +5839,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
 	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty());
 }
 
-void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason)
+void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason)
 {
 	llwarns << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl;
 	doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true));
@@ -5915,7 +5915,7 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)
 	getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);
 }
 
-void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason)
+void LLFloaterModelPreview::setPermissonsErrorStatus(S32 status, const std::string& reason)
 {
 	llwarns << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl;
 
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index e588418f7b1d7142fa07745040a176af93112f04..6c0c60b87fb648cf6322d4c806444971f0bb1aa1 100755
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -200,11 +200,11 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase
 	/*virtual*/ void onPermissionsReceived(const LLSD& result);
 
 	// called when error occurs during permissions request
-	/*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason);
+	/*virtual*/ void setPermissonsErrorStatus(S32 status, const std::string& reason);
 
 	/*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url);
 				void handleModelPhysicsFeeReceived();
-	/*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason);
+	/*virtual*/ void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason);
 
 	/*virtual*/ void onModelUploadSuccess();
 
diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp
index 6d3800bfa46f26a59bf2a12e941ab3796a0f01c3..9f1fc06e14e5e479e033c26b965221c3148d8522 100755
--- a/indra/newview/llfloatermodeluploadbase.cpp
+++ b/indra/newview/llfloatermodeluploadbase.cpp
@@ -45,7 +45,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()
 	if (!url.empty())
 	{
 		llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<llendl;
-		LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle()));
+		LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle()));
 	}
 	else
 	{
diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h
index a52bc286874122d5dc64fe7473e8772f7e10f22d..d9a887968783f06749466660c6aa463e9ad562fc 100755
--- a/indra/newview/llfloatermodeluploadbase.h
+++ b/indra/newview/llfloatermodeluploadbase.h
@@ -37,13 +37,13 @@ class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObs
 
 	virtual ~LLFloaterModelUploadBase(){};
 
-	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0;
+	virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0;
 
 	virtual void onPermissionsReceived(const LLSD& result) = 0;
 
 	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0;
 
-	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0;
+	virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0;
 
 	virtual void onModelUploadSuccess() {};
 
diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp
index 0862cd2897e0a7abe4ff1b8232c028b9ad4cacdb..c11a0568a66b16acefe745adcafb591d015324e9 100755
--- a/indra/newview/llfloaterobjectweights.cpp
+++ b/indra/newview/llfloaterobjectweights.cpp
@@ -123,7 +123,7 @@ void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost
 }
 
 //virtual
-void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reason)
+void LLFloaterObjectWeights::setErrorStatus(S32 status, const std::string& reason)
 {
 	const std::string text = getString("nothing_selected");
 
diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h
index 9a244573bef2ad3fded6d564765020a38a9f3a5e..1a2c317bad862171a9303d73b77a501534a60149 100755
--- a/indra/newview/llfloaterobjectweights.h
+++ b/indra/newview/llfloaterobjectweights.h
@@ -63,7 +63,7 @@ class LLFloaterObjectWeights : public LLFloater, LLAccountingCostObserver
 	/*virtual*/ void onOpen(const LLSD& key);
 
 	/*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost);
-	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason);
+	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
 
 	void updateLandImpacts(const LLParcel* parcel);
 	void refresh();
diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp
index 3a7ca17b73d34d3d71c34bcf090c2e57b87f52d9..efc04ac358f7aec27a84e89fd298e782f016ac76 100755
--- a/indra/newview/llfloaterregiondebugconsole.cpp
+++ b/indra/newview/llfloaterregiondebugconsole.cpp
@@ -73,24 +73,29 @@ namespace
 	// called if this request times out.
 	class AsyncConsoleResponder : public LLHTTPClient::Responder
 	{
-	public:
+		LOG_CLASS(AsyncConsoleResponder);
+	protected:
 		/* virtual */
-		void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+		void httpFailure()
 		{
+			LL_WARNS("Console") << dumpResponse() << LL_ENDL;
 			sConsoleReplySignal(UNABLE_TO_SEND_COMMAND);
 		}
 	};
 
 	class ConsoleResponder : public LLHTTPClient::Responder
 	{
+		LOG_CLASS(ConsoleResponder);
 	public:
 		ConsoleResponder(LLTextEditor *output) : mOutput(output)
 		{
 		}
 
+	protected:
 		/*virtual*/
-		void error(U32 status, const std::string& reason)
+		void httpFailure()
 		{
+			LL_WARNS("Console") << dumpResponse() << LL_ENDL;
 			if (mOutput)
 			{
 				mOutput->appendText(
@@ -100,8 +105,10 @@ namespace
 		}
 
 		/*virtual*/
-		void result(const LLSD& content)
+		void httpSuccess()
 		{
+			const LLSD& content = getContent();
+			LL_DEBUGS("Console") << content << LL_ENDL;
 			if (mOutput)
 			{
 				mOutput->appendText(
@@ -109,6 +116,7 @@ namespace
 			}
 		}
 
+	public:
 		LLTextEditor * mOutput;
 	};
 
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 50c013a49dfa3b479cf8adffada194f5b1a1a2b3..ddfae005bb56a6b0de51e2b8ab74ac5418db44e5 100755
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -756,12 +756,12 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L
 
 class ConsoleRequestResponder : public LLHTTPClient::Responder
 {
-public:
+	LOG_CLASS(ConsoleRequestResponder);
+protected:
 	/*virtual*/
-	void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	void httpFailure()
 	{
-		llwarns << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:"
-				<< status << "]: " << content << llendl;
+		llwarns << "error requesting mesh_rez_enabled " << dumpResponse() << llendl;
 	}
 };
 
@@ -769,12 +769,12 @@ class ConsoleRequestResponder : public LLHTTPClient::Responder
 // called if this request times out.
 class ConsoleUpdateResponder : public LLHTTPClient::Responder
 {
-public:
+	LOG_CLASS(ConsoleUpdateResponder);
+protected:
 	/* virtual */
-	void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	void httpFailure()
 	{
-		llwarns << "ConsoleRequestResponder error updating mesh enabled region setting [status:"
-				<< status << "]: " << content << llendl;
+		llwarns << "error updating mesh enabled region setting " << dumpResponse() << llendl;
 	}
 };
 
@@ -2233,14 +2233,16 @@ void LLPanelEstateInfo::getEstateOwner()
 
 class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLEstateChangeInfoResponder);
 public:
 	LLEstateChangeInfoResponder(LLPanelEstateInfo* panel)
 	{
 		mpPanel = panel->getHandle();
 	}
 	
+protected:
 	// if we get a normal response, handle it here
-	virtual void result(const LLSD& content)
+	virtual void httpSuccess()
 	{
 		LL_INFOS("Windlight") << "Successfully committed estate info" << llendl;
 
@@ -2251,10 +2253,9 @@ class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
 	}
 	
 	// if we get an error response
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	virtual void httpFailure()
 	{
-		llinfos << "LLEstateChangeInfoResponder::error [status:"
-			<< status << "]: " << content << llendl;
+		LL_WARNS("Windlight") << dumpResponse() << LL_ENDL;
 	}
 private:
 	LLHandle<LLPanel> mpPanel;
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 35b63c54803fde1765942cd98b507c7cf9962daa..cc4199a758657474b68adfa341401f4f5a75241b 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -707,16 +707,18 @@ class LLUserReportScreenshotResponder : public LLAssetUploadResponder
 
 class LLUserReportResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLUserReportResponder);
 public:
 	LLUserReportResponder(): LLHTTPClient::Responder()  {}
 
-	void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
-	{
-		// *TODO do some user messaging here
-		LLUploadDialog::modalUploadFinished();
-	}
-	void result(const LLSD& content)
+private:
+	void httpCompleted()
 	{
+		if (!isGoodStatus())
+		{
+			// *TODO do some user messaging here
+			LL_WARNS("UserReport") << dumpResponse() << LL_ENDL;
+		}
 		// we don't care about what the server returns
 		LLUploadDialog::modalUploadFinished();
 	}
diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp
index 13cb3c2eb00256ad87432ae0710d8a23a71ff251..11a0d3ebe496ed3a815c3f5acad6ea99827da041 100755
--- a/indra/newview/llfloaterscriptlimits.cpp
+++ b/indra/newview/llfloaterscriptlimits.cpp
@@ -183,8 +183,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)
 // Responders
 ///----------------------------------------------------------------------------
 
-void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)
+void fetchScriptLimitsRegionInfoResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	//we don't need to test with a fake respose here (shouldn't anyway)
 
 #ifdef DUMP_REPLIES_TO_LLINFOS
@@ -221,13 +227,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)
 	}
 }
 
-void fetchScriptLimitsRegionInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsRegionInfoResponder::httpFailure()
 {
-	llwarns << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 }
 
-void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
+void fetchScriptLimitsRegionSummaryResponder::httpSuccess()
 {
+	const LLSD& content_ref = getContent();
 #ifdef USE_FAKE_RESPONSES
 
 	LLSD fake_content;
@@ -268,6 +275,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
 
 #endif
 
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
+
 
 #ifdef DUMP_REPLIES_TO_LLINFOS
 
@@ -291,7 +304,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
 		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
 		if(tab)
 		{
-		LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
+			LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
 			if(panel_memory)
 			{
 				panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
@@ -301,20 +314,21 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
 				{
 					btn->setEnabled(true);
 				}
-				
-		panel_memory->setRegionSummary(content);
-	}
-}
+
+				panel_memory->setRegionSummary(content);
+			}
+		}
 	}
 }
 
-void fetchScriptLimitsRegionSummaryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsRegionSummaryResponder::httpFailure()
 {
-	llwarns << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 }
 
-void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref)
+void fetchScriptLimitsRegionDetailsResponder::httpSuccess()
 {
+	const LLSD& content_ref = getContent();
 #ifdef USE_FAKE_RESPONSES
 /*
 Updated detail service, ** denotes field added:
@@ -377,6 +391,12 @@ result (map)
 
 #endif
 
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
+
 #ifdef DUMP_REPLIES_TO_LLINFOS
 
 	LLSDNotationStreamer notation_streamer(content);
@@ -417,13 +437,14 @@ result (map)
 	}
 }
 
-void fetchScriptLimitsRegionDetailsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsRegionDetailsResponder::httpFailure()
 {
-	llwarns << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 }
 
-void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
+void fetchScriptLimitsAttachmentInfoResponder::httpSuccess()
 {
+	const LLSD& content_ref = getContent();
 
 #ifdef USE_FAKE_RESPONSES
 
@@ -465,6 +486,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
 
 #endif
 
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
+
 #ifdef DUMP_REPLIES_TO_LLINFOS
 
 	LLSDNotationStreamer notation_streamer(content);
@@ -513,9 +540,9 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
 	}
 }
 
-void fetchScriptLimitsAttachmentInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsAttachmentInfoResponder::httpFailure()
 {
-	llwarns << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 }
 
 ///----------------------------------------------------------------------------
@@ -586,7 +613,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id)
 }
 
 // virtual
-void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason)
+void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason)
 {
 	llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
 }
diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h
index f8732ef94bb02f14db6c46cf0b2661e24953eb50..a5cb1b6184a571b4ad00f73ccf7b3a757c11ae3a 100755
--- a/indra/newview/llfloaterscriptlimits.h
+++ b/indra/newview/llfloaterscriptlimits.h
@@ -85,49 +85,49 @@ class LLPanelScriptLimitsInfo : public LLPanel
 
 class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder
 {
-	public:
-		fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {};
-
-		void result(const LLSD& content);
-		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-	public:
-	protected:
-		LLSD mInfo;
+	LOG_CLASS(fetchScriptLimitsRegionInfoResponder);
+public:
+	fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {};
+
+private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
+	LLSD mInfo;
 };
 
 class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder
 {
-	public:
-		fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {};
-
-		void result(const LLSD& content);
-		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-	public:
-	protected:
-		LLSD mInfo;
+	LOG_CLASS(fetchScriptLimitsRegionSummaryResponder);
+public:
+	fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {};
+
+private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
+	LLSD mInfo;
 };
 
 class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder
 {
-	public:
-		fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {};
-
-		void result(const LLSD& content);
-		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-	public:
-	protected:
-		LLSD mInfo;
+	LOG_CLASS(fetchScriptLimitsRegionDetailsResponder);
+public:
+	fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {};
+
+private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
+	LLSD mInfo;
 };
 
 class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder
 {
-	public:
-		fetchScriptLimitsAttachmentInfoResponder() {};
+	LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder);
+public:
+	fetchScriptLimitsAttachmentInfoResponder() {};
 
-		void result(const LLSD& content);
-		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-	public:
-	protected:
+private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
 };
 
 /////////////////////////////////////////////////////////////////////////////
@@ -190,7 +190,7 @@ class LLPanelScriptLimitsRegionMemory : public LLPanelScriptLimitsInfo, LLRemote
 // LLRemoteParcelInfoObserver interface:
 /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 /*virtual*/ void setParcelID(const LLUUID& parcel_id);
-/*virtual*/ void setErrorStatus(U32 status, const std::string& reason);
+/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
 	
 	static void onClickRefresh(void* userdata);
 	static void onClickHighlight(void* userdata);
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 2a946b1edfa06048dc610ae01cc7c940361149f5..a446b767acb0bef9daba63dd35e50f0004f41f7a 100755
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -30,6 +30,7 @@
 #include "llcommandhandler.h"
 #include "llfloaterreg.h"
 #include "llfloatersearch.h"
+#include "llhttpconstants.h"
 #include "llmediactrl.h"
 #include "llnotificationsutil.h"
 #include "lllogininstance.h"
@@ -200,5 +201,5 @@ void LLFloaterSearch::search(const SearchQuery &p)
 	url = LLWeb::expandURLSubstitutions(url, subs);
 
 	// and load the URL in the web view
-	mWebBrowser->navigateTo(url, "text/html");
+	mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
 }
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index a242b224cd7fab1b538d4edad4bd287a8c1afc5b..0613ffc94d803f35e31e9d5a017c75d126cbe855 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -36,7 +36,7 @@
 #include "llbutton.h"
 #include "llevents.h"
 #include "llhttpclient.h"
-#include "llhttpstatuscodes.h"	// for HTTP_FOUND
+#include "llhttpconstants.h"
 #include "llnotificationsutil.h"
 #include "llradiogroup.h"
 #include "lltextbox.h"
@@ -62,42 +62,46 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)
 // on parent class indicating if the web server is working or not
 class LLIamHere : public LLHTTPClient::Responder
 {
-	private:
-		LLIamHere( LLFloaterTOS* parent ) :
-		   mParent( parent )
-		{}
+	LOG_CLASS(LLIamHere);
+private:
+	LLIamHere( LLFloaterTOS* parent ) :
+	   mParent( parent )
+	{}
 
-		LLFloaterTOS* mParent;
+	LLFloaterTOS* mParent;
 
-	public:
-
-		static LLIamHere* build( LLFloaterTOS* parent )
-		{
-			return new LLIamHere( parent );
-		};
-		
-		virtual void  setParent( LLFloaterTOS* parentIn )
-		{
-			mParent = parentIn;
-		};
-		
-		virtual void result( const LLSD& content )
+public:
+	static LLIamHere* build( LLFloaterTOS* parent )
+	{
+		return new LLIamHere( parent );
+	}
+	
+	virtual void  setParent( LLFloaterTOS* parentIn )
+	{
+		mParent = parentIn;
+	}
+	
+protected:
+	virtual void httpSuccess()
+	{
+		if ( mParent )
 		{
-			if ( mParent )
-				mParent->setSiteIsAlive( true );
-		};
+			mParent->setSiteIsAlive( true );
+		}
+	}
 
-		virtual void error( U32 status, const std::string& reason )
+	virtual void httpFailure()
+	{
+		LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL;
+		if ( mParent )
 		{
-			if ( mParent )
-			{
-				// *HACK: For purposes of this alive check, 302 Found
-				// (aka Moved Temporarily) is considered alive.  The web site
-				// redirects this link to a "cache busting" temporary URL. JC
-				bool alive = (status == HTTP_FOUND);
-				mParent->setSiteIsAlive( alive );
-			}
-		};
+			// *HACK: For purposes of this alive check, 302 Found
+			// (aka Moved Temporarily) is considered alive.  The web site
+			// redirects this link to a "cache busting" temporary URL. JC
+			bool alive = (getStatus() == HTTP_FOUND);
+			mParent->setSiteIsAlive( alive );
+		}
+	}
 };
 
 // this is global and not a class member to keep crud out of the header file
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index e85d849c9ad3b0ddca38532d739eafe3a467e29f..e26f1e9ea541d83d2345f53cfc804f2db3a173e6 100755
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -48,31 +48,30 @@ static LLFloaterURLEntry* sInstance = NULL;
 // on the Panel Land Media and to discover the MIME type
 class LLMediaTypeResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLMediaTypeResponder);
 public:
 	LLMediaTypeResponder( const LLHandle<LLFloater> parent ) :
-	  mParent( parent )
-	  {}
-
-	  LLHandle<LLFloater> mParent;
-
-
-	  virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
-	  {
-		  std::string media_type = content["content-type"].asString();
-		  std::string::size_type idx1 = media_type.find_first_of(";");
-		  std::string mime_type = media_type.substr(0, idx1);
-		  completeAny(status, mime_type);
-	  }
-
-	  void completeAny(U32 status, const std::string& mime_type)
-	  {
-		  // Set empty type to none/none.  Empty string is reserved for legacy parcels
-		  // which have no mime type set.
-		  std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType();
-		  LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get();
-		  if ( floater_url_entry )
-			  floater_url_entry->headerFetchComplete( status, resolved_mime_type );
-	  }
+		mParent( parent )
+	{}
+
+	LLHandle<LLFloater> mParent;
+
+private:
+	/* virtual */ void httpCompleted()
+	{
+		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE);
+		std::string::size_type idx1 = media_type.find_first_of(";");
+		std::string mime_type = media_type.substr(0, idx1);
+
+		// Set empty type to none/none.  Empty string is reserved for legacy parcels
+		// which have no mime type set.
+		std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType();
+		LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get();
+		if ( floater_url_entry )
+		{
+			floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type );
+		}
+	}
 };
 
 //-----------------------------------------------------------------------------
@@ -136,7 +135,7 @@ void LLFloaterURLEntry::buildURLHistory()
 	}
 }
 
-void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type)
+void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_type)
 {
 	LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get());
 	if (panel_media)
diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h
index dfb49fe5ac97bdb8cd53d300a303aa6814971b14..bdd1ebe5921f5dbd01a48d694ab6c5a9e7c5ec57 100755
--- a/indra/newview/llfloaterurlentry.h
+++ b/indra/newview/llfloaterurlentry.h
@@ -40,7 +40,7 @@ class LLFloaterURLEntry : public LLFloater
 	// that panel via the handle.
 	static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url);
 	/*virtual*/	BOOL	postBuild();
-	void headerFetchComplete(U32 status, const std::string& mime_type);
+	void headerFetchComplete(S32 status, const std::string& mime_type);
 
 	bool addURLToCombobox(const std::string& media_url);
 
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 3fe2518de67230cb185fda3cc036366796cfd5aa..21b171446fd99470c3ab3d07e7bb51cc95387610 100755
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -29,6 +29,7 @@
 #include "llcombobox.h"
 #include "lliconctrl.h"
 #include "llfloaterreg.h"
+#include "llhttpconstants.h"
 #include "lllayoutstack.h"
 #include "llpluginclassmedia.h"
 #include "llprogressbar.h"
@@ -234,9 +235,9 @@ void LLFloaterWebContent::open_media(const Params& p)
 {
 	// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
 	LLViewerMedia::proxyWindowOpened(p.target(), p.id());
-	mWebBrowser->setHomePageUrl(p.url, "text/html");
+	mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML);
 	mWebBrowser->setTarget(p.target);
-	mWebBrowser->navigateTo(p.url, "text/html");
+	mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML);
 	
 	set_current_url(p.url);
 
@@ -451,7 +452,7 @@ void LLFloaterWebContent::onEnterAddress()
 	std::string url = mAddressCombo->getValue().asString();
 	if ( url.length() > 0 )
 	{
-		mWebBrowser->navigateTo( url, "text/html");
+		mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
 	};
 }
 
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index 5c6ce9d311df02207c2f1edd8bb80bf293f9981a..0ce053480201745a349b7bcd50d45f9b16781c2d 100755
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -86,7 +86,7 @@ const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollect
 
 	if (cats_count > 1)
 	{
-		LL_WARNS("LLFriendCardsManager")
+		LL_WARNS_ONCE("LLFriendCardsManager")
 			<< "There is more than one Friend card folder."
 			<< "The first folder will be used."
 			<< LL_ENDL;
diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp
index 9aa86297fc084808db2f7eb95a3cb10fd5e887c1..5eaa83d87235346860a2ba6c7cda1deb4c26c0f4 100755
--- a/indra/newview/llgesturemgr.cpp
+++ b/indra/newview/llgesturemgr.cpp
@@ -299,6 +299,12 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id,
 }
 
 
+void notify_update_label(const LLUUID& base_item_id)
+{
+	gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id);
+	LLGestureMgr::instance().notifyObservers();
+}
+
 void LLGestureMgr::deactivateGesture(const LLUUID& item_id)
 {
 	const LLUUID& base_item_id = get_linked_uuid(item_id);
@@ -322,7 +328,6 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)
 	}
 
 	mActive.erase(it);
-	gInventory.addChangedMask(LLInventoryObserver::LABEL, base_item_id);
 
 	// Inform the database of this change
 	LLMessageSystem* msg = gMessageSystem;
@@ -338,9 +343,11 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id)
 
 	gAgent.sendReliableMessage();
 
-	LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id);
+	LLPointer<LLInventoryCallback> cb =
+		new LLBoostFuncInventoryCallback(no_op_inventory_func,
+										 boost::bind(notify_update_label,base_item_id));
 
-	notifyObservers();
+	LLAppearanceMgr::instance().removeCOFItemLinks(base_item_id, cb);
 }
 
 
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index cbd844cdac07743deb4a444a3a602a5b5b44cdf3..472e3862ea0a317b0881548898e94c283f889b8a 100755
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -1843,23 +1843,31 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
 // Responder class for capability group management
 class GroupMemberDataResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(GroupMemberDataResponder);
 public:
-		GroupMemberDataResponder() {}
-		virtual ~GroupMemberDataResponder() {}
-		virtual void result(const LLSD& pContent);
-		virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
+	GroupMemberDataResponder() {}
+	virtual ~GroupMemberDataResponder() {}
+
 private:
-		LLSD mMemberData;
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
+	LLSD mMemberData;
 };
 
-void GroupMemberDataResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent)
+void GroupMemberDataResponder::httpFailure()
 {
-	LL_WARNS("GrpMgr") << "Error receiving group member data [status:" 
-		<< pStatus << "]: " << pContent << LL_ENDL;
+	LL_WARNS("GrpMgr") << "Error receiving group member data "
+		<< dumpResponse() << LL_ENDL;
 }
 
-void GroupMemberDataResponder::result(const LLSD& content)
+void GroupMemberDataResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	LLGroupMgr::processCapGroupMembersRequest(content);
 }
 
diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp
index 37428c4a44b5769885613c4ffc247f0c3b63b5a4..b1286cccf2b7522c2d6dbc6fe0523966e416c858 100755
--- a/indra/newview/llhomelocationresponder.cpp
+++ b/indra/newview/llhomelocationresponder.cpp
@@ -33,71 +33,76 @@
 #include "llagent.h"
 #include "llviewerregion.h"
 
-void LLHomeLocationResponder::result( const LLSD& content )
+void LLHomeLocationResponder::httpSuccess()
 {
+  const LLSD& content = getContent();
   LLVector3 agent_pos;
   bool      error = true;
-		
+
   do {
-	
+
     // was the call to /agent/<agent-id>/home-location successful?
     // If not, we keep error set to true
     if( ! content.has("success") )
     {
       break;
     }
-		
+
     if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) )
     {
       break;
     }
-		
+
     // did the simulator return a "justified" home location?
     // If no, we keep error set to true
     if( ! content.has( "HomeLocation" ) )
     {
       break;
     }
-		
+
     if( ! content["HomeLocation"].has("LocationPos") )
     {
       break;
     }
-		
+
     if( ! content["HomeLocation"]["LocationPos"].has("X") )
     {
       break;
     }
 
     agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger();
-		
+
     if( ! content["HomeLocation"]["LocationPos"].has("Y") )
     {
       break;
     }
 
     agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger();
-		
+
     if( ! content["HomeLocation"]["LocationPos"].has("Z") )
     {
       break;
     }
 
     agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger();
-		
+
     error = false;
   } while( 0 );
-	
-  if( ! error )
+
+  if( error )
+  {
+    failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content);
+  }
+  else
   {
     llinfos << "setting home position" << llendl;
-		
+
     LLViewerRegion *viewer_region = gAgent.getRegion();
     gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos );
   }
 }
 
-void LLHomeLocationResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content )
+void LLHomeLocationResponder::httpFailure()
 {
-	llwarns << "LLHomeLocationResponder error [status:" << status << "]: " << content << llendl;
+  llwarns << dumpResponse() << llendl;
 }
diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h
index 9bf4b12c4e9eef85c5e5cbd45de4b9fa220f2f35..adc6c8cb58109b11e5333c63b9dafbc0ae2ccb55 100755
--- a/indra/newview/llhomelocationresponder.h
+++ b/indra/newview/llhomelocationresponder.h
@@ -35,8 +35,10 @@
 /* Typedef, Enum, Class, Struct, etc. */
 class LLHomeLocationResponder : public LLHTTPClient::Responder
 {
-	virtual void result( const LLSD& content );
-	virtual void errorWithContent( U32 status, const std::string& reason, const LLSD& content );
+	LOG_CLASS(LLHomeLocationResponder);
+private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
 };
 
 #endif
diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..1512b46103208ce436fe2effbbe35c10c1044128
--- /dev/null
+++ b/indra/newview/llhttpretrypolicy.cpp
@@ -0,0 +1,137 @@
+/** 
+ * @file llhttpretrypolicy.h
+ * @brief Header for a retry policy class intended for use with http responders.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llhttpretrypolicy.h"
+
+LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx):
+	mMinDelay(min_delay),
+	mMaxDelay(max_delay),
+	mBackoffFactor(backoff_factor),
+	mMaxRetries(max_retries),
+	mRetryOn4xx(retry_on_4xx)
+{
+	init();
+}
+
+void LLAdaptiveRetryPolicy::init()
+{
+	mDelay = mMinDelay;
+	mRetryCount = 0;
+	mShouldRetry = true;
+}
+
+bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header_time)
+{
+	return (headers.has(HTTP_IN_HEADER_RETRY_AFTER)
+			&& getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time));
+}
+
+bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time)
+{
+	if (headers)
+	{
+		const std::string *retry_value = headers->find(HTTP_IN_HEADER_RETRY_AFTER.c_str()); 
+		if (retry_value && 
+			getSecondsUntilRetryAfter(*retry_value, retry_header_time))
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+void LLAdaptiveRetryPolicy::onSuccess()
+{
+	init();
+}
+
+void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers)
+{
+	F32 retry_header_time;
+	bool has_retry_header_time = getRetryAfter(headers,retry_header_time);
+	onFailureCommon(status, has_retry_header_time, retry_header_time);
+}
+  
+void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response)
+{
+	F32 retry_header_time;
+	const LLCore::HttpHeaders *headers = response->getHeaders();
+	bool has_retry_header_time = getRetryAfter(headers,retry_header_time);
+	onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time);
+}
+
+void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time)
+{
+	if (!mShouldRetry)
+	{
+		llinfos << "keep on failing" << llendl;
+		return;
+	}
+	if (mRetryCount > 0)
+	{
+		mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay);
+	}
+	// Honor server Retry-After header.
+	// Status 503 may ask us to wait for a certain amount of time before retrying.
+	F32 wait_time = mDelay;
+	if (has_retry_header_time)
+	{
+		wait_time = retry_header_time;
+	}
+
+	if (mRetryCount>=mMaxRetries)
+	{
+		llinfos << "Too many retries " << mRetryCount << ", will not retry" << llendl;
+		mShouldRetry = false;
+	}
+	if (!mRetryOn4xx && !isHttpServerErrorStatus(status))
+	{
+		llinfos << "Non-server error " << status << ", will not retry" << llendl;
+		mShouldRetry = false;
+	}
+	if (mShouldRetry)
+	{
+		llinfos << "Retry count " << mRetryCount << " should retry after " << wait_time << llendl;
+		mRetryTimer.reset();
+		mRetryTimer.setTimerExpirySec(wait_time);
+	}
+	mRetryCount++;
+}
+	
+
+bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const
+{
+	if (mRetryCount == 0)
+	{
+		// Called shouldRetry before any failure.
+		seconds_to_wait = F32_MAX;
+		return false;
+	}
+	seconds_to_wait = mShouldRetry ? mRetryTimer.getRemainingTimeF32() : F32_MAX;
+	return mShouldRetry;
+}
diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h
new file mode 100755
index 0000000000000000000000000000000000000000..5b1a1d79e037a342decadde0f3e264a2467d86b6
--- /dev/null
+++ b/indra/newview/llhttpretrypolicy.h
@@ -0,0 +1,94 @@
+/** 
+ * @file file llhttpretrypolicy.h
+ * @brief declarations for http retry policy class.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+										
+#ifndef LL_RETRYPOLICY_H
+#define LL_RETRYPOLICY_H
+
+#include "lltimer.h"
+#include "llthread.h"
+
+#include "llhttpconstants.h"
+
+// For compatibility with new core http lib.
+#include "httpresponse.h"
+#include "httpheaders.h"
+
+// This is intended for use with HTTP Clients/Responders, but is not
+// specifically coupled with those classes.
+class LLHTTPRetryPolicy: public LLThreadSafeRefCount
+{
+public:
+	LLHTTPRetryPolicy() {}
+
+	virtual ~LLHTTPRetryPolicy() {}
+	// Call after a sucess to reset retry state.
+
+	virtual void onSuccess() = 0;
+	// Call once after an HTTP failure to update state.
+	virtual void onFailure(S32 status, const LLSD& headers) = 0;
+
+	virtual void onFailure(const LLCore::HttpResponse *response) = 0;
+
+	virtual bool shouldRetry(F32& seconds_to_wait) const = 0;
+};
+
+// Very general policy with geometric back-off after failures,
+// up to a maximum delay, and maximum number of retries.
+class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy
+{
+public:
+	LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx = false);
+
+	// virtual
+	void onSuccess();
+	
+	// virtual
+	void onFailure(S32 status, const LLSD& headers);
+	// virtual
+	void onFailure(const LLCore::HttpResponse *response);
+	// virtual
+	bool shouldRetry(F32& seconds_to_wait) const;
+
+protected:
+	void init();
+	bool getRetryAfter(const LLSD& headers, F32& retry_header_time);
+	bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time);
+	void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time);
+
+private:
+
+	const F32 mMinDelay; // delay never less than this value
+	const F32 mMaxDelay; // delay never exceeds this value
+	const F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay.
+	const U32 mMaxRetries; // maximum number of times shouldRetry will return true.
+	F32 mDelay; // current default delay.
+	U32 mRetryCount; // number of times shouldRetry has been called.
+	LLTimer mRetryTimer; // time until next retry.
+	bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc.
+	bool mRetryOn4xx; // Normally only retry on 5xx server errors.
+};
+
+#endif
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 59272d721fb6509b19f2a6210b288194357c8026..8a02dde88cff78aa614cb5cd75113f88c37b84d7 100755
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -388,16 +388,17 @@ void LLFloaterIMPanel::draw()
 
 class LLSessionInviteResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLSessionInviteResponder);
 public:
 	LLSessionInviteResponder(const LLUUID& session_id)
 	{
 		mSessionID = session_id;
 	}
 
-	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+protected:
+	void httpFailure()
 	{
-		llwarns << "Error inviting all agents to session [status:" 
-				<< statusNum << "]: " << content << llendl;
+		llwarns << "Error inviting all agents to session " << dumpResponse() << llendl;
 		//throw something back to the viewer here?
 	}
 
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 2c20409381d3331018c0b099d9a45ee7c62eb435..aed0414c50a22158a4fd409fc6cf7526032028f6 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -899,7 +899,7 @@ void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& m
 	LLIMSession* session = findIMSession(session_id);
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return;
 	}
 
@@ -921,7 +921,7 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)
 	LLIMSession* session = findIMSession(session_id);
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return;
 	}
 
@@ -941,7 +941,7 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,
 
 	if (!session) 
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return false;
 	}
 
@@ -1016,7 +1016,7 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,
 
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return NULL;
 	}
 
@@ -1053,7 +1053,7 @@ const std::string LLIMModel::getName(const LLUUID& session_id) const
 
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return LLTrans::getString("no_session_message");
 	}
 
@@ -1065,7 +1065,7 @@ const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const
 	LLIMSession* session = findIMSession(session_id);
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return -1;
 	}
 
@@ -1089,7 +1089,7 @@ EInstantMessage LLIMModel::getType(const LLUUID& session_id) const
 	LLIMSession* session = findIMSession(session_id);
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return IM_COUNT;
 	}
 
@@ -1101,7 +1101,7 @@ LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const
 	LLIMSession* session = findIMSession(session_id);
 	if (!session)
 	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
+		llwarns << "session " << session_id << " does not exist " << llendl;
 		return NULL;
 	}
 
@@ -1387,6 +1387,7 @@ void start_deprecated_conference_chat(
 
 class LLStartConferenceChatResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLStartConferenceChatResponder);
 public:
 	LLStartConferenceChatResponder(
 		const LLUUID& temp_session_id,
@@ -1400,10 +1401,12 @@ class LLStartConferenceChatResponder : public LLHTTPClient::Responder
 		mAgents = agents_to_invite;
 	}
 
-	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+protected:
+	virtual void httpFailure()
 	{
 		//try an "old school" way.
-		if ( statusNum == 400 )
+		// *TODO: What about other error status codes?  4xx 5xx?
+		if ( getStatus() == HTTP_BAD_REQUEST )
 		{
 			start_deprecated_conference_chat(
 				mTempSessionID,
@@ -1412,8 +1415,7 @@ class LLStartConferenceChatResponder : public LLHTTPClient::Responder
 				mAgents);
 		}
 
-		llwarns << "LLStartConferenceChatResponder error [status:"
-				<< statusNum << "]: " << content << llendl;
+		llwarns << dumpResponse() << llendl;
 
 		//else throw an error back to the client?
 		//in theory we should have just have these error strings
@@ -1505,6 +1507,7 @@ bool LLIMModel::sendStartSession(
 class LLViewerChatterBoxInvitationAcceptResponder :
 	public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder);
 public:
 	LLViewerChatterBoxInvitationAcceptResponder(
 		const LLUUID& session_id,
@@ -1514,8 +1517,15 @@ class LLViewerChatterBoxInvitationAcceptResponder :
 		mInvitiationType = invitation_type;
 	}
 
-	void result(const LLSD& content)
+private:
+	void httpSuccess()
 	{
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		if ( gIMMgr)
 		{
 			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
@@ -1560,19 +1570,17 @@ class LLViewerChatterBoxInvitationAcceptResponder :
 		}
 	}
 
-	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+	void httpFailure()
 	{
-		llwarns << "LLViewerChatterBoxInvitationAcceptResponder error [status:"
-				<< statusNum << "]: " << content << llendl;
+		llwarns << dumpResponse() << llendl;
 		//throw something back to the viewer here?
 		if ( gIMMgr )
 		{
 			gIMMgr->clearPendingAgentListUpdates(mSessionID);
 			gIMMgr->clearPendingInvitation(mSessionID);
-			if ( 404 == statusNum )
+			if ( HTTP_NOT_FOUND == getStatus() )
 			{
-				std::string error_string;
-				error_string = "session_does_not_exist_error";
+				static const std::string error_string("session_does_not_exist_error");
 				gIMMgr->showSessionStartError(error_string, mSessionID);
 			}
 		}
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 9c6db3676f56baf328126c966e249388848c52e2..6ff16742ddc02c41228053bc6aacb50974fdec08 100755
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -292,11 +292,7 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)
 	delete mPropertiesRequest;
 	mPropertiesRequest = NULL;
 }
-/*
-prep#
-			virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
-				llwarns << "MuteVoiceResponder error [status:" << status << "]: " << content << llendl;
-	*/
+
 
 void LLInspectAvatar::updateVolumeSlider()
 {
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index a5043a30acce7fcde10fb3a452515cdcc2a831c2..89c56ab82c91bf085b6f1ab4d726b02af3416246 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -200,6 +200,7 @@ const std::string& LLInvFVBridge::getDisplayName() const
 	{
 		buildDisplayName();
 	}
+
 	return mDisplayName;
 }
 
@@ -1159,17 +1160,10 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 
 void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
 {
-	LLInventoryCategory* cat = model->getCategory(uuid);
-	if (cat)
-	{
-		model->purgeDescendentsOf(uuid);
-		model->notifyObservers();
-	}
 	LLInventoryObject* obj = model->getObject(uuid);
 	if (obj)
 	{
-		model->purgeObject(uuid);
-		model->notifyObservers();
+		remove_inventory_object(uuid, NULL);
 	}
 }
 
@@ -1573,18 +1567,18 @@ void LLItemBridge::buildDisplayName() const
 	else
 	{
 		mDisplayName.assign(LLStringUtil::null);
-}
-
+	}
+	
 	mSearchableName.assign(mDisplayName);
 	mSearchableName.append(getLabelSuffix());
 	LLStringUtil::toUpper(mSearchableName);
-
+	
     //Name set, so trigger a sort
     if(mParent)
-{
-        mParent->requestSort();
-	}
+	{
+		mParent->requestSort();
 	}
+}
 
 LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
 {
@@ -1698,13 +1692,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)
 	LLViewerInventoryItem* item = getItem();
 	if(item && (item->getName() != new_name))
 	{
-		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
-		new_item->rename(new_name);
-		new_item->updateServer(FALSE);
-		model->updateItem(new_item);
-
-		model->notifyObservers();
-		buildDisplayName();
+		LLSD updates;
+		updates["name"] = new_name;
+		update_inventory_item(item->getUUID(),updates, NULL);
 	}
 	// return FALSE because we either notified observers (& therefore
 	// rebuilt) or we didn't update.
@@ -1901,49 +1891,19 @@ void LLFolderBridge::buildDisplayName() const
 
 void LLFolderBridge::update()
 {
-	bool possibly_has_children = false;
-	bool up_to_date = isUpToDate();
-	if(!up_to_date && hasChildren()) // we know we have children but  haven't  fetched them (doesn't obey filter)
-	{
-		possibly_has_children = true;
-	}
-
-	bool loading = (possibly_has_children
-		&& !up_to_date );
+	// we know we have children but  haven't  fetched them (doesn't obey filter)
+	bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen();
 
 	if (loading != mIsLoading)
 	{
-		if ( loading && !mIsLoading )
+		if ( loading )
 		{
 			// Measure how long we've been in the loading state
 			mTimeSinceRequestStart.reset();
 		}
+		mIsLoading = loading;
 
-		const BOOL in_inventory = gInventory.isObjectDescendentOf(getUUID(),   gInventory.getRootFolderID());
-		const BOOL in_library = gInventory.isObjectDescendentOf(getUUID(),   gInventory.getLibraryRootFolderID());
-
-		bool root_is_loading = false;
-		if (in_inventory)
-		{
-			root_is_loading =   LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress();
-		}
-		if (in_library)
-		{
-			root_is_loading =   LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress();
-		}
-		if ((mIsLoading
-				&&	mTimeSinceRequestStart.getElapsedTimeF32() >=   gSavedSettings.getF32("FolderLoadingMessageWaitTime"))
-			||	(LLInventoryModelBackgroundFetch::instance().folderFetchActive()
-				&&	root_is_loading))
-		{
-			mDisplayName = LLInvFVBridge::getDisplayName() + " ( " +   LLTrans::getString("LoadingData") + " ) ";
-			mIsLoading = true;
-		}
-		else
-		{
-			mDisplayName = LLInvFVBridge::getDisplayName();
-			mIsLoading = false;
-		}
+		mFolderViewItem->refresh();
 	}
 }
 
@@ -3063,6 +3023,13 @@ LLUIImagePtr LLFolderBridge::getIconOverlay() const
 	return NULL;
 }
 
+std::string LLFolderBridge::getLabelSuffix() const
+{
+	static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime");
+	return mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay() 
+		? llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str())
+		: LLStringUtil::null;
+}
 
 BOOL LLFolderBridge::renameItem(const std::string& new_name)
 {
@@ -3586,6 +3553,10 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&
 		{
 			disabled_items.push_back(std::string("Replace Outfit"));
 		}
+		if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID))
+		{
+			disabled_items.push_back(std::string("Add To Outfit"));
+		}
 		items.push_back(std::string("Outfit Separator"));
 	}
 }
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 517153e1710c440955989e411b3e7ac3d75bcec4..2a937b574dbe23390dcc81899b01d45e3fe2e451 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -248,7 +248,7 @@ class LLFolderBridge : public LLInvFVBridge
 	LLFolderBridge(LLInventoryPanel* inventory, 
 				   LLFolderView* root,
 				   const LLUUID& uuid) 
-        :       LLInvFVBridge(inventory, root, uuid),
+	:	LLInvFVBridge(inventory, root, uuid),
 		mCallingCards(FALSE),
 		mWearables(FALSE),
 		mIsLoading(false)
@@ -272,6 +272,8 @@ class LLFolderBridge : public LLInvFVBridge
 	virtual LLUIImagePtr getIconOverlay() const;
 
 	static LLUIImagePtr getIcon(LLFolderType::EType preferred_type);
+	
+	virtual std::string getLabelSuffix() const;
 
 	virtual BOOL renameItem(const std::string& new_name);
 
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index f1a4889f5ac141728fb2b565b31383207ede20c2..faa5d70952e9668ae7b57767a42467c3587e20df 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -123,12 +123,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
 		return;
 	}
 
-	LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
-	new_cat->rename(new_name);
-	new_cat->updateServer(FALSE);
-	model->updateCategory(new_cat);
-
-	model->notifyObservers();
+	LLSD updates;
+	updates["name"] = new_name;
+	update_inventory_category(cat_id, updates, NULL);
 }
 
 void copy_inventory_category(LLInventoryModel* model,
@@ -741,6 +738,13 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item
 	return FALSE;
 }
 
+bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+	LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
+	if (!vitem) return false;
+	return (vitem->getActualType() == LLAssetType::AT_LINK  && !vitem->getIsBrokenLink());
+}
+
 bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
 {
 	if(mType == LLAssetType::AT_CATEGORY)
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index f1066a4dc96622575df5a3f80d4b9a13afb195ce..6b3861aa79f21984bc2a8f42bdd3f27ec1b5b3df 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -186,6 +186,13 @@ class LLIsOfAssetType : public LLInventoryCollectFunctor
 	LLAssetType::EType mType;
 };
 
+class LLIsValidItemLink : public LLInventoryCollectFunctor
+{
+public:
+	virtual bool operator()(LLInventoryCategory* cat,
+							LLInventoryItem* item);
+};
+
 class LLIsTypeWithPermissions : public LLInventoryCollectFunctor
 {
 public:
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 935fe2b4d0e88c6c70c7e5f310ebaf7e4755f9e0..aadf87ab35c705bc7485f9401ea119f2e691dc47 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -27,6 +27,7 @@
 #include "llviewerprecompiledheaders.h"
 #include "llinventorymodel.h"
 
+#include "llaisapi.h"
 #include "llagent.h"
 #include "llagentwearables.h"
 #include "llappearancemgr.h"
@@ -48,6 +49,7 @@
 #include "llcallbacklist.h"
 #include "llvoavatarself.h"
 #include "llgesturemgr.h"
+#include "llsdutil.h"
 #include <typeinfo>
 
 //#define DIFF_INVENTORY_FILES
@@ -252,6 +254,23 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL
 	return NULL;
 }
 
+bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const
+{
+	LLInventoryObject *object = getObject(object_id);
+	while (object && object->getParentUUID().notNull())
+	{
+		LLInventoryObject *parent_object = getObject(object->getParentUUID());
+		if (!parent_object)
+		{
+			llwarns << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << llendl;
+			return false;
+		}
+		object = parent_object;
+	}
+	result = object->getUUID();
+	return true;
+}
+
 // Get the object by id. Returns NULL if not found.
 LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const
 {
@@ -450,6 +469,7 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp
 
 class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLCreateInventoryCategoryResponder);
 public:
 	LLCreateInventoryCategoryResponder(LLInventoryModel* model, 
 									   void (*callback)(const LLSD&, void*),
@@ -460,16 +480,21 @@ class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder
 	{
 	}
 	
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+protected:
+	virtual void httpFailure()
 	{
-		LL_WARNS("InvAPI") << "CreateInventoryCategory failed [status:"
-				<< status << "]: " << content << LL_ENDL;
+		LL_WARNS("InvAPI") << dumpResponse() << LL_ENDL;
 	}
 	
-	virtual void result(const LLSD& content)
+	virtual void httpSuccess()
 	{
 		//Server has created folder.
-		
+		const LLSD& content = getContent();
+		if (!content.isMap() || !content.has("folder_id"))
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		LLUUID category_id = content["folder_id"].asUUID();
 		
 		
@@ -587,6 +612,40 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
 	return id;
 }
 
+// This is optimized for the case that we just want to know whether a
+// category has any immediate children meeting a condition, without
+// needing to recurse or build up any lists.
+bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id,
+												   LLInventoryCollectFunctor& filter)
+{
+	LLInventoryModel::cat_array_t *cats;
+	LLInventoryModel::item_array_t *items;
+	getDirectDescendentsOf(cat_id, cats, items);
+	if (cats)
+	{
+		for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin();
+			 it != cats->end(); ++it)
+		{
+			if (filter(*it,NULL))
+			{
+				return true;
+			}
+		}
+	}
+	if (items)
+	{
+		for (LLInventoryModel::item_array_t::const_iterator it = items->begin();
+			 it != items->end(); ++it)
+		{
+			if (filter(NULL,*it))
+			{
+				return true;
+			}
+		}
+	}
+	return false;
+}
+												  
 // Starting with the object specified, add it's descendents to the
 // array provided, but do not add the inventory object specified by
 // id. There is no guaranteed order. Neither array will be erased
@@ -618,8 +677,7 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
 											cat_array_t& cats,
 											item_array_t& items,
 											BOOL include_trash,
-											LLInventoryCollectFunctor& add,
-											BOOL follow_folder_links)
+											LLInventoryCollectFunctor& add)
 {
 	// Start with categories
 	if(!include_trash)
@@ -646,36 +704,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
 	LLViewerInventoryItem* item = NULL;
 	item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
 
-	// Follow folder links recursively.  Currently never goes more
-	// than one level deep (for current outfit support)
-	// Note: if making it fully recursive, need more checking against infinite loops.
-	if (follow_folder_links && item_array)
-	{
-		S32 count = item_array->count();
-		for(S32 i = 0; i < count; ++i)
-		{
-			item = item_array->get(i);
-			if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER)
-			{
-				LLViewerInventoryCategory *linked_cat = item->getLinkedCategory();
-				if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT)
-					// BAP - was 
-					// LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType()))
-					// Change back once ensemble typing is in place.
-				{
-					if(add(linked_cat,NULL))
-					{
-						// BAP should this be added here?  May not
-						// matter if it's only being used in current
-						// outfit traversal.
-						cats.put(LLPointer<LLViewerInventoryCategory>(linked_cat));
-					}
-					collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE);
-				}
-			}
-		}
-	}
-	
 	// Move onto items
 	if(item_array)
 	{
@@ -748,6 +776,10 @@ LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID
 																	const LLUUID& start_folder_id)
 {
 	item_array_t items;
+	const LLInventoryObject *obj = getObject(id);
+	if (!obj || obj->getIsLinkType())
+		return items;
+	
 	LLInventoryModel::cat_array_t cat_array;
 	LLLinkedItemIDMatches is_linked_item_match(id);
 	collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id),
@@ -1123,8 +1155,197 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
 	notifyObservers();
 }
 
+void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
+{
+	LLTimer timer;
+	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+	{
+		dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+	}
+
+	AISUpdate ais_update(update); // parse update llsd into stuff to do.
+	ais_update.doUpdate(); // execute the updates in the appropriate order.
+	llinfos << "elapsed: " << timer.getElapsedTimeF32() << llendl;
+}
+
+void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version)
+{
+	U32 mask = LLInventoryObserver::NONE;
+
+	LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id);
+	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << llendl;
+	if(item)
+	{
+		for (LLSD::map_const_iterator it = updates.beginMap();
+			 it != updates.endMap(); ++it)
+		{
+			if (it->first == "name")
+			{
+				llinfos << "Updating name from " << item->getName() << " to " << it->second.asString() << llendl;
+				item->rename(it->second.asString());
+				mask |= LLInventoryObserver::LABEL;
+			}
+			else if (it->first == "desc")
+			{
+				llinfos << "Updating description from " << item->getActualDescription()
+						<< " to " << it->second.asString() << llendl;
+				item->setDescription(it->second.asString());
+			}
+			else
+			{
+				llerrs << "unhandled updates for field: " << it->first << llendl;
+			}
+		}
+		mask |= LLInventoryObserver::INTERNAL;
+		addChangedMask(mask, item->getUUID());
+		if (update_parent_version)
+		{
+			// Descendent count is unchanged, but folder version incremented.
+			LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0);
+			accountForUpdate(up);
+		}
+		gInventory.notifyObservers(); // do we want to be able to make this optional?
+	}
+}
+
+void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates)
+{
+	U32 mask = LLInventoryObserver::NONE;
+
+	LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id);
+	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << llendl;
+	if(cat)
+	{
+		for (LLSD::map_const_iterator it = updates.beginMap();
+			 it != updates.endMap(); ++it)
+		{
+			if (it->first == "name")
+			{
+				llinfos << "Updating name from " << cat->getName() << " to " << it->second.asString() << llendl;
+				cat->rename(it->second.asString());
+				mask |= LLInventoryObserver::LABEL;
+			}
+			else
+			{
+				llerrs << "unhandled updates for field: " << it->first << llendl;
+			}
+		}
+		mask |= LLInventoryObserver::INTERNAL;
+		addChangedMask(mask, cat->getUUID());
+		gInventory.notifyObservers(); // do we want to be able to make this optional?
+	}
+}
+
+// Update model after descendents have been purged.
+void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links)
+{
+	LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id);
+	if (cat.notNull())
+	{
+		// do the cache accounting
+		S32 descendents = cat->getDescendentCount();
+		if(descendents > 0)
+		{
+			LLInventoryModel::LLCategoryUpdate up(object_id, -descendents);
+			accountForUpdate(up);
+		}
+
+		// we know that descendent count is 0, however since the
+		// accounting may actually not do an update, we should force
+		// it here.
+		cat->setDescendentCount(0);
+
+		// unceremoniously remove anything we have locally stored.
+		LLInventoryModel::cat_array_t categories;
+		LLInventoryModel::item_array_t items;
+		collectDescendents(object_id,
+						   categories,
+						   items,
+						   LLInventoryModel::INCLUDE_TRASH);
+		S32 count = items.count();
+
+		LLUUID uu_id;
+		for(S32 i = 0; i < count; ++i)
+		{
+			uu_id = items.get(i)->getUUID();
+
+			// This check prevents the deletion of a previously deleted item.
+			// This is necessary because deletion is not done in a hierarchical
+			// order. The current item may have been already deleted as a child
+			// of its deleted parent.
+			if (getItem(uu_id))
+			{
+				deleteObject(uu_id, fix_broken_links);
+			}
+		}
+
+		count = categories.count();
+		// Slightly kludgy way to make sure categories are removed
+		// only after their child categories have gone away.
+
+		// FIXME: Would probably make more sense to have this whole
+		// descendent-clearing thing be a post-order recursive
+		// function to get the leaf-up behavior automatically.
+		S32 deleted_count;
+		S32 total_deleted_count = 0;
+		do
+		{
+			deleted_count = 0;
+			for(S32 i = 0; i < count; ++i)
+			{
+				uu_id = categories.get(i)->getUUID();
+				if (getCategory(uu_id))
+				{
+					cat_array_t* cat_list = getUnlockedCatArray(uu_id);
+					if (!cat_list || (cat_list->size() == 0))
+					{
+						deleteObject(uu_id, fix_broken_links);
+						deleted_count++;
+					}
+				}
+			}
+			total_deleted_count += deleted_count;
+		}
+		while (deleted_count > 0);
+		if (total_deleted_count != count)
+		{
+			llwarns << "Unexpected count of categories deleted, got "
+					<< total_deleted_count << " expected " << count << llendl;
+		}
+		//gInventory.validate();
+	}
+}
+
+// Update model after an item is confirmed as removed from
+// server. Works for categories or items.
+void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers)
+{
+	LLPointer<LLInventoryObject> obj = getObject(object_id);
+	if(obj)
+	{
+		if (getCategory(object_id))
+		{
+			// For category, need to delete/update all children first.
+			onDescendentsPurgedFromServer(object_id, fix_broken_links);
+		}
+
+
+		// From item/cat removeFromServer()
+		if (update_parent_version)
+		{
+			LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1);
+			accountForUpdate(up);
+		}
+
+		// From purgeObject()
+		LLPreview::hide(object_id);
+		deleteObject(object_id, fix_broken_links, do_notify_observers);
+	}
+}
+
+
 // Delete a particular inventory object by ID.
-void LLInventoryModel::deleteObject(const LLUUID& id)
+void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers)
 {
 	lldebugs << "LLInventoryModel::deleteObject()" << llendl;
 	LLPointer<LLInventoryObject> obj = getObject(id);
@@ -1155,31 +1376,37 @@ void LLInventoryModel::deleteObject(const LLUUID& id)
 	item_list = getUnlockedItemArray(id);
 	if(item_list)
 	{
+		if (item_list->size())
+		{
+			llwarns << "Deleting cat " << id << " while it still has child items" << llendl;
+		}
 		delete item_list;
 		mParentChildItemTree.erase(id);
 	}
 	cat_list = getUnlockedCatArray(id);
 	if(cat_list)
 	{
+		if (cat_list->size())
+		{
+			llwarns << "Deleting cat " << id << " while it still has child cats" << llendl;
+		}
 		delete cat_list;
 		mParentChildCategoryTree.erase(id);
 	}
 	addChangedMask(LLInventoryObserver::REMOVE, id);
+	
+	// Can't have links to links, so there's no need for this update
+	// if the item removed is a link. Can also skip if source of the
+	// update is getting broken link info separately.
+	bool is_link_type = obj->getIsLinkType();
 	obj = NULL; // delete obj
-	updateLinkedObjectsFromPurge(id);
-	gInventory.notifyObservers();
-}
-
-// Delete a particular inventory item by ID, and remove it from the server.
-void LLInventoryModel::purgeObject(const LLUUID &id)
-{
-	lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl;
-	LLPointer<LLInventoryObject> obj = getObject(id);
-	if(obj)
+	if (fix_broken_links && !is_link_type)
+	{
+		updateLinkedObjectsFromPurge(id);
+	}
+	if (do_notify_observers)
 	{
-		obj->removeFromServer();
-		LLPreview::hide(id);
-		deleteObject(id);
+		notifyObservers();
 	}
 }
 
@@ -1189,129 +1416,19 @@ void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)
 
 	// REBUILD is expensive, so clear the current change list first else
 	// everything else on the changelist will also get rebuilt.
-	gInventory.notifyObservers();
-	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
-		 iter != item_array.end();
-		 iter++)
-	{
-		const LLViewerInventoryItem *linked_item = (*iter);
-		const LLUUID &item_id = linked_item->getUUID();
-		if (item_id == baseobj_id) continue;
-		addChangedMask(LLInventoryObserver::REBUILD, item_id);
-	}
-	gInventory.notifyObservers();
-}
-
-// This is a method which collects the descendents of the id
-// provided. If the category is not found, no action is
-// taken. This method goes through the long winded process of
-// cancelling any calling cards, removing server representation of
-// folders, items, etc in a fairly efficient manner.
-void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
-{
-	EHasChildren children = categoryHasChildren(id);
-	if(children == CHILDREN_NO)
-	{
-		llinfos << "Not purging descendents of " << id << llendl;
-		return;
-	}
-	LLPointer<LLViewerInventoryCategory> cat = getCategory(id);
-	if (cat.notNull())
+	if (item_array.size() > 0)
 	{
-		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode())
+		gInventory.notifyObservers();
+		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+			iter != item_array.end();
+			iter++)
 		{
-			// Something on the clipboard is in "cut mode" and needs to be preserved
-			llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
-			<< " iterate and purge non hidden items" << llendl;
-			cat_array_t* categories;
-			item_array_t* items;
-			// Get the list of direct descendants in tha categoy passed as argument
-			getDirectDescendentsOf(id, categories, items);
-			std::vector<LLUUID> list_uuids;
-			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently)
-			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists
-			for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it)
-			{
-				list_uuids.push_back((*it)->getUUID());
-			}
-			for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it)
-			{
-				list_uuids.push_back((*it)->getUUID());
-			}
-			// Iterate through the list and only purge the UUIDs that are not on the clipboard
-			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it)
-			{
-				if (!LLClipboard::instance().isOnClipboard(*it))
-				{
-					purgeObject(*it);
-				}
-			}
-		}
-		else
-		{
-			// Fast purge
-			// do the cache accounting
-			llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
-				<< llendl;
-			S32 descendents = cat->getDescendentCount();
-			if(descendents > 0)
-			{
-				LLCategoryUpdate up(id, -descendents);
-				accountForUpdate(up);
-			}
-
-			// we know that descendent count is 0, however since the
-			// accounting may actually not do an update, we should force
-			// it here.
-			cat->setDescendentCount(0);
-
-			// send it upstream
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessage("PurgeInventoryDescendents");
-			msg->nextBlock("AgentData");
-			msg->addUUID("AgentID", gAgent.getID());
-			msg->addUUID("SessionID", gAgent.getSessionID());
-			msg->nextBlock("InventoryData");
-			msg->addUUID("FolderID", id);
-			gAgent.sendReliableMessage();
-
-			// unceremoniously remove anything we have locally stored.
-			cat_array_t categories;
-			item_array_t items;
-			collectDescendents(id,
-							   categories,
-							   items,
-							   INCLUDE_TRASH);
-			S32 count = items.count();
-
-			item_map_t::iterator item_map_end = mItemMap.end();
-			cat_map_t::iterator cat_map_end = mCategoryMap.end();
-			LLUUID uu_id;
-
-			for(S32 i = 0; i < count; ++i)
-			{
-				uu_id = items.get(i)->getUUID();
-
-				// This check prevents the deletion of a previously deleted item.
-				// This is necessary because deletion is not done in a hierarchical
-				// order. The current item may have been already deleted as a child
-				// of its deleted parent.
-				if (mItemMap.find(uu_id) != item_map_end)
-				{
-					deleteObject(uu_id);
-				}
-			}
-
-			count = categories.count();
-			for(S32 i = 0; i < count; ++i)
-			{
-				uu_id = categories.get(i)->getUUID();
-				if (mCategoryMap.find(uu_id) != cat_map_end)
-				{
-					deleteObject(uu_id);
-				}
-			}
+			const LLViewerInventoryItem *linked_item = (*iter);
+			const LLUUID &item_id = linked_item->getUUID();
+			if (item_id == baseobj_id) continue;
+			addChangedMask(LLInventoryObserver::REBUILD, item_id);
 		}
+		gInventory.notifyObservers();
 	}
 }
 
@@ -1396,8 +1513,14 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)
 }
 
 // If we get back a normal response, handle it here
-void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)
-{	
+void LLInventoryModel::fetchInventoryResponder::httpSuccess()
+{
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	start_new_inventory_observer();
 
 	/*LLUUID agent_id;
@@ -1456,9 +1579,9 @@ void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)
 }
 
 //If we get back an error (not found, etc...), handle it here
-void LLInventoryModel::fetchInventoryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLInventoryModel::fetchInventoryResponder::httpFailure()
 {
-	llwarns << "fetchInventory error [status:" << status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 	gInventory.notifyObservers();
 }
 
@@ -1665,47 +1788,6 @@ void LLInventoryModel::accountForUpdate(
 	}
 }
 
-
-/*
-void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id)
-{
-	LLViewerInventoryCategory* cat = getCategory(category_id);
-	if(cat)
-	{
-		S32 version = cat->getVersion();
-		if(LLViewerInventoryCategory::VERSION_UNKNOWN != version)
-		{
-			cat->setVersion(version + 1);
-			llinfos << "IncrementVersion: " << cat->getName() << " "
-					<< cat->getVersion() << llendl;
-		}
-		else
-		{
-			llinfos << "Attempt to increment version when unknown: "
-					<< category_id << llendl;
-		}
-	}
-	else
-	{
-		llinfos << "Attempt to increment category: " << category_id << llendl;
-	}
-}
-void LLInventoryModel::incrementCategorySetVersion(
-	const std::set<LLUUID>& categories)
-{
-	if(!categories.empty())
-	{ 
-		std::set<LLUUID>::const_iterator it = categories.begin();
-		std::set<LLUUID>::const_iterator end = categories.end();
-		for(; it != end; ++it)
-		{
-			incrementCategoryVersion(*it);
-		}
-	}
-}
-*/
-
-
 LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(
 	const LLUUID& cat_id) const
 {
@@ -2091,11 +2173,16 @@ void LLInventoryModel::buildParentChildMap()
 	S32 count = cats.count();
 	S32 i;
 	S32 lost = 0;
+	cat_array_t lost_cats;
 	for(i = 0; i < count; ++i)
 	{
 		LLViewerInventoryCategory* cat = cats.get(i);
 		catsp = getUnlockedCatArray(cat->getParentUUID());
-		if(catsp)
+		if(catsp &&
+		   // Only the two root folders should be children of null.
+		   // Others should go to lost & found.
+		   (cat->getParentUUID().notNull() || 
+			cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY ))
 		{
 			catsp->put(cat);
 		}
@@ -2107,35 +2194,10 @@ void LLInventoryModel::buildParentChildMap()
 			// implement it, we would need a set or map of uuid pairs
 			// which would be (folder_id, new_parent_id) to be sent up
 			// to the server.
-			llinfos << "Lost categroy: " << cat->getUUID() << " - "
+			llinfos << "Lost category: " << cat->getUUID() << " - "
 					<< cat->getName() << llendl;
 			++lost;
-			// plop it into the lost & found.
-			LLFolderType::EType pref = cat->getPreferredType();
-			if(LLFolderType::FT_NONE == pref)
-			{
-				cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
-			}
-			else if(LLFolderType::FT_ROOT_INVENTORY == pref)
-			{
-				// it's the root
-				cat->setParent(LLUUID::null);
-			}
-			else
-			{
-				// it's a protected folder.
-				cat->setParent(gInventory.getRootFolderID());
-			}
-			cat->updateServer(TRUE);
-			catsp = getUnlockedCatArray(cat->getParentUUID());
-			if(catsp)
-			{
-				catsp->put(cat);
-			}
-			else
-			{		
-				llwarns << "Lost and found Not there!!" << llendl;
-			}
+			lost_cats.put(cat);
 		}
 	}
 	if(lost)
@@ -2143,6 +2205,42 @@ void LLInventoryModel::buildParentChildMap()
 		llwarns << "Found  " << lost << " lost categories." << llendl;
 	}
 
+	// Do moves in a separate pass to make sure we've properly filed
+	// the FT_LOST_AND_FOUND category before we try to find its UUID.
+	for(i = 0; i<lost_cats.count(); ++i)
+	{
+		LLViewerInventoryCategory *cat = lost_cats.get(i);
+
+		// plop it into the lost & found.
+		LLFolderType::EType pref = cat->getPreferredType();
+		if(LLFolderType::FT_NONE == pref)
+		{
+			cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
+		}
+		else if(LLFolderType::FT_ROOT_INVENTORY == pref)
+		{
+			// it's the root
+			cat->setParent(LLUUID::null);
+		}
+		else
+		{
+			// it's a protected folder.
+			cat->setParent(gInventory.getRootFolderID());
+		}
+		// FIXME note that updateServer() fails with protected
+		// types, so this will not work as intended in that case.
+		cat->updateServer(TRUE);
+		catsp = getUnlockedCatArray(cat->getParentUUID());
+		if(catsp)
+		{
+			catsp->put(cat);
+		}
+		else
+		{		
+			llwarns << "Lost and found Not there!!" << llendl;
+		}
+	}
+
 	const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);
 	sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin();
 
@@ -2271,6 +2369,11 @@ void LLInventoryModel::buildParentChildMap()
 			notifyObservers();
 		}
 	}
+
+	if (!gInventory.validate())
+	{
+	 	llwarns << "model failed validity check!" << llendl;
+	}
 }
 
 struct LLUUIDAndName
@@ -2809,7 +2912,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 	LLUUID tid;
 	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);
 #ifndef LL_RELEASE_FOR_DOWNLOAD
-	llinfos << "Bulk inventory: " << tid << llendl;
+	LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << llendl;
 #endif
 
 	update_map_t update;
@@ -2821,9 +2924,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 	{
 		LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
 		tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
-		llinfos << "unpacked folder '" << tfolder->getName() << "' ("
-				<< tfolder->getUUID() << ") in " << tfolder->getParentUUID()
-				<< llendl;
+		LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' ("
+							   << tfolder->getUUID() << ") in " << tfolder->getParentUUID()
+							   << llendl;
 		if(tfolder->getUUID().notNull())
 		{
 			folders.push_back(tfolder);
@@ -2863,8 +2966,8 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 	{
 		LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
 		titem->unpackMessage(msg, _PREHASH_ItemData, i);
-		llinfos << "unpacked item '" << titem->getName() << "' in "
-				<< titem->getParentUUID() << llendl;
+		LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in "
+							   << titem->getParentUUID() << llendl;
 		U32 callback_id;
 		msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);
 		if(titem->getUUID().notNull() ) // && callback_id.notNull() )
@@ -2941,6 +3044,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 		InventoryCallbackInfo cbinfo = (*inv_it);
 		gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
 	}
+
+	//gInventory.validate();
+
 	// Don't show the inventory.  We used to call showAgentInventory here.
 	//LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
 	//if(view)
@@ -2999,7 +3105,8 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)
 		// If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added.
 		if (gInventory.getItem(titem->getUUID()))
 		{
-			lldebugs << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl;
+			LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName()
+								   << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl;
 			continue;
 		}
 		gInventory.updateItem(titem);
@@ -3085,8 +3192,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L
 	if (option == 0) // YES
 	{
 		const LLUUID folder_id = findCategoryUUIDForType(preferred_type);
-		purgeDescendentsOf(folder_id);
-		notifyObservers();
+		purge_descendents_of(folder_id, NULL);
 	}
 	return false;
 }
@@ -3101,8 +3207,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT
 	else
 	{
 		const LLUUID folder_id = findCategoryUUIDForType(preferred_type);
-		purgeDescendentsOf(folder_id);
-		notifyObservers();
+		purge_descendents_of(folder_id, NULL);
 	}
 }
 
@@ -3389,6 +3494,254 @@ void LLInventoryModel::dumpInventory() const
 	llinfos << "\n**********************\nEnd Inventory Dump" << llendl;
 }
 
+// Do various integrity checks on model, logging issues found and
+// returning an overall good/bad flag.
+bool LLInventoryModel::validate() const
+{
+	bool valid = true;
+
+	if (getRootFolderID().isNull())
+	{
+		llwarns << "no root folder id" << llendl;
+		valid = false;
+	}
+	if (getLibraryRootFolderID().isNull())
+	{
+		llwarns << "no root folder id" << llendl;
+		valid = false;
+	}
+
+	if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size())
+	{
+		// ParentChild should be one larger because of the special entry for null uuid.
+		llinfos << "unexpected sizes: cat map size " << mCategoryMap.size()
+				<< " parent/child " << mParentChildCategoryTree.size() << llendl;
+		valid = false;
+	}
+	S32 cat_lock = 0;
+	S32 item_lock = 0;
+	S32 desc_unknown_count = 0;
+	S32 version_unknown_count = 0;
+	for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
+	{
+		const LLUUID& cat_id = cit->first;
+		const LLViewerInventoryCategory *cat = cit->second;
+		if (!cat)
+		{
+			llwarns << "invalid cat" << llendl;
+			valid = false;
+			continue;
+		}
+		if (cat_id != cat->getUUID())
+		{
+			llwarns << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << llendl;
+			valid = false;
+		}
+
+		if (cat->getParentUUID().isNull())
+		{
+			if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID())
+			{
+				llwarns << "cat " << cat_id << " has no parent, but is not root ("
+						<< getRootFolderID() << ") or library root ("
+						<< getLibraryRootFolderID() << ")" << llendl;
+			}
+		}
+		cat_array_t* cats;
+		item_array_t* items;
+		getDirectDescendentsOf(cat_id,cats,items);
+		if (!cats || !items)
+		{
+			llwarns << "invalid direct descendents for " << cat_id << llendl;
+			valid = false;
+			continue;
+		}
+		if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
+		{
+			desc_unknown_count++;
+		}
+		else if (cats->size() + items->size() != cat->getDescendentCount())
+		{
+			llwarns << "invalid desc count for " << cat_id << " name [" << cat->getName()
+					<< "] parent " << cat->getParentUUID()
+					<< " cached " << cat->getDescendentCount()
+					<< " expected " << cats->size() << "+" << items->size()
+					<< "=" << cats->size() +items->size() << llendl;
+			valid = false;
+		}
+		if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)
+		{
+			version_unknown_count++;
+		}
+		if (mCategoryLock.count(cat_id))
+		{
+			cat_lock++;
+		}
+		if (mItemLock.count(cat_id))
+		{
+			item_lock++;
+		}
+		for (S32 i = 0; i<items->size(); i++)
+		{
+			LLViewerInventoryItem *item = items->get(i);
+
+			if (!item)
+			{
+				llwarns << "null item at index " << i << " for cat " << cat_id << llendl;
+				valid = false;
+				continue;
+			}
+
+			const LLUUID& item_id = item->getUUID();
+			
+			if (item->getParentUUID() != cat_id)
+			{
+				llwarns << "wrong parent for " << item_id << " found "
+						<< item->getParentUUID() << " expected " << cat_id
+						<< llendl;
+				valid = false;
+			}
+
+
+			// Entries in items and mItemMap should correspond.
+			item_map_t::const_iterator it = mItemMap.find(item_id);
+			if (it == mItemMap.end())
+			{
+				llwarns << "item " << item_id << " found as child of "
+						<< cat_id << " but not in top level mItemMap" << llendl;
+				valid = false;
+			}
+			else
+			{
+				LLViewerInventoryItem *top_item = it->second;
+				if (top_item != item)
+				{
+					llwarns << "item mismatch, item_id " << item_id
+							<< " top level entry is different, uuid " << top_item->getUUID() << llendl;
+				}
+			}
+
+			// Topmost ancestor should be root or library.
+			LLUUID topmost_ancestor_id;
+			bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id);
+			if (!found)
+			{
+				llwarns << "unable to find topmost ancestor for " << item_id << llendl;
+				valid = false;
+			}
+			else
+			{
+				if (topmost_ancestor_id != getRootFolderID() &&
+					topmost_ancestor_id != getLibraryRootFolderID())
+				{
+					llwarns << "unrecognized top level ancestor for " << item_id
+							<< " got " << topmost_ancestor_id
+							<< " expected " << getRootFolderID()
+							<< " or " << getLibraryRootFolderID() << llendl;
+					valid = false;
+				}
+			}
+		}
+
+		// Does this category appear as a child of its supposed parent?
+		const LLUUID& parent_id = cat->getParentUUID();
+		if (!parent_id.isNull())
+		{
+			cat_array_t* cats;
+			item_array_t* items;
+			getDirectDescendentsOf(parent_id,cats,items);
+			if (!cats)
+			{
+				llwarns << "cat " << cat_id << " name [" << cat->getName()
+						<< "] orphaned - no child cat array for alleged parent " << parent_id << llendl;
+				valid = false;
+			}
+			else
+			{
+				bool found = false;
+				for (S32 i = 0; i<cats->size(); i++)
+				{
+					LLViewerInventoryCategory *kid_cat = cats->get(i);
+					if (kid_cat == cat)
+					{
+						found = true;
+						break;
+					}
+				}
+				if (!found)
+				{
+					llwarns << "cat " << cat_id << " name [" << cat->getName()
+							<< "] orphaned - not found in child cat array of alleged parent " << parent_id << llendl;
+				}
+			}
+		}
+	}
+
+	for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
+	{
+		const LLUUID& item_id = iit->first;
+		LLViewerInventoryItem *item = iit->second;
+		if (item->getUUID() != item_id)
+		{
+			llwarns << "item_id " << item_id << " does not match " << item->getUUID() << llendl;
+			valid = false;
+		}
+
+		const LLUUID& parent_id = item->getParentUUID();
+		if (parent_id.isNull())
+		{
+			llwarns << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << llendl;
+		}
+		else
+		{
+			cat_array_t* cats;
+			item_array_t* items;
+			getDirectDescendentsOf(parent_id,cats,items);
+			if (!items)
+			{
+				llwarns << "item " << item_id << " name [" << item->getName()
+						<< "] orphaned - alleged parent has no child items list " << parent_id << llendl;
+			}
+			else
+			{
+				bool found = false;
+				for (S32 i=0; i<items->size(); ++i)
+				{
+					if (items->get(i) == item) 
+					{
+						found = true;
+						break;
+					}
+				}
+				if (!found)
+				{
+					llwarns << "item " << item_id << " name [" << item->getName()
+							<< "] orphaned - not found as child of alleged parent " << parent_id << llendl;
+				}
+			}
+				
+		}
+	}
+	
+	if (cat_lock > 0 || item_lock > 0)
+	{
+		llwarns << "Found locks on some categories: sub-cat arrays "
+				<< cat_lock << ", item arrays " << item_lock << llendl;
+	}
+	if (desc_unknown_count != 0)
+	{
+		llinfos << "Found " << desc_unknown_count << " cats with unknown descendent count" << llendl; 
+	}
+	if (version_unknown_count != 0)
+	{
+		llinfos << "Found " << version_unknown_count << " cats with unknown version" << llendl;
+	}
+
+	llinfos << "Validate done, valid = " << (U32) valid << llendl;
+
+	return valid;
+}
+
 ///----------------------------------------------------------------------------
 /// Local function definitions
 ///----------------------------------------------------------------------------
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 8aac879a93780c1e9b27296b6589905b9684d938..5de951ed05c27b580ae438d2b8490a031e87db17 100755
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -81,11 +81,12 @@ class LLInventoryModel
 
 	class fetchInventoryResponder : public LLHTTPClient::Responder
 	{
+		LOG_CLASS(fetchInventoryResponder);
 	public:
 		fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
-		void result(const LLSD& content);			
-		void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
 	protected:
+		virtual void httpSuccess();
+		virtual void httpFailure();
 		LLSD mRequestSD;
 	};
 
@@ -204,6 +205,9 @@ class LLInventoryModel
 		EXCLUDE_TRASH = FALSE, 
 		INCLUDE_TRASH = TRUE 
 	};
+	// Simpler existence test if matches don't actually need to be collected.
+	bool hasMatchingDirectDescendent(const LLUUID& cat_id,
+									 LLInventoryCollectFunctor& filter);
 	void collectDescendents(const LLUUID& id,
 							cat_array_t& categories,
 							item_array_t& items,
@@ -212,8 +216,7 @@ class LLInventoryModel
 							  cat_array_t& categories,
 							  item_array_t& items,
 							  BOOL include_trash,
-							  LLInventoryCollectFunctor& add,
-							  BOOL follow_folder_links = FALSE);
+							  LLInventoryCollectFunctor& add);
 
 	// Collect all items in inventory that are linked to item_id.
 	// Assumes item_id is itself not a linked item.
@@ -224,6 +227,9 @@ class LLInventoryModel
 	// Check if one object has a parent chain up to the category specified by UUID.
 	BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id) const;
 
+	// Follow parent chain to the top.
+	bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const;
+	
 	//--------------------------------------------------------------------
 	// Find
 	//--------------------------------------------------------------------
@@ -322,11 +328,31 @@ class LLInventoryModel
 	// Delete
 	//--------------------------------------------------------------------
 public:
+
+	// Update model after an AISv3 update received for any operation.
+	void onAISUpdateReceived(const std::string& context, const LLSD& update);
+		
+	// Update model after an item is confirmed as removed from
+	// server. Works for categories or items.
+	void onObjectDeletedFromServer(const LLUUID& item_id,
+								   bool fix_broken_links = true,
+								   bool update_parent_version = true,
+								   bool do_notify_observers = true);
+
+	// Update model after all descendents removed from server.
+	void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);
+
+	// Update model after an existing item gets updated on server.
+	void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version);
+
+	// Update model after an existing category gets updated on server.
+	void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates);
+
 	// Delete a particular inventory object by ID. Will purge one
 	// object from the internal data structures, maintaining a
 	// consistent internal state. No cache accounting, observer
 	// notification, or server update is performed.
-	void deleteObject(const LLUUID& id);
+	void deleteObject(const LLUUID& id, bool fix_broken_links = true, bool do_notify_observers = true);
 	/// move Item item_id to Trash
 	void removeItem(const LLUUID& item_id);
 	/// move Category category_id to Trash
@@ -334,17 +360,6 @@ class LLInventoryModel
 	/// removeItem() or removeCategory(), whichever is appropriate
 	void removeObject(const LLUUID& object_id);
 
-	// Delete a particular inventory object by ID, and delete it from
-	// the server. Also updates linked items.
-	void purgeObject(const LLUUID& id);
-
-	// Collects and purges the descendants of the id
-	// provided. If the category is not found, no action is
-	// taken. This method goes through the long winded process of
-	// removing server representation of folders and items while doing
-	// cache accounting in a fairly efficient manner. This method does
-	// not notify observers (though maybe it should...)
-	void purgeDescendentsOf(const LLUUID& id);
 protected:
 	void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id);
 	
@@ -551,6 +566,7 @@ class LLInventoryModel
 	//--------------------------------------------------------------------
 public:
 	void dumpInventory() const;
+	bool validate() const;
 
 /**                    Miscellaneous
  **                                                                            **
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index f2b39e71863d35f0f962f47d78677b2031d90f75..864f38cbde2b71ec13e863deeb18fccc93beffeb 100755
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -1,6 +1,6 @@
 /** 
- * @file llinventorymodel.cpp
- * @brief Implementation of the inventory model used to track agent inventory.
+ * @file llinventorymodelbackgroundfetch.cpp
+ * @brief Implementation of background fetching of inventory.
  *
  * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -172,8 +172,11 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
 		mRecursiveLibraryFetchStarted)
 	{
 		mAllFoldersFetched = TRUE;
+		//llinfos << "All folders fetched, validating" << llendl;
+		//gInventory.validate();
 	}
 	mFolderFetchActive = false;
+	mBackgroundFetchActive = false;
 }
 
 void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
@@ -363,35 +366,40 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching)
 
 class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder
 {
+	LOG_CLASS(LLInventoryModelFetchItemResponder);
 public:
-	LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {};
-	void result(const LLSD& content);			
-	void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+	LLInventoryModelFetchItemResponder(const LLSD& request_sd) :
+		LLInventoryModel::fetchInventoryResponder(request_sd)
+	{
+		LLInventoryModelBackgroundFetch::instance().incrFetchCount(1);
+	}
+private:
+	/* virtual */ void httpCompleted()
+	{
+		LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+		LLInventoryModel::fetchInventoryResponder::httpCompleted();
+	}
 };
 
-void LLInventoryModelFetchItemResponder::result( const LLSD& content )
-{
-	LLInventoryModel::fetchInventoryResponder::result(content);
-	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
-}
-
-void LLInventoryModelFetchItemResponder::errorWithContent( U32 status, const std::string& reason, const LLSD& content )
-{
-	LLInventoryModel::fetchInventoryResponder::errorWithContent(status, reason, content);
-	LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
-}
-
-
 class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLInventoryModelFetchDescendentsResponder);
 public:
 	LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : 
 		mRequestSD(request_sd),
 		mRecursiveCatUUIDs(recursive_cats)
-	{};
+	{
+		LLInventoryModelBackgroundFetch::instance().incrFetchCount(1);
+	}
 	//LLInventoryModelFetchDescendentsResponder() {};
-	void result(const LLSD& content);
-	void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+private:
+	/* virtual */ void httpCompleted()
+	{
+		LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+		LLHTTPClient::Responder::httpCompleted();
+	}
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
 protected:
 	BOOL getIsRecursive(const LLUUID& cat_id) const;
 private:
@@ -400,8 +408,14 @@ class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
 };
 
 // If we get back a normal response, handle it here.
-void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
+void LLInventoryModelFetchDescendentsResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
 	if (content.has("folders"))	
 	{
@@ -508,16 +522,15 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
 		for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();
 			folder_it != content["bad_folders"].endArray();
 			++folder_it)
-		{	
+		{
+			// *TODO: Stop copying data
 			LLSD folder_sd = *folder_it;
 			
 			// These folders failed on the dataserver.  We probably don't want to retry them.
-			llinfos << "Folder " << folder_sd["folder_id"].asString() 
+			llwarns << "Folder " << folder_sd["folder_id"].asString() 
 					<< "Error: " << folder_sd["error"].asString() << llendl;
 		}
 	}
-
-	fetcher->incrFetchCount(-1);
 	
 	if (fetcher->isBulkFetchProcessingComplete())
 	{
@@ -529,21 +542,17 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
 }
 
 // If we get back an error (not found, etc...), handle it here.
-void LLInventoryModelFetchDescendentsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLInventoryModelFetchDescendentsResponder::httpFailure()
 {
+	llwarns << dumpResponse() << llendl;
 	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
 
-	llinfos << "LLInventoryModelFetchDescendentsResponder::error [status:"
-			<< status << "]: " << content << llendl;
-						
-	fetcher->incrFetchCount(-1);
-
-	if (status==499) // timed out
+	if (getStatus()==HTTP_INTERNAL_ERROR) // timed out or curl failure
 	{
 		for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();
 			folder_it != mRequestSD["folders"].endArray();
 			++folder_it)
-		{	
+		{
 			LLSD folder_sd = *folder_it;
 			LLUUID folder_id = folder_sd["folder_id"];
 			const BOOL recursive = getIsRecursive(folder_id);
@@ -586,7 +595,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
 	{
 		return; // just bail if we are disconnected
-	}	
+	}
 
 	U32 item_count=0;
 	U32 folder_count=0;
@@ -689,7 +698,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 			std::string url = region->getCapability("FetchInventoryDescendents2");   			
 			if ( !url.empty() )
 			{
-				mFetchCount++;
 				if (folder_request_body["folders"].size())
 				{
 					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
@@ -702,7 +710,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
 					LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
 				}
-			}					
+			}
 		}
 		if (item_count)
 		{
@@ -710,39 +718,23 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 
 			if (item_request_body.size())
 			{
-				mFetchCount++;
 				url = region->getCapability("FetchInventory2");
 				if (!url.empty())
 				{
 					LLSD body;
-					body["agent_id"]	= gAgent.getID();
 					body["items"] = item_request_body;
 
 					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
 				}
-				//else
-				//{
-				//	LLMessageSystem* msg = gMessageSystem;
-				//	msg->newMessage("FetchInventory");
-				//	msg->nextBlock("AgentData");
-				//	msg->addUUID("AgentID", gAgent.getID());
-				//	msg->addUUID("SessionID", gAgent.getSessionID());
-				//	msg->nextBlock("InventoryData");
-				//	msg->addUUID("OwnerID", mPermissions.getOwner());
-				//	msg->addUUID("ItemID", mUUID);
-				//	gAgent.sendReliableMessage();
-				//}
 			}
 
 			if (item_request_body_lib.size())
 			{
-				mFetchCount++;
 
 				url = region->getCapability("FetchLib2");
 				if (!url.empty())
 				{
 					LLSD body;
-					body["agent_id"]	= gAgent.getID();
 					body["items"] = item_request_body_lib;
 
 					LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body));
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index 0b009b68f74ae87e4854a767b8cf2ef9aecbd60f..28e1df725aee7841246c2d8b4ba0ea5c116d08ef 100755
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -99,7 +99,7 @@ namespace LLMarketplaceImport
 	bool hasSessionCookie();
 	bool inProgress();
 	bool resultPending();
-	U32 getResultStatus();
+	S32 getResultStatus();
 	const LLSD& getResults();
 
 	bool establishMarketplaceSessionCookie();
@@ -113,7 +113,7 @@ namespace LLMarketplaceImport
 	static bool sImportInProgress = false;
 	static bool sImportPostPending = false;
 	static bool sImportGetPending = false;
-	static U32 sImportResultStatus = 0;
+	static S32 sImportResultStatus = 0;
 	static LLSD sImportResults = LLSD::emptyMap();
 
 	static LLTimer slmGetTimer;
@@ -123,22 +123,22 @@ namespace LLMarketplaceImport
 	
 	class LLImportPostResponder : public LLHTTPClient::Responder
 	{
+		LOG_CLASS(LLImportPostResponder);
 	public:
 		LLImportPostResponder() : LLCurl::Responder() {}
-		
-		void completed(U32 status, const std::string& reason, const LLSD& content)
+
+	protected:
+		/* virtual */ void httpCompleted()
 		{
 			slmPostTimer.stop();
 
 			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
 			{
-				llinfos << " SLM POST status: " << status << llendl;
-				llinfos << " SLM POST reason: " << reason << llendl;
-				llinfos << " SLM POST content: " << content.asString() << llendl;
-
-				llinfos << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << llendl;
+				llinfos << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] "
+						<< dumpResponse() << llendl;
 			}
 
+			S32 status = getStatus();
 			if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) ||
 				(status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||
 				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))
@@ -154,38 +154,35 @@ namespace LLMarketplaceImport
 			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE);
 			sImportPostPending = false;
 			sImportResultStatus = status;
-			sImportId = content;
+			sImportId = getContent();
 		}
 	};
 	
 	class LLImportGetResponder : public LLHTTPClient::Responder
 	{
+		LOG_CLASS(LLImportGetResponder);
 	public:
 		LLImportGetResponder() : LLCurl::Responder() {}
 		
-		void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+	protected:
+		/* virtual */ void httpCompleted()
 		{
-			const std::string& set_cookie_string = content["set-cookie"].asString();
+			const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
 			
 			if (!set_cookie_string.empty())
 			{
 				sMarketplaceCookie = set_cookie_string;
 			}
-		}
-		
-		void completed(U32 status, const std::string& reason, const LLSD& content)
-		{
+
 			slmGetTimer.stop();
 
 			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
 			{
-				llinfos << " SLM GET status: " << status << llendl;
-				llinfos << " SLM GET reason: " << reason << llendl;
-				llinfos << " SLM GET content: " << content.asString() << llendl;
-
-				llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl;
+				llinfos << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] "
+						<< dumpResponse() << llendl;
 			}
 			
+			S32 status = getStatus();
 			if ((status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||
 				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))
 			{
@@ -200,7 +197,7 @@ namespace LLMarketplaceImport
 			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);
 			sImportGetPending = false;
 			sImportResultStatus = status;
-			sImportResults = content;
+			sImportResults = getContent();
 		}
 	};
 
@@ -221,7 +218,7 @@ namespace LLMarketplaceImport
 		return (sImportPostPending || sImportGetPending);
 	}
 	
-	U32 getResultStatus()
+	S32 getResultStatus()
 	{
 		return sImportResultStatus;
 	}
@@ -280,10 +277,11 @@ namespace LLMarketplaceImport
 
 		// Make the headers for the post
 		LLSD headers = LLSD::emptyMap();
-		headers["Accept"] = "*/*";
-		headers["Cookie"] = sMarketplaceCookie;
-		headers["Content-Type"] = "application/llsd+xml";
-		headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent();
+		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
+		headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie;
+		// *TODO: Why are we setting Content-Type for a GET request?
+		headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;
+		headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();
 		
 		if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
 		{
@@ -313,11 +311,11 @@ namespace LLMarketplaceImport
 		
 		// Make the headers for the post
 		LLSD headers = LLSD::emptyMap();
-		headers["Accept"] = "*/*";
-		headers["Connection"] = "Keep-Alive";
-		headers["Cookie"] = sMarketplaceCookie;
-		headers["Content-Type"] = "application/xml";
-		headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent();
+		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
+		headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive";
+		headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie;
+		headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML;
+		headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent();
 		
 		if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
 		{
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 2075aeed63210d69a80e552a4f3361dc026b0eb3..cb5640b4da1656401ff3332ede0e6487dcf32e56 100755
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -52,6 +52,7 @@
 #include "llsdutil.h"
 #include "lllayoutstack.h"
 #include "lliconctrl.h"
+#include "llhttpconstants.h"
 #include "lltextbox.h"
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
@@ -576,7 +577,7 @@ void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::str
 	{
 		mCurrentNavUrl = expanded_filename;
 		mMediaSource->setSize(mTextureWidth, mTextureHeight);
-		mMediaSource->navigateTo(expanded_filename, "text/html", false);
+		mMediaSource->navigateTo(expanded_filename, HTTP_CONTENT_TEXT_HTML, false);
 	}
 }
 
@@ -948,7 +949,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL;
 			if ( mErrorPageURL.length() > 0 )
 			{
-				navigateTo(mErrorPageURL, "text/html");
+				navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML);
 			};
 		};
 		break;
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index e3b46d5d2f3fd7727d844cf69d51e1c3e94b330f..691be13610e4b5e7908a53d71546631ab0968159 100755
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -35,7 +35,7 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 #include "llsdutil.h"
 #include "llmediaentry.h"
 #include "lltextureentry.h"
@@ -564,7 +564,7 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
 }
 
 /*virtual*/
-void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLMediaDataClient::Responder::httpFailure()
 {
 	mRequest->stopTracking();
 
@@ -574,9 +574,17 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin
 		return;
 	}
 	
-	if (status == HTTP_SERVICE_UNAVAILABLE)
+	if (getStatus() == HTTP_SERVICE_UNAVAILABLE)
 	{
-		F32 retry_timeout = mRequest->getRetryTimerDelay();
+		F32 retry_timeout;
+#if 0
+		// *TODO: Honor server Retry-After header.
+		if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER)
+			|| !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout))
+#endif
+		{
+			retry_timeout = mRequest->getRetryTimerDelay();
+		}
 		
 		mRequest->incRetryCount();
 		
@@ -594,15 +602,16 @@ void LLMediaDataClient::Responder::errorWithContent(U32 status, const std::strin
 				<< mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
 		}
 	}
+	// *TODO: Redirect on 3xx status codes.
 	else 
 	{
-		LL_WARNS("LLMediaDataClient") << *mRequest << " http error [status:" 
-				<< status << "]:" << content << ")" << LL_ENDL;
+		LL_WARNS("LLMediaDataClient") << *mRequest << " http failure "
+				<< dumpResponse() << LL_ENDL;
 	}
 }
 
 /*virtual*/
-void LLMediaDataClient::Responder::result(const LLSD& content)
+void LLMediaDataClient::Responder::httpSuccess()
 {
 	mRequest->stopTracking();
 
@@ -612,7 +621,7 @@ void LLMediaDataClient::Responder::result(const LLSD& content)
 		return;
 	}
 
-	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL;
+	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -876,7 +885,7 @@ LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResp
 
 
 /*virtual*/
-void LLObjectMediaDataClient::Responder::result(const LLSD& content)
+void LLObjectMediaDataClient::Responder::httpSuccess()
 {
 	getRequest()->stopTracking();
 
@@ -886,10 +895,16 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content)
 		return;
 	}
 
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
+
 	// This responder is only used for GET requests, not UPDATE.
+	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL;
 
-	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL;
-	
 	// Look for an error
 	if (content.has("error"))
 	{
@@ -1003,7 +1018,7 @@ LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::crea
 }
 
 /*virtual*/
-void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLObjectMediaNavigateClient::Responder::httpFailure()
 {
 	getRequest()->stopTracking();
 
@@ -1015,14 +1030,14 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const
 
 	// Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base
 	// class
-	if (status == HTTP_SERVICE_UNAVAILABLE)
+	if (getStatus() == HTTP_SERVICE_UNAVAILABLE)
 	{
-		LLMediaDataClient::Responder::errorWithContent(status, reason, content);
+		LLMediaDataClient::Responder::httpFailure();
 	}
 	else
 	{
 		// bounce the face back
-		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL;
+		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL;
 		const LLSD &payload = getRequest()->getPayload();
 		// bounce the face back
 		getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
@@ -1030,7 +1045,7 @@ void LLObjectMediaNavigateClient::Responder::errorWithContent(U32 status, const
 }
 
 /*virtual*/
-void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
+void LLObjectMediaNavigateClient::Responder::httpSuccess()
 {
 	getRequest()->stopTracking();
 
@@ -1040,8 +1055,9 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
 		return;
 	}
 
-	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL;
+	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL;
 	
+	const LLSD& content = getContent();
 	if (content.has("error"))
 	{
 		const LLSD &error = content["error"];
@@ -1065,6 +1081,6 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content)
 	else 
 	{
 		// No action required.
-		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(content) << LL_ENDL;
+		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL;
 	}
 }
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 89e20a28d097e95c732b206fb509a9ec7498ea61..231b883c32c6f9d157839a2911622a2604eda2a2 100755
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -74,8 +74,9 @@ class LLMediaDataClientObject : public LLRefCount
 // Abstracts the Cap URL, the request, and the responder
 class LLMediaDataClient : public LLRefCount
 {
-public:
+protected:
     LOG_CLASS(LLMediaDataClient);
+public:
     
     const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)
 	const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs
@@ -192,14 +193,16 @@ class LLMediaDataClient : public LLRefCount
 	// Responder
 	class Responder : public LLHTTPClient::Responder
 	{
+		LOG_CLASS(Responder);
 	public:
 		Responder(const request_ptr_t &request);
+		request_ptr_t &getRequest() { return mRequest; }
+
+	protected:
 		//If we get back an error (not found, etc...), handle it here
-		virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+		virtual void httpFailure();
 		//If we get back a normal response, handle it here.	 Default just logs it.
-		virtual void result(const LLSD& content);
-
-		request_ptr_t &getRequest() { return mRequest; }
+		virtual void httpSuccess();
 
 	private:
 		request_ptr_t mRequest;
@@ -287,8 +290,9 @@ class LLMediaDataClient : public LLRefCount
 // MediaDataClient specific for the ObjectMedia cap
 class LLObjectMediaDataClient : public LLMediaDataClient
 {
-public:
+protected:
     LOG_CLASS(LLObjectMediaDataClient);
+public:
     LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
 							F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
 							U32 max_retries = MAX_RETRIES,
@@ -341,10 +345,12 @@ class LLObjectMediaDataClient : public LLMediaDataClient
 		    
     class Responder : public LLMediaDataClient::Responder
     {
+        LOG_CLASS(Responder);
     public:
         Responder(const request_ptr_t &request)
             : LLMediaDataClient::Responder(request) {}
-        virtual void result(const LLSD &content);
+    protected:
+        virtual void httpSuccess();
     };
 private:
 	// The Get/Update data client needs a second queue to avoid object updates starving load-ins.
@@ -362,8 +368,9 @@ class LLObjectMediaDataClient : public LLMediaDataClient
 // MediaDataClient specific for the ObjectMediaNavigate cap
 class LLObjectMediaNavigateClient : public LLMediaDataClient
 {
-public:
+protected:
     LOG_CLASS(LLObjectMediaNavigateClient);
+public:
 	// NOTE: from llmediaservice.h
 	static const int ERROR_PERMISSION_DENIED_CODE = 8002;
 	
@@ -397,11 +404,13 @@ class LLObjectMediaNavigateClient : public LLMediaDataClient
 
     class Responder : public LLMediaDataClient::Responder
     {
+        LOG_CLASS(Responder);
     public:
         Responder(const request_ptr_t &request)
             : LLMediaDataClient::Responder(request) {}
-		virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-        virtual void result(const LLSD &content);
+    protected:
+        virtual void httpFailure();
+        virtual void httpSuccess();
     private:
         void mediaNavigateBounceBack();
     };
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index b47fe9d4b123e2331cbf9a94c564d69c69a2c30d..95289f716774d19dcd859123f3600b61818c0069 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -28,7 +28,7 @@
 
 #include "apr_pools.h"
 #include "apr_dso.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 #include "llmeshrepository.h"
 
 #include "llagent.h"
@@ -202,6 +202,7 @@ U32	LLMeshRepoThread::sMaxConcurrentRequests = 1;
 
 class LLMeshHeaderResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLMeshHeaderResponder);
 public:
 	LLVolumeParams mMeshParams;
 	bool mProcessed;
@@ -230,14 +231,14 @@ class LLMeshHeaderResponder : public LLCurl::Responder
 		}
 	}
 
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer);
 
 };
 
 class LLMeshLODResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLMeshLODResponder);
 public:
 	LLVolumeParams mMeshParams;
 	S32 mLOD;
@@ -266,14 +267,14 @@ class LLMeshLODResponder : public LLCurl::Responder
 		}
 	}
 
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer);
 
 };
 
 class LLMeshSkinInfoResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLMeshSkinInfoResponder);
 public:
 	LLUUID mMeshID;
 	U32 mRequestedBytes;
@@ -291,14 +292,14 @@ class LLMeshSkinInfoResponder : public LLCurl::Responder
 		llassert(mProcessed);
 	}
 
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer);
 
 };
 
 class LLMeshDecompositionResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLMeshDecompositionResponder);
 public:
 	LLUUID mMeshID;
 	U32 mRequestedBytes;
@@ -316,14 +317,14 @@ class LLMeshDecompositionResponder : public LLCurl::Responder
 		llassert(mProcessed);
 	}
 
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer);
 
 };
 
 class LLMeshPhysicsShapeResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLMeshPhysicsShapeResponder);
 public:
 	LLUUID mMeshID;
 	U32 mRequestedBytes;
@@ -341,8 +342,7 @@ class LLMeshPhysicsShapeResponder : public LLCurl::Responder
 		llassert(mProcessed);
 	}
 
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer);
 
 };
@@ -398,6 +398,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s
 
 class LLWholeModelFeeResponder: public LLCurl::Responder
 {
+	LOG_CLASS(LLWholeModelFeeResponder);
 	LLMeshUploadThread* mThread;
 	LLSD mModelData;
 	LLHandle<LLWholeModelFeeObserver> mObserverHandle;
@@ -421,21 +422,20 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 		}
 	}
 
-	virtual void completed(U32 status,
-						   const std::string& reason,
-						   const LLSD& content)
+protected:
+	virtual void httpCompleted()
 	{
-		LLSD cc = content;
+		LLSD cc = getContent();
 		if (gSavedSettings.getS32("MeshUploadFakeErrors")&1)
 		{
 			cc = llsd_from_file("fake_upload_error.xml");
 		}
-			
+
 		dump_llsd_to_file(cc,make_dump_name("whole_model_fee_response_",dump_num));
 
 		LLWholeModelFeeObserver* observer = mObserverHandle.get();
 
-		if (isGoodStatus(status) &&
+		if (isGoodStatus() &&
 			cc["state"].asString() == "upload")
 		{
 			mThread->mWholeModelUploadURL = cc["uploader"].asString();
@@ -448,13 +448,14 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 		}
 		else
 		{
-			llwarns << "fee request failed" << llendl;
+			llwarns << "fee request failed " << dumpResponse() << llendl;
+			S32 status = getStatus();
 			log_upload_error(status,cc,"fee",mModelData["name"]);
 			mThread->mWholeModelUploadURL = "";
 
 			if (observer)
 			{
-				observer->setModelPhysicsFeeErrorStatus(status, reason);
+				observer->setModelPhysicsFeeErrorStatus(status, getReason());
 			}
 		}
 	}
@@ -463,6 +464,7 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 
 class LLWholeModelUploadResponder: public LLCurl::Responder
 {
+	LOG_CLASS(LLWholeModelUploadResponder);
 	LLMeshUploadThread* mThread;
 	LLSD mModelData;
 	LLHandle<LLWholeModelUploadObserver> mObserverHandle;
@@ -487,11 +489,10 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 		}
 	}
 
-	virtual void completed(U32 status,
-						   const std::string& reason,
-						   const LLSD& content)
+protected:
+	virtual void httpCompleted()
 	{
-		LLSD cc = content;
+		LLSD cc = getContent();
 		if (gSavedSettings.getS32("MeshUploadFakeErrors")&2)
 		{
 			cc = llsd_from_file("fake_upload_error.xml");
@@ -503,7 +504,7 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 
 		// requested "mesh" asset type isn't actually the type
 		// of the resultant object, fix it up here.
-		if (isGoodStatus(status) &&
+		if (isGoodStatus() &&
 			cc["state"].asString() == "complete")
 		{
 			mModelData["asset_type"] = "object";
@@ -516,9 +517,9 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 		}
 		else
 		{
-			llwarns << "upload failed" << llendl;
+			llwarns << "upload failed " << dumpResponse() << llendl;
 			std::string model_name = mModelData["name"].asString();
-			log_upload_error(status,cc,"upload",model_name);
+			log_upload_error(getStatus(),cc,"upload",model_name);
 
 			if (observer)
 			{
@@ -807,7 +808,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)
 
 			//reading from VFS failed for whatever reason, fetch from sim
 			std::vector<std::string> headers;
-			headers.push_back("Accept: application/octet-stream");
+			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);
 
 			std::string http_url = constructUrl(mesh_id);
 			if (!http_url.empty())
@@ -889,7 +890,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
 
 			//reading from VFS failed for whatever reason, fetch from sim
 			std::vector<std::string> headers;
-			headers.push_back("Accept: application/octet-stream");
+			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);
 
 			std::string http_url = constructUrl(mesh_id);
 			if (!http_url.empty())
@@ -970,7 +971,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 
 			//reading from VFS failed for whatever reason, fetch from sim
 			std::vector<std::string> headers;
-			headers.push_back("Accept: application/octet-stream");
+			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);
 
 			std::string http_url = constructUrl(mesh_id);
 			if (!http_url.empty())
@@ -1051,7 +1052,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c
 	//either cache entry doesn't exist or is corrupt, request header from simulator	
 	bool retval = true ;
 	std::vector<std::string> headers;
-	headers.push_back("Accept: application/octet-stream");
+	headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);
 
 	std::string http_url = constructUrl(mesh_params.getSculptID());
 	if (!http_url.empty())
@@ -1126,7 +1127,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,
 
 			//reading from VFS failed for whatever reason, fetch from sim
 			std::vector<std::string> headers;
-			headers.push_back("Accept: application/octet-stream");
+			headers.push_back(HTTP_OUT_HEADER_ACCEPT + ": " + HTTP_CONTENT_OCTET_STREAM);
 
 			std::string http_url = constructUrl(mesh_id);
 			if (!http_url.empty())
@@ -1898,10 +1899,10 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
 
 }
 
-void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
+void LLMeshLODResponder::completedRaw(const LLChannelDescriptors& channels,
+									  const LLIOPipe::buffer_ptr_t& buffer)
 {
+	S32 status = getStatus();
 	mProcessed = true;
 	
 	// thread could have already be destroyed during logout
@@ -1912,14 +1913,15 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
 	
 	S32 data_size = buffer->countAfter(channels.in(), NULL);
 
+	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?
 	if (status < 200 || status > 400)
 	{
-		llwarns << status << ": " << reason << llendl;
+		llwarns << dumpResponse() << llendl;
 	}
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -1927,8 +1929,8 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
-			llwarns << "Unhandled status " << status << llendl;
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
+			llwarns << "Unhandled status " << dumpResponse() << llendl;
 		}
 		return;
 	}
@@ -1962,10 +1964,10 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
 	delete [] data;
 }
 
-void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
+void LLMeshSkinInfoResponder::completedRaw(const LLChannelDescriptors& channels,
+										   const LLIOPipe::buffer_ptr_t& buffer)
 {
+	S32 status = getStatus();
 	mProcessed = true;
 
 	// thread could have already be destroyed during logout
@@ -1976,14 +1978,15 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason
 
 	S32 data_size = buffer->countAfter(channels.in(), NULL);
 
+	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?
 	if (status < 200 || status > 400)
 	{
-		llwarns << status << ": " << reason << llendl;
+		llwarns << dumpResponse() << llendl;
 	}
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -1991,8 +1994,8 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
-			llwarns << "Unhandled status " << status << llendl;
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
+			llwarns << "Unhandled status " << dumpResponse() << llendl;
 		}
 		return;
 	}
@@ -2026,10 +2029,10 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason
 	delete [] data;
 }
 
-void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
+void LLMeshDecompositionResponder::completedRaw(const LLChannelDescriptors& channels,
+												const LLIOPipe::buffer_ptr_t& buffer)
 {
+	S32 status = getStatus();
 	mProcessed = true;
 	
 	if( !gMeshRepo.mThread )
@@ -2039,14 +2042,15 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r
 
 	S32 data_size = buffer->countAfter(channels.in(), NULL);
 
+	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?
 	if (status < 200 || status > 400)
 	{
-		llwarns << status << ": " << reason << llendl;
+		llwarns << dumpResponse() << llendl;
 	}
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -2054,8 +2058,8 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
-			llwarns << "Unhandled status " << status << llendl;
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
+			llwarns << "Unhandled status " << dumpResponse() << llendl;
 		}
 		return;
 	}
@@ -2089,10 +2093,10 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r
 	delete [] data;
 }
 
-void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
+void LLMeshPhysicsShapeResponder::completedRaw(const LLChannelDescriptors& channels,
+											   const LLIOPipe::buffer_ptr_t& buffer)
 {
+	S32 status = getStatus();
 	mProcessed = true;
 
 	// thread could have already be destroyed during logout
@@ -2103,14 +2107,15 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re
 
 	S32 data_size = buffer->countAfter(channels.in(), NULL);
 
+	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?
 	if (status < 200 || status > 400)
 	{
-		llwarns << status << ": " << reason << llendl;
+		llwarns << dumpResponse() << llendl;
 	}
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -2118,8 +2123,8 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
-			llwarns << "Unhandled status " << status << llendl;
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
+			llwarns << "Unhandled status " << dumpResponse() << llendl;
 		}
 		return;
 	}
@@ -2153,10 +2158,10 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re
 	delete [] data;
 }
 
-void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
+void LLMeshHeaderResponder::completedRaw(const LLChannelDescriptors& channels,
+										 const LLIOPipe::buffer_ptr_t& buffer)
 {
+	S32 status = getStatus();
 	mProcessed = true;
 
 	// thread could have already be destroyed during logout
@@ -2165,6 +2170,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		return;
 	}
 
+	// *TODO: What about 3xx redirect codes? What about status 400 (Bad Request)?
 	if (status < 200 || status > 400)
 	{
 		//llwarns
@@ -2178,9 +2184,9 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		// and (somewhat more optional than the others) retries
 		// again after some set period of time
 
-		llassert(status == 503 || status == 499);
+		llassert(status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_INTERNAL_ERROR);
 
-		if (status == 503 || status == 499)
+		if (status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_INTERNAL_ERROR)
 		{ //retry
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -2192,7 +2198,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		}
 		else
 		{
-			llwarns << "Unhandled status." << llendl;
+			llwarns << "Unhandled status " << dumpResponse() << llendl;
 		}
 	}
 
@@ -2214,9 +2220,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 
 	if (!success)
 	{
-		llwarns
-			<< "Unable to parse mesh header: "
-			<< status << ": " << reason << llendl;
+		llwarns << "Unable to parse mesh header: " << dumpResponse() << llendl;
 	}
 	else if (data && data_size > 0)
 	{
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index 862e4be203a5dea41b621fc98acf92b814b7bd2d..4f5e07c566f2ad78acc9797e737922eeee72ef4f 100755
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -95,15 +95,11 @@ class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder
 {
 	LOG_CLASS(LLClassifiedClickMessageResponder);
 
-public:
+protected:
 	// If we get back an error (not found, etc...), handle it here
-	virtual void errorWithContent(
-		U32 status,
-		const std::string& reason,
-		const LLSD& content)
+	virtual void httpFailure()
 	{
-		llwarns << "Sending click message failed (" << status << "): [" << reason << "]" << llendl;
-		llwarns << "Content: [" << content << "]" << llendl;
+		llwarns << "Sending click message failed " << dumpResponse() << llendl;
 	}
 };
 
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index e71dba5caee73871c17c7e9d531ceeed95a2b2a2..580e31591c8d4e7eaa64e7b9d7107676251d96b0 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1079,10 +1079,15 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
 
         if (force_save_as)
         {
-                // the name of the wearable has changed, re-save wearable with new name
-                LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID());
+			// FIXME race condition if removeCOFItemLinks does not
+			// complete immediately.  Looks like we're counting on the
+			// fact that updateAppearanceFromCOF will get called after
+			// we exit customize mode.
+
+			// the name of the wearable has changed, re-save wearable with new name
+			LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID());
 			gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE);
-                mNameEditor->setText(mWearableItem->getName());
+			mNameEditor->setText(mWearableItem->getName());
         }
         else
         {
@@ -1091,6 +1096,14 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
 			// version so texture baking service knows appearance has changed.
 			if (link_item)
 			{
+				// FIXME - two link-modifying calls here plus one
+				// inventory change request, none of which use a
+				// callback. When does a new appearance request go out
+				// and how is it synced with these changes?  As above,
+				// we seem to be implicitly depending on
+				// updateAppearanceFromCOF() to be called when we
+				// exit customize mode.
+
 				// Create new link
 				link_inventory_item( gAgent.getID(),
 									 link_item->getLinkedUUID(),
@@ -1100,9 +1113,9 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
 									 LLAssetType::AT_LINK,
 									 NULL);
 				// Remove old link
-				gInventory.purgeObject(link_item->getUUID());
+				remove_inventory_item(link_item->getUUID(), NULL);
 			}
-                gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name);
+			gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name);
         }
 
 	
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index 88400e4ef2f0e8ba1b68ad735c0b961847e7b80f..d1a18fdc8c0b08e4405a44580b6ed320acdfa3ca 100755
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -527,7 +527,7 @@ void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)
 }
 
 // virtual
-void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason)
+void LLLandmarksPanel::setErrorStatus(S32 status, const std::string& reason)
 {
 	llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
 }
diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h
index 8fae0f0b67f7db6862ccdfda46b2f3274d951235..a39338304cf7e23d9297219baa4b2146be214175 100755
--- a/indra/newview/llpanellandmarks.h
+++ b/indra/newview/llpanellandmarks.h
@@ -106,7 +106,7 @@ class LLLandmarksPanel : public LLPanelPlacesTab, LLRemoteParcelInfoObserver
 	//LLRemoteParcelInfoObserver interface
 	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 	/*virtual*/ void setParcelID(const LLUUID& parcel_id);
-	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason);
+	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
 	
 private:
 	void initFavoritesInventoryPanel();
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index bcb90bcb56662d219b2453909d61a81588a6437f..c4ba0979144c44266ef28ca46fc2afa05fd06c4c 100755
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -437,7 +437,7 @@ void LLPanelLogin::showLoginWidgets()
 		sInstance->reshapeBrowser();
 		// *TODO: Append all the usual login parameters, like first_login=Y etc.
 		std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();
-		web_browser->navigateTo( splash_screen_url, "text/html" );
+		web_browser->navigateTo( splash_screen_url, HTTP_CONTENT_TEXT_HTML );
 		LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");
 		username_combo->setFocus(TRUE);
 	}
@@ -791,7 +791,7 @@ void LLPanelLogin::loadLoginPage()
 	if (web_browser->getCurrentNavUrl() != login_uri.asString())
 	{
 		LL_DEBUGS("AppInit") << "loading:    " << login_uri << LL_ENDL;
-		web_browser->navigateTo( login_uri.asString(), "text/html" );
+		web_browser->navigateTo( login_uri.asString(), HTTP_CONTENT_TEXT_HTML );
 	}
 }
 
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index c09d4393c81c79e3f9f2a5a8e9fd9fc2e0c7d92b..0e3057dcad8e16bba8d6ad0ed16ede85f8b86c6b 100755
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -1184,12 +1184,12 @@ BOOL LLPanelOutfitEdit::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 			 * second argument is used to delay the appearance update until all dragged items
 			 * are added to optimize user experience.
 			 */
-			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), false);
+			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID());
 		}
 		else
 		{
 			// if asset id is not available for the item we must wear it immediately (attachments only)
-			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), true);
+			LLAppearanceMgr::instance().addCOFItemLink(item->getLinkedUUID(), new LLUpdateAppearanceAndEditWearableOnDestroy(item->getUUID()));
 		}
 	}
 
diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp
index f90236f6f2890ac53dc1c9677f610063980cacbc..d6c927ab58491a69b38c425651976290aa630a70 100755
--- a/indra/newview/llpaneloutfitsinventory.cpp
+++ b/indra/newview/llpaneloutfitsinventory.cpp
@@ -76,7 +76,8 @@ BOOL LLPanelOutfitsInventory::postBuild()
 	// Fetch your outfits folder so that the links are in memory.
 	// ( This is only necessary if we want to show a warning if a user deletes an item that has a
 	// a link in an outfit, see "ConfirmItemDeleteHasLinks". )
-	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTFIT, false);
+
+	const LLUUID &outfits_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
 	if (outfits_cat.notNull())
 	{
 		LLInventoryModelBackgroundFetch::instance().start(outfits_cat);
diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h
index 3c1f14759c82b23974db4f85da22c5019748b15b..7a8bd66fcfe2420a503b3be2b8a107339ed9a62e 100755
--- a/indra/newview/llpanelpick.h
+++ b/indra/newview/llpanelpick.h
@@ -86,7 +86,7 @@ class LLPanelPickInfo : public LLPanel, public LLAvatarPropertiesObserver, LLRem
 	//This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing
 	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 	/*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; }
-	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason) {};
+	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {};
 
 protected:
 
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index 4ae0c0eb1252c7c595b47333f3f75c89d61bb335..4e7c5f6ed2912e64bce73898d280bd8475f76d67 100755
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -169,15 +169,15 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id,
 }
 
 // virtual
-void LLPanelPlaceInfo::setErrorStatus(U32 status, const std::string& reason)
+void LLPanelPlaceInfo::setErrorStatus(S32 status, const std::string& reason)
 {
 	// We only really handle 404 and 499 errors
 	std::string error_text;
-	if(status == 404)
+	if(status == HTTP_NOT_FOUND)
 	{
 		error_text = getString("server_error_text");
 	}
-	else if(status == 499)
+	else if(status == HTTP_INTERNAL_ERROR)
 	{
 		error_text = getString("server_forbidden_text");
 	}
diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h
index 64f0b6b5503898e84746a10d35b5cfc406af52a2..30327378eff8c09a9d382e83ff3f7ca0881878e3 100755
--- a/indra/newview/llpanelplaceinfo.h
+++ b/indra/newview/llpanelplaceinfo.h
@@ -86,7 +86,7 @@ class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver
 	void displayParcelInfo(const LLUUID& region_id,
 						   const LLVector3d& pos_global);
 
-	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason);
+	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
 
 	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index 6c2a01fc82fdad1bbd1f66abf38ea3e3d9c52f45..730df2ea238f642b2d1cae352e290c76abb58dc4 100755
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -217,7 +217,7 @@ class LLPlacesRemoteParcelInfoObserver : public LLRemoteParcelInfoObserver
 			LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
 		}
 	}
-	/*virtual*/ void setErrorStatus(U32 status, const std::string& reason)
+	/*virtual*/ void setErrorStatus(S32 status, const std::string& reason)
 	{
 		llerrs << "Can't complete remote parcel request. Http Status: "
 			   << status << ". Reason : " << reason << llendl;
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp
index c277359133285f460f0000c587b14118ff9dd854..a9c755de35e63032be0a2dabd9a065a14a01fdcf 100755
--- a/indra/newview/llpathfindingmanager.cpp
+++ b/indra/newview/llpathfindingmanager.cpp
@@ -103,17 +103,16 @@ LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode
 
 class NavMeshStatusResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(NavMeshStatusResponder);
 public:
-	NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly);
+	NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly);
 	virtual ~NavMeshStatusResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
-
 protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 private:
-	std::string    mCapabilityURL;
 	LLViewerRegion *mRegion;
 	LLUUID         mRegionUUID;
 	bool           mIsGetStatusOnly;
@@ -125,17 +124,16 @@ class NavMeshStatusResponder : public LLHTTPClient::Responder
 
 class NavMeshResponder : public LLHTTPClient::Responder
 {
+    LOG_CLASS(NavMeshResponder);
 public:
-	NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr);
+	NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr);
 	virtual ~NavMeshResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
-
 protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 private:
-	std::string             mCapabilityURL;
 	U32                     mNavMeshVersion;
 	LLPathfindingNavMeshPtr mNavMeshPtr;
 };
@@ -146,17 +144,14 @@ class NavMeshResponder : public LLHTTPClient::Responder
 
 class AgentStateResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(AgentStateResponder);
 public:
-	AgentStateResponder(const std::string &pCapabilityURL);
+	AgentStateResponder();
 	virtual ~AgentStateResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
-
 protected:
-
-private:
-	std::string mCapabilityURL;
+	virtual void httpSuccess();
+	virtual void httpFailure();
 };
 
 
@@ -165,17 +160,16 @@ class AgentStateResponder : public LLHTTPClient::Responder
 //---------------------------------------------------------------------------
 class NavMeshRebakeResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(NavMeshRebakeResponder);
 public:
-	NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback);
+	NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback);
 	virtual ~NavMeshRebakeResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent);
-
 protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 private:
-	std::string                                     mCapabilityURL;
 	LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback;
 };
 
@@ -190,11 +184,9 @@ class LinksetsResponder
 	virtual ~LinksetsResponder();
 
 	void handleObjectLinksetsResult(const LLSD &pContent);
-	void handleObjectLinksetsError(U32 pStatus, const std::string &pReason, 
-								   const LLSD& pContent, const std::string &pURL);
+	void handleObjectLinksetsError();
 	void handleTerrainLinksetsResult(const LLSD &pContent);
-	void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason,
-									const LLSD& pContent, const std::string &pURL);
+	void handleTerrainLinksetsError();
 
 protected:
 
@@ -227,17 +219,16 @@ typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;
 
 class ObjectLinksetsResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(ObjectLinksetsResponder);
 public:
-	ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr);
+	ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);
 	virtual ~ObjectLinksetsResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent);
-
 protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 private:
-	std::string          mCapabilityURL;
 	LinksetsResponderPtr mLinksetsResponsderPtr;
 };
 
@@ -247,17 +238,16 @@ class ObjectLinksetsResponder : public LLHTTPClient::Responder
 
 class TerrainLinksetsResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(TerrainLinksetsResponder);
 public:
-	TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr);
+	TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);
 	virtual ~TerrainLinksetsResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent);
-
 protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 private:
-	std::string          mCapabilityURL;
 	LinksetsResponderPtr mLinksetsResponsderPtr;
 };
 
@@ -267,17 +257,16 @@ class TerrainLinksetsResponder : public LLHTTPClient::Responder
 
 class CharactersResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(TerrainLinksetsResponder);
 public:
-	CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback);
+	CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback);
 	virtual ~CharactersResponder();
 
-	virtual void result(const LLSD &pContent);
-	virtual void errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent);
-
 protected:
+	virtual void httpSuccess();
+	virtual void httpFailure();
 
 private:
-	std::string                                     mCapabilityURL;
 	LLPathfindingManager::request_id_t              mRequestId;
 	LLPathfindingManager::object_request_callback_t mCharactersCallback;
 };
@@ -364,7 +353,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b
 		std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion);
 		llassert(!navMeshStatusURL.empty());
 		navMeshPtr->handleNavMeshCheckVersion();
-		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly);
+		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly);
 		LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder);
 	}
 }
@@ -398,12 +387,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re
 			bool doRequestTerrain = isAllowViewTerrainProperties();
 			LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain));
 
-			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr);
+			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);
 			LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder);
 
 			if (doRequestTerrain)
 			{
-				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr);
+				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);
 				LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder);
 			}
 		}
@@ -447,13 +436,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP
 
 			if (!objectPostData.isUndefined())
 			{
-				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr);
+				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);
 				LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder);
 			}
 
 			if (!terrainPostData.isUndefined())
 			{
-				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr);
+				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);
 				LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder);
 			}
 		}
@@ -486,7 +475,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_
 		{
 			pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr);
 
-			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback);
+			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback);
 			LLHTTPClient::get(charactersURL, charactersResponder);
 		}
 	}
@@ -519,7 +508,7 @@ void LLPathfindingManager::requestGetAgentState()
 		{
 			std::string agentStateURL = getAgentStateURLForRegion(currentRegion);
 			llassert(!agentStateURL.empty());
-			LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL);
+			LLHTTPClient::ResponderPtr responder = new AgentStateResponder();
 			LLHTTPClient::get(agentStateURL, responder);
 		}
 	}
@@ -543,7 +532,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak
 		llassert(!navMeshStatusURL.empty());
 		LLSD postData;			
 		postData["command"] = "rebuild";
-		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback);
+		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback);
 		LLHTTPClient::post(navMeshStatusURL, postData, responder);
 	}
 }
@@ -565,7 +554,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt
 		else
 		{
 			navMeshPtr->handleNavMeshStart(pNavMeshStatus);
-			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr);
+			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr);
 
 			LLSD postData;
 			LLHTTPClient::post(navMeshURL, postData, responder);
@@ -779,9 +768,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c
 // NavMeshStatusResponder
 //---------------------------------------------------------------------------
 
-NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly)
+NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly)
 	: LLHTTPClient::Responder(),
-	mCapabilityURL(pCapabilityURL),
 	mRegion(pRegion),
 	mRegionUUID(),
 	mIsGetStatusOnly(pIsGetStatusOnly)
@@ -796,15 +784,15 @@ NavMeshStatusResponder::~NavMeshStatusResponder()
 {
 }
 
-void NavMeshStatusResponder::result(const LLSD &pContent)
+void NavMeshStatusResponder::httpSuccess()
 {
-	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent);
+	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent());
 	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);
 }
 
-void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent)
+void NavMeshStatusResponder::httpFailure()
 {
-	llwarns << "NavMeshStatusResponder error [status:" << pStatus << "]: " << pContent << llendl;
+	llwarns << dumpResponse() << llendl;
 	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID);
 	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);
 }
@@ -813,9 +801,8 @@ void NavMeshStatusResponder::errorWithContent(U32 pStatus, const std::string& pR
 // NavMeshResponder
 //---------------------------------------------------------------------------
 
-NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr)
+NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr)
 	: LLHTTPClient::Responder(),
-	mCapabilityURL(pCapabilityURL),
 	mNavMeshVersion(pNavMeshVersion),
 	mNavMeshPtr(pNavMeshPtr)
 {
@@ -825,23 +812,23 @@ NavMeshResponder::~NavMeshResponder()
 {
 }
 
-void NavMeshResponder::result(const LLSD &pContent)
+void NavMeshResponder::httpSuccess()
 {
-	mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion);
+	mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion);
 }
 
-void NavMeshResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent)
+void NavMeshResponder::httpFailure()
 {
-	mNavMeshPtr->handleNavMeshError(pStatus, pReason, pContent, mCapabilityURL, mNavMeshVersion);
+	llwarns << dumpResponse() << llendl;
+	mNavMeshPtr->handleNavMeshError(mNavMeshVersion);
 }
 
 //---------------------------------------------------------------------------
 // AgentStateResponder
 //---------------------------------------------------------------------------
 
-AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL)
+AgentStateResponder::AgentStateResponder()
 : LLHTTPClient::Responder()
-, mCapabilityURL(pCapabilityURL)
 {
 }
 
@@ -849,17 +836,18 @@ AgentStateResponder::~AgentStateResponder()
 {
 }
 
-void AgentStateResponder::result(const LLSD &pContent)
+void AgentStateResponder::httpSuccess()
 {
+	const LLSD& pContent = getContent();
 	llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD));
 	llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean());
 	BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean();
 	LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion);
 }
 
-void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent)
+void AgentStateResponder::httpFailure()
 {
-	llwarns << "AgentStateResponder error [status:" << pStatus << "]: " << pContent << llendl;
+	llwarns << dumpResponse() << llendl;
 	LLPathfindingManager::getInstance()->handleAgentState(FALSE);
 }
 
@@ -867,9 +855,8 @@ void AgentStateResponder::errorWithContent(U32 pStatus, const std::string &pReas
 //---------------------------------------------------------------------------
 // navmesh rebake responder
 //---------------------------------------------------------------------------
-NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback)
+NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback)
 	: LLHTTPClient::Responder(),
-	mCapabilityURL(pCapabilityURL),
 	mRebakeNavMeshCallback(pRebakeNavMeshCallback)
 {
 }
@@ -878,14 +865,14 @@ NavMeshRebakeResponder::~NavMeshRebakeResponder()
 {
 }
 
-void NavMeshRebakeResponder::result(const LLSD &pContent)
+void NavMeshRebakeResponder::httpSuccess()
 {
 	mRebakeNavMeshCallback(true);
 }
 
-void NavMeshRebakeResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent)
+void NavMeshRebakeResponder::httpFailure()
 {
-	llwarns << "NavMeshRebakeResponder error [status:" << pStatus << "]: " << pContent << llendl;
+	llwarns << dumpResponse() << llendl;
 	mRebakeNavMeshCallback(false);
 }
 
@@ -918,11 +905,8 @@ void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent)
 	}
 }
 
-void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason,
-												 const LLSD& pContent, const std::string &pURL)
+void LinksetsResponder::handleObjectLinksetsError()
 {
-	llwarns << "LinksetsResponder object linksets error with request to URL '" << pURL << "' [status:"
-			<< pStatus << "]: " << pContent << llendl;
 	mObjectMessagingState = kReceivedError;
 	if (mTerrainMessagingState != kWaiting)
 	{
@@ -941,11 +925,8 @@ void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent)
 	}
 }
 
-void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason,
-												   const LLSD& pContent, const std::string &pURL)
+void LinksetsResponder::handleTerrainLinksetsError()
 {
-	llwarns << "LinksetsResponder terrain linksets error with request to URL '" << pURL << "' [status:"
-			<< pStatus << "]: " << pContent << llendl;
 	mTerrainMessagingState = kReceivedError;
 	if (mObjectMessagingState != kWaiting)
 	{
@@ -979,9 +960,8 @@ void LinksetsResponder::sendCallback()
 // ObjectLinksetsResponder
 //---------------------------------------------------------------------------
 
-ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr)
+ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)
 	: LLHTTPClient::Responder(),
-	mCapabilityURL(pCapabilityURL),
 	mLinksetsResponsderPtr(pLinksetsResponsderPtr)
 {
 }
@@ -990,23 +970,23 @@ ObjectLinksetsResponder::~ObjectLinksetsResponder()
 {
 }
 
-void ObjectLinksetsResponder::result(const LLSD &pContent)
+void ObjectLinksetsResponder::httpSuccess()
 {
-	mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent);
+	mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent());
 }
 
-void ObjectLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent)
+void ObjectLinksetsResponder::httpFailure()
 {
-	mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, pContent, mCapabilityURL);
+	llwarns << dumpResponse() << llendl;
+	mLinksetsResponsderPtr->handleObjectLinksetsError();
 }
 
 //---------------------------------------------------------------------------
 // TerrainLinksetsResponder
 //---------------------------------------------------------------------------
 
-TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr)
+TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)
 	: LLHTTPClient::Responder(),
-	mCapabilityURL(pCapabilityURL),
 	mLinksetsResponsderPtr(pLinksetsResponsderPtr)
 {
 }
@@ -1015,23 +995,23 @@ TerrainLinksetsResponder::~TerrainLinksetsResponder()
 {
 }
 
-void TerrainLinksetsResponder::result(const LLSD &pContent)
+void TerrainLinksetsResponder::httpSuccess()
 {
-	mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent);
+	mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent());
 }
 
-void TerrainLinksetsResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent)
+void TerrainLinksetsResponder::httpFailure()
 {
-	mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, pContent, mCapabilityURL);
+	llwarns << dumpResponse() << llendl;
+	mLinksetsResponsderPtr->handleTerrainLinksetsError();
 }
 
 //---------------------------------------------------------------------------
 // CharactersResponder
 //---------------------------------------------------------------------------
 
-CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback)
+CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback)
 	: LLHTTPClient::Responder(),
-	mCapabilityURL(pCapabilityURL),
 	mRequestId(pRequestId),
 	mCharactersCallback(pCharactersCallback)
 {
@@ -1041,15 +1021,15 @@ CharactersResponder::~CharactersResponder()
 {
 }
 
-void CharactersResponder::result(const LLSD &pContent)
+void CharactersResponder::httpSuccess()
 {
-	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(pContent));
+	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent()));
 	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr);
 }
 
-void CharactersResponder::errorWithContent(U32 pStatus, const std::string &pReason, const LLSD& pContent)
+void CharactersResponder::httpFailure()
 {
-	llwarns << "CharactersResponder error [status:" << pStatus << "]: " << pContent << llendl;
+	llwarns << dumpResponse() << llendl;
 
 	LLPathfindingObjectListPtr characterListPtr =  LLPathfindingObjectListPtr(new LLPathfindingCharacterList());
 	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr);
diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp
index 0c23e5ac923785ae99a64625f321ad6b4af2bf1e..555105cf409a5ff6b3d36579bd5bbcf7c872bea2 100755
--- a/indra/newview/llpathfindingnavmesh.cpp
+++ b/indra/newview/llpathfindingnavmesh.cpp
@@ -184,10 +184,8 @@ void LLPathfindingNavMesh::handleNavMeshError()
 	setRequestStatus(kNavMeshRequestError);
 }
 
-void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion)
+void LLPathfindingNavMesh::handleNavMeshError(U32 pNavMeshVersion)
 {
-	llwarns << "LLPathfindingNavMesh error with request to URL '" << pURL << "' [status:"
-			<< pStatus << "]: " << pContent << llendl;
 	if (mNavMeshStatus.getVersion() == pNavMeshVersion)
 	{
 		handleNavMeshError();
diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h
index b872ccad7cbd24235889a427beb36b512cd2c292..87f32b8d56487245b7ff0ba0d890845b483cfb4a 100755
--- a/indra/newview/llpathfindingnavmesh.h
+++ b/indra/newview/llpathfindingnavmesh.h
@@ -74,7 +74,7 @@ class LLPathfindingNavMesh
 	void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion);
 	void handleNavMeshNotEnabled();
 	void handleNavMeshError();
-	void handleNavMeshError(U32 pStatus, const std::string &pReason, const LLSD& pContent, const std::string &pURL, U32 pNavMeshVersion);
+	void handleNavMeshError(U32 pNavMeshVersion);
 
 protected:
 
diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp
index 04934b13f107569c6ce9f64e4cffef237998eb73..452efad291613b2903333b4efb8f819c452b2d5d 100755
--- a/indra/newview/llpreview.cpp
+++ b/indra/newview/llpreview.cpp
@@ -401,13 +401,6 @@ void LLPreview::onDiscardBtn(void* data)
 	self->mForceClose = TRUE;
 	self->closeFloater();
 
-	// Delete the item entirely
-	/*
-	item->removeFromServer();
-	gInventory.deleteObject(item->getUUID());
-	gInventory.notifyObservers();
-	*/
-
 	// Move the item to the trash
 	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
 	if (item->getParentUUID() != trash_id)
diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp
index 1390000fc506eb1bbba570224824e0283f52fe64..94a6389f8a7202e8d16539a9561507a2422f1e48 100755
--- a/indra/newview/llproductinforequest.cpp
+++ b/indra/newview/llproductinforequest.cpp
@@ -35,18 +35,24 @@
 
 class LLProductInfoRequestResponder : public LLHTTPClient::Responder
 {
-public:
+	LOG_CLASS(LLProductInfoRequestResponder);
+private:
 	//If we get back a normal response, handle it here
-	virtual void result(const LLSD& content)
+	/* virtual */ void httpSuccess()
 	{
-		LLProductInfoRequestManager::instance().setSkuDescriptions(content);
+		const LLSD& content = getContent();
+		if (!content.isArray())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
+		LLProductInfoRequestManager::instance().setSkuDescriptions(getContent());
 	}
 
 	//If we get back an error (not found, etc...), handle it here
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	/* virtual */ void httpFailure()
 	{
-		llwarns << "LLProductInfoRequest error [status:"
-				<< status << ":] " << content << llendl;
+		llwarns << dumpResponse() << llendl;
 	}
 };
 
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index 500dec7ee5841878bfbddb2857f9a590c6b847b9..7418bbf615035d1ad889b2eb2c08f7b611d57083 100755
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -47,9 +47,15 @@ LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemote
 
 //If we get back a normal response, handle it here
 //virtual
-void LLRemoteParcelRequestResponder::result(const LLSD& content)
+void LLRemoteParcelRequestResponder::httpSuccess()
 {
-	LLUUID parcel_id = content["parcel_id"];
+	const LLSD& content = getContent();
+	if (!content.isMap() || !content.has("parcel_id"))
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
+	LLUUID parcel_id = getContent()["parcel_id"];
 
 	// Panel inspecting the information may be closed and destroyed
 	// before this response is received.
@@ -62,17 +68,16 @@ void LLRemoteParcelRequestResponder::result(const LLSD& content)
 
 //If we get back an error (not found, etc...), handle it here
 //virtual
-void LLRemoteParcelRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLRemoteParcelRequestResponder::httpFailure()
 {
-	llwarns << "LLRemoteParcelRequest error [status:"
-			<< status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 
 	// Panel inspecting the information may be closed and destroyed
 	// before this response is received.
 	LLRemoteParcelInfoObserver* observer = mObserverHandle.get();
 	if (observer)
 	{
-		observer->setErrorStatus(status, reason);
+		observer->setErrorStatus(getStatus(), getReason());
 	}
 }
 
diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h
index b87056573b1bfea0ea4753f9a220b57b83b11763..0f8ae41d76756965347c1c46e59f4e1b0b00f84c 100755
--- a/indra/newview/llremoteparcelrequest.h
+++ b/indra/newview/llremoteparcelrequest.h
@@ -37,16 +37,17 @@ class LLRemoteParcelInfoObserver;
 
 class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLRemoteParcelRequestResponder);
 public:
 	LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle);
 
+private:
 	//If we get back a normal response, handle it here
-	/*virtual*/ void result(const LLSD& content);
+	/*virtual*/ void httpSuccess();
 
 	//If we get back an error (not found, etc...), handle it here
-	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+	/*virtual*/ void httpFailure();
 
-protected:
 	LLHandle<LLRemoteParcelInfoObserver> mObserverHandle;
 };
 
@@ -78,7 +79,7 @@ class LLRemoteParcelInfoObserver
 	virtual ~LLRemoteParcelInfoObserver() {}
 	virtual void processParcelInfo(const LLParcelData& parcel_data) = 0;
 	virtual void setParcelID(const LLUUID& parcel_id) = 0;
-	virtual void setErrorStatus(U32 status, const std::string& reason) = 0;
+	virtual void setErrorStatus(S32 status, const std::string& reason) = 0;
 	LLHandle<LLRemoteParcelInfoObserver>	getObserverHandle() const { return mObserverHandle; }
 
 protected:
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 74fa5a87bba7b96cf49046ce58da33e501b2bf49..e082859767de1ef9961dfd510234bc1df11c7e5c 100755
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -452,7 +452,7 @@ void LLSidepanelAppearance::editWearable(LLViewerWearable *wearable, LLView *dat
 	LLFloaterSidePanelContainer::showPanel("appearance", LLSD());
 	LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data);
 	if (panel)
-	{
+	{	
 		panel->showWearableEditPanel(wearable, disable_camera_switch);
 	}
 }
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index a4582071e8b3922b4d8fe60d74511496f7b62a37..bf209df863b9a777662d3310b270a96c092331f4 100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -268,21 +268,23 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)
 
 class ModerationResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(ModerationResponder);
 public:
 	ModerationResponder(const LLUUID& session_id)
 	{
 		mSessionID = session_id;
 	}
 	
-	virtual void error(U32 status, const std::string& reason)
+protected:
+	virtual void httpFailure()
 	{
-		llwarns << status << ": " << reason << llendl;
+		llwarns << dumpResponse() << llendl;;
 		
 		if ( gIMMgr )
 		{
 			//403 == you're not a mod
 			//should be disabled if you're not a moderator
-			if ( 403 == status )
+			if ( HTTP_FORBIDDEN == getStatus() )
 			{
 				gIMMgr->showSessionEventError(
 											  "mute",
@@ -853,10 +855,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
 		}
 	}
 }
-/*prep#
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
-		llwarns << "ModerationResponder error [status:" << status << "]: " << content << llendl;
-		*/
+
 void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)
 {
 	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 82596a86b9f3b5f486eb2543ea17828ab0ade2d1..8890df199b12d9178c7f8d4d71d165d74eccfbee 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1281,6 +1281,8 @@ bool idle_startup()
 		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
 		LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
 		
+		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from init_idle(). Seed cap == "
+		<< gFirstSimSeedCap << LL_ENDL;
 		regionp->setSeedCapability(gFirstSimSeedCap);
 		LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
 		display_startup();
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index be5fde9e2b020b31b88e4bbabb0955552270f1fb..70e2c0f2dc99d5910f1b6d88735d5a896080ffb0 100755
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -4,7 +4,7 @@
  *
  * $LicenseInfo:firstyear=2000&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,7 @@
 
 #include "lldir.h"
 #include "llhttpclient.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 #include "llimage.h"
 #include "llimagej2c.h"
 #include "llimageworker.h"
@@ -63,6 +63,8 @@
 #include "bufferarray.h"
 #include "bufferstream.h"
 
+#include "llhttpretrypolicy.h"
+
 bool LLTextureFetchDebugger::sDebuggerEnabled = false ;
 LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128);
 LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128);
@@ -244,6 +246,25 @@ static const S32 HTTP_REQUESTS_IN_QUEUE_LOW_WATER = 20;			// Active level at whi
 
 //////////////////////////////////////////////////////////////////////////////
 
+static const char* e_state_name[] =
+{
+	"INVALID",
+	"INIT",
+	"LOAD_FROM_TEXTURE_CACHE",
+	"CACHE_POST",
+	"LOAD_FROM_NETWORK",
+	"LOAD_FROM_SIMULATOR",
+	"WAIT_HTTP_RESOURCE",
+	"WAIT_HTTP_RESOURCE2",
+	"SEND_HTTP_REQ",
+	"WAIT_HTTP_REQ",
+	"DECODE_IMAGE",
+	"DECODE_IMAGE_UPDATE",
+	"WRITE_TO_CACHE",
+	"WAIT_ON_WRITE",
+	"DONE"
+};
+
 class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 
 {
@@ -382,12 +403,14 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
 	bool getCanUseHTTP() const { return mCanUseHTTP; }
 
+	void setUrl(const std::string& url) { mUrl = url; }
+
 	LLTextureFetch & getFetcher() { return *mFetcher; }
 
 	// Inherited from LLCore::HttpHandler
 	// Threads:  Ttf
 	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
-	
+
 protected:
 	LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type,
 						 const std::string& url, const LLUUID& id, const LLHost& host,
@@ -547,6 +570,8 @@ class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
 	S32 mActiveCount;
 	LLCore::HttpStatus mGetStatus;
 	std::string mGetReason;
+	LLAdaptiveRetryPolicy mFetchRetryPolicy;
+
 	
 	// Work Data
 	LLMutex mWorkMutex;
@@ -889,7 +914,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mHttpHasResource(false),
 	  mCacheReadCount(0U),
 	  mCacheWriteCount(0U),
-	  mResourceWaitCount(0U)
+	  mResourceWaitCount(0U),
+	  mFetchRetryPolicy(10.0,3600.0,2.0,10)
 {
 	mCanUseNET = mUrl.empty() ;
 	
@@ -1148,6 +1174,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE
 		LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
 							 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
+
 		// fall through
 	}
 
@@ -1270,6 +1297,21 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == LOAD_FROM_NETWORK)
 	{
+		// Check for retries to previous server failures.
+		F32 wait_seconds;
+		if (mFetchRetryPolicy.shouldRetry(wait_seconds))
+		{
+			if (wait_seconds <= 0.0)
+			{
+				llinfos << mID << " retrying now" << llendl;
+			}
+			else
+			{
+				//llinfos << mID << " waiting to retry for " << wait_seconds << " seconds" << llendl;
+				return false;
+			}
+		}
+
 		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
 
 // 		if (mHost != LLHost::invalid) get_url = false;
@@ -1286,7 +1328,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				std::string http_url = region->getHttpUrl() ;
 				if (!http_url.empty())
 				{
-					mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
+					setUrl(http_url + "/?texture_id=" + mID.asString().c_str());
 					mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
 				}
 				else
@@ -1340,7 +1382,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			//recordTextureStart(false);
 			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 
-			LL_DEBUGS("Texture") << mID << " does this happen?" << llendl;
 			return false;
 		}
 	}
@@ -1482,12 +1523,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 								 << LL_ENDL;
 
 			// Will call callbackHttpGet when curl request completes
+			// Only server bake images use the returned headers currently, for getting retry-after field.
+			LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions;
 			mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass,
 																	  mWorkPriority,
 																	  mUrl,
 																	  mRequestedOffset,
 																	  mRequestedSize,
-																	  mFetcher->mHttpOptions,
+																	  options,
 																	  mFetcher->mHttpHeaders,
 																	  this);
 		}
@@ -1519,15 +1562,22 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			{
 				if (http_not_found == mGetStatus)
 				{
-					if(mWriteToCacheState == NOT_WRITE) //map tiles
+					if (mFTType != FTT_MAP_TILE)
+					{
+						llwarns << "Texture missing from server (404): " << mUrl << llendl;
+					}
+
+					if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes
 					{
 						setState(DONE);
 						releaseHttpSemaphore();
-						LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl;
-						return true; // failed, means no map tile on the empty region.
+						if (mFTType != FTT_MAP_TILE)
+						{
+							LL_WARNS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl;
+						}
+						return true; 
 					}
 
-					llwarns << "Texture missing from server (404): " << mUrl << llendl;
 
 					// roll back to try UDP
 					if (mCanUseNET)
@@ -1543,6 +1593,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				else if (http_service_unavail == mGetStatus)
 				{
 					LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL;
+					llinfos << "503: HTTP GET failed for: " << mUrl
+							<< " Status: " << mGetStatus.toHex()
+							<< " Reason: '" << mGetReason << "'"
+							<< llendl;
 				}
 				else if (http_not_sat == mGetStatus)
 				{
@@ -1551,7 +1605,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				}
 				else
 				{
-					llinfos << "HTTP GET failed for: " << mUrl
+					llinfos << "other: HTTP GET failed for: " << mUrl
 							<< " Status: " << mGetStatus.toHex()
 							<< " Reason: '" << mGetReason << "'"
 							<< llendl;
@@ -1891,14 +1945,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe
 		mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
 	}
 
+	static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate");
+	F32 rand_val = ll_frand();
+	F32 rate = fake_failure_rate;
+	if (mFTType == FTT_SERVER_BAKE && (fake_failure_rate > 0.0) && (rand_val < fake_failure_rate))
+	{
+		llwarns << mID << " for debugging, setting fake failure status for texture " << mID
+				<< " (rand was " << rand_val << "/" << rate << ")" << llendl;
+		response->setStatus(LLCore::HttpStatus(503));
+	}
 	bool success = true;
 	bool partial = false;
 	LLCore::HttpStatus status(response->getStatus());
+	if (!status && (mFTType == FTT_SERVER_BAKE))
+	{
+		llinfos << mID << " state " << e_state_name[mState] << llendl;
+		mFetchRetryPolicy.onFailure(response);
+		F32 retry_after;
+		if (mFetchRetryPolicy.shouldRetry(retry_after))
+		{
+			llinfos << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << llendl;
+			mFetcher->removeFromHTTPQueue(mID, 0);
+			std::string reason(status.toString());
+			setGetStatus(status, reason);
+			releaseHttpSemaphore();
+			setState(LOAD_FROM_NETWORK);
+			return;
+		}
+		else
+		{
+			llinfos << mID << " will not retry" << llendl;
+		}
+	}
+	else
+	{
+		mFetchRetryPolicy.onSuccess();
+	}
 	
 	LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID
 						 << " status: " << status.toHex()
 						 << " '" << status.toString() << "'"
 						 << llendl;
+
 //	unsigned int offset(0), length(0), full_length(0);
 //	response->getRange(&offset, &length, &full_length);
 // 	llwarns << "HTTP COMPLETE: " << mID << " handle: " << handle
@@ -1907,13 +1995,16 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe
 // 			<< " offset: " << offset << " length: " << length
 // 			<< llendl;
 
+	std::string reason(status.toString());
+	setGetStatus(status, reason);
 	if (! status)
 	{
 		success = false;
-		std::string reason(status.toString());
-		setGetStatus(status, reason);
-		llwarns << "CURL GET FAILED, status: " << status.toHex()
-				<< " reason: " << reason << llendl;
+		if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them.
+		{
+			llwarns << mID << " CURL GET FAILED, status: " << status.toHex()
+					<< " reason: " << reason << llendl;
+		}
 	}
 	else
 	{
@@ -2376,6 +2467,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mQAMode(qa_mode),
 	  mHttpRequest(NULL),
 	  mHttpOptions(NULL),
+	  mHttpOptionsWithHeaders(NULL),
 	  mHttpHeaders(NULL),
 	  mHttpMetricsHeaders(NULL),
 	  mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
@@ -2406,10 +2498,13 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	
 	mHttpRequest = new LLCore::HttpRequest;
 	mHttpOptions = new LLCore::HttpOptions;
+	mHttpOptionsWithHeaders = new LLCore::HttpOptions;
+	mHttpOptionsWithHeaders->setWantHeaders(true);
 	mHttpHeaders = new LLCore::HttpHeaders;
-	mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c");
+	// *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ?
+	mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);
 	mHttpMetricsHeaders = new LLCore::HttpHeaders;
-	mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml");
+	mHttpMetricsHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
 	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault();
 }
 
@@ -2430,6 +2525,12 @@ LLTextureFetch::~LLTextureFetch()
 		mHttpOptions = NULL;
 	}
 
+	if (mHttpOptionsWithHeaders)
+	{
+		mHttpOptionsWithHeaders->release();
+		mHttpOptionsWithHeaders = NULL;
+	}
+
 	if (mHttpHeaders)
 	{
 		mHttpHeaders->release();
@@ -2464,7 +2565,11 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
 	{
 		return false;
 	}
-	
+
+	if (f_type == FTT_SERVER_BAKE)
+	{
+		LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << llendl;
+	}
 	LLTextureFetchWorker* worker = getWorker(id) ;
 	if (worker)
 	{
@@ -2522,7 +2627,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
 		worker->mNeedsAux = needs_aux;
 		worker->setImagePriority(priority);
 		worker->setDesiredDiscard(desired_discard, desired_size);
-		worker->setCanUseHTTP(can_use_http) ;
+		worker->setCanUseHTTP(can_use_http);
+		worker->setUrl(url);
 		if (!worker->haveWork())
 		{
 			worker->setState(LLTextureFetchWorker::INIT);
@@ -2549,7 +2655,7 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
 		worker->unlockWorkMutex();										// -Mw
 	}
 	
- 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " Discard: " << desired_discard << " size " << desired_size << llendl;
+ 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) << " Discard: " << desired_discard << " size " << desired_size << llendl;
 	return true;
 }
 
@@ -2728,7 +2834,8 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
 
 // Threads:  T*
 bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
-										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux)
+										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux,
+										LLCore::HttpStatus& last_http_get_status)
 {
 	bool res = false;
 	LLTextureFetchWorker* worker = getWorker(id);
@@ -2750,6 +2857,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
 		else if (worker->checkWork())
 		{
 			worker->lockWorkMutex();									// +Mw
+			last_http_get_status = worker->mGetStatus;
 			discard_level = worker->mDecodedDiscard;
 			raw = worker->mRawImage;
 			aux = worker->mAuxImage;
@@ -3220,25 +3328,14 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)
 
 void LLTextureFetchWorker::setState(e_state new_state)
 {
-	static const char* e_state_name[] =
-	{
-		"INVALID",
-		"INIT",
-		"LOAD_FROM_TEXTURE_CACHE",
-		"CACHE_POST",
-		"LOAD_FROM_NETWORK",
-		"LOAD_FROM_SIMULATOR",
-		"WAIT_HTTP_RESOURCE",
-		"WAIT_HTTP_RESOURCE2",
-		"SEND_HTTP_REQ",
-		"WAIT_HTTP_REQ",
-		"DECODE_IMAGE",
-		"DECODE_IMAGE_UPDATE",
-		"WRITE_TO_CACHE",
-		"WAIT_ON_WRITE",
-		"DONE"
-	};
-	LL_DEBUGS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl;
+	if (mFTType == FTT_SERVER_BAKE)
+	{
+	// NOTE: turning on these log statements is a reliable way to get
+	// blurry images fairly frequently. Presumably this is an
+	// indication of some subtle timing or locking issue.
+
+//		LL_INFOS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl;
+	}
 	mState = new_state;
 }
 
@@ -4041,7 +4138,8 @@ void LLTextureFetchDebugger::init()
 	if (! mHttpHeaders)
 	{
 		mHttpHeaders = new LLCore::HttpHeaders;
-		mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c");
+		// *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ?
+		mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);
 	}
 }
 
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 902a3d7a25431054b235e171fc1504fbebac0927..237912cde7cf4177b30dd23cce19de7023c99473 100755
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -4,7 +4,7 @@
  *
  * $LicenseInfo:firstyear=2000&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
@@ -95,7 +95,8 @@ class LLTextureFetch : public LLWorkerThread
 
 	// Threads:  T*
 	bool getRequestFinished(const LLUUID& id, S32& discard_level,
-							LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux);
+							LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux,
+							LLCore::HttpStatus& last_http_get_status);
 
 	// Threads:  T*
 	bool updateRequestPriority(const LLUUID& id, F32 priority);
@@ -351,6 +352,7 @@ class LLTextureFetch : public LLWorkerThread
 	// LLCurl interfaces used in the past.
 	LLCore::HttpRequest *				mHttpRequest;					// Ttf
 	LLCore::HttpOptions *				mHttpOptions;					// Ttf
+	LLCore::HttpOptions *				mHttpOptionsWithHeaders;		// Ttf
 	LLCore::HttpHeaders *				mHttpHeaders;					// Ttf
 	LLCore::HttpHeaders *				mHttpMetricsHeaders;			// Ttf
 	LLCore::HttpRequest::policy_t		mHttpPolicyClass;				// T*
@@ -395,6 +397,9 @@ class LLTextureFetch : public LLWorkerThread
 	e_tex_source mFetchSource;
 	e_tex_source mOriginFetchSource;
 
+	// Retry logic
+	//LLAdaptiveRetryPolicy mFetchRetryPolicy;
+	
 public:
 	//debug use
 	LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;}
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 148e5a015b199b4397c567cf7f36a6b4b2b3e4b5..fa94b523623ad486abd379b7bb1271899646a14f 100755
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -54,6 +54,7 @@
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
 #include "llviewerobject.h"
+#include "llviewerwearable.h"
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "pipeline.h"
@@ -147,13 +148,20 @@ BOOL LLVisualParamHint::needsRender()
 
 void LLVisualParamHint::preRender(BOOL clear_depth)
 {
+	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr;
+	if (wearable)
+	{
+		wearable->setVolitile(TRUE);
+	}
 	mLastParamWeight = mVisualParam->getWeight();
 	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);
 	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);
 	gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f);
 	gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f);
 	gAgentAvatarp->updateComposites();
-	gAgentAvatarp->updateVisualParams();
+	// Calling LLCharacter version, as we don't want position/height changes to cause the avatar to jump
+	// up and down when we're doing preview renders. -Nyx
+	gAgentAvatarp->LLCharacter::updateVisualParams();
 	gAgentAvatarp->updateGeometry(gAgentAvatarp->mDrawable);
 	gAgentAvatarp->updateLOD();
 
@@ -239,6 +247,12 @@ BOOL LLVisualParamHint::render()
 	}
 	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
 	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE);
+	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr;
+	if (wearable)
+	{
+		wearable->setVolitile(FALSE);
+	}
+
 	gAgentAvatarp->updateVisualParams();
 	gGL.color4f(1,1,1,1);
 	mGLTexturep->setGLTextureCreated(true);
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index f3d8de1904be0f2f1ccabdd0d806805806db13fa..ae934d9f5ae2a1764b4f79943936a40bb1c6fc25 100755
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -84,7 +84,7 @@ bool LLGoogleTranslationHandler::parseResponse(
 		return false;
 	}
 
-	if (status != STATUS_OK)
+	if (status != HTTP_OK)
 	{
 		// Request failed. Extract error message from the response.
 		parseErrorResponse(root, status, err_msg);
@@ -186,7 +186,7 @@ bool LLBingTranslationHandler::parseResponse(
 	std::string& detected_lang,
 	std::string& err_msg) const
 {
-	if (status != STATUS_OK)
+	if (status != HTTP_OK)
 	{
 		static const std::string MSG_BEGIN_MARKER = "Message: ";
 		size_t begin = body.find(MSG_BEGIN_MARKER);
@@ -251,8 +251,6 @@ LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_la
 
 // virtual
 void LLTranslate::TranslationReceiver::completedRaw(
-	U32 http_status,
-	const std::string& reason,
 	const LLChannelDescriptors& channels,
 	const LLIOPipe::buffer_ptr_t& buffer)
 {
@@ -262,8 +260,8 @@ void LLTranslate::TranslationReceiver::completedRaw(
 
 	const std::string body = strstrm.str();
 	std::string translation, detected_lang, err_msg;
-	int status = http_status;
-	LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL;
+	int status = getStatus();
+	LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL;
 	LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;
 	if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))
 	{
@@ -301,12 +299,10 @@ LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
 
 // virtual
 void LLTranslate::KeyVerificationReceiver::completedRaw(
-	U32 http_status,
-	const std::string& reason,
 	const LLChannelDescriptors& channels,
 	const LLIOPipe::buffer_ptr_t& buffer)
 {
-	bool ok = (http_status == 200);
+	bool ok = (getStatus() == HTTP_OK);
 	setVerificationStatus(ok);
 }
 
@@ -398,8 +394,8 @@ void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr
 			LLVersionInfo::getPatch(),
 			LLVersionInfo::getBuild());
 
-		sHeader.insert("Accept", "text/plain");
-		sHeader.insert("User-Agent", user_agent);
+		sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+		sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent);
 	}
 
 	LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT);
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index db5ad9479c13c5bb2f9b42a45ebb8e72b696babb..972274714a073607d8b498bbdaba01475ac51ac6 100755
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -95,9 +95,6 @@ class LLTranslationAPIHandler
 	virtual bool isConfigured() const = 0;
 
 	virtual ~LLTranslationAPIHandler() {}
-
-protected:
-	static const int STATUS_OK = 200;
 };
 
 /// Google Translate v2 API handler.
@@ -201,8 +198,6 @@ public :
 		 * @see mHandler
 		 */
 		/*virtual*/ void completedRaw(
-			U32 http_status,
-			const std::string& reason,
 			const LLChannelDescriptors& channels,
 			const LLIOPipe::buffer_ptr_t& buffer);
 
@@ -250,8 +245,6 @@ public :
 		 * @see setVerificationStatus()
 		 */
 		/*virtual*/ void completedRaw(
-			U32 http_status,
-			const std::string& reason,
 			const LLChannelDescriptors& channels,
 			const LLIOPipe::buffer_ptr_t& buffer);
 
diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp
index 1d777b3f7f380be2e6fc0e560a52d580dc900851..88c48ba0a3279a6a1eb6a976029abd1684e45dae 100755
--- a/indra/newview/lluploadfloaterobservers.cpp
+++ b/indra/newview/lluploadfloaterobservers.cpp
@@ -1,6 +1,6 @@
 /**
  * @file lluploadfloaterobservers.cpp
- * @brief LLUploadModelPremissionsResponder definition
+ * @brief LLUploadModelPermissionsResponder definition
  *
  * $LicenseInfo:firstyear=2011&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -28,26 +28,31 @@
 
 #include "lluploadfloaterobservers.h"
 
-LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)
+LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)
 :mObserverHandle(observer)
 {
 }
 
-void LLUploadModelPremissionsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLUploadModelPermissionsResponder::httpFailure()
 {
-	llwarns << "LLUploadModelPremissionsResponder error [status:"
-			<< status << "]: " << content << llendl;
+	llwarns << dumpResponse() << llendl;
 
 	LLUploadPermissionsObserver* observer = mObserverHandle.get();
 
 	if (observer)
 	{
-		observer->setPermissonsErrorStatus(status, reason);
+		observer->setPermissonsErrorStatus(getStatus(), getReason());
 	}
 }
 
-void LLUploadModelPremissionsResponder::result(const LLSD& content)
+void LLUploadModelPermissionsResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap())
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	LLUploadPermissionsObserver* observer = mObserverHandle.get();
 
 	if (observer)
@@ -55,3 +60,4 @@ void LLUploadModelPremissionsResponder::result(const LLSD& content)
 		observer->onPermissionsReceived(content);
 	}
 }
+
diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h
index b43ddb44d95456e57c9e952a51153c4409675d39..4ff4a827a5ee5f9a409e5f4052909a9d064add6d 100755
--- a/indra/newview/lluploadfloaterobservers.h
+++ b/indra/newview/lluploadfloaterobservers.h
@@ -1,6 +1,6 @@
 /**
  * @file lluploadfloaterobservers.h
- * @brief LLUploadModelPremissionsResponder declaration
+ * @brief LLUploadModelPermissionsResponder declaration
  *
  * $LicenseInfo:firstyear=2011&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -39,7 +39,7 @@ class LLUploadPermissionsObserver
 	virtual ~LLUploadPermissionsObserver() {}
 
 	virtual void onPermissionsReceived(const LLSD& result) = 0;
-	virtual void setPermissonsErrorStatus(U32 status, const std::string& reason) = 0;
+	virtual void setPermissonsErrorStatus(S32 status, const std::string& reason) = 0;
 
 	LLHandle<LLUploadPermissionsObserver> getPermObserverHandle() const {return mUploadPermObserverHandle;}
 
@@ -54,7 +54,7 @@ class LLWholeModelFeeObserver
 	virtual ~LLWholeModelFeeObserver() {}
 
 	virtual void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) = 0;
-	virtual void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) = 0;
+	virtual void setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) = 0;
 
 	LLHandle<LLWholeModelFeeObserver> getWholeModelFeeObserverHandle() const { return mWholeModelFeeObserverHandle; }
 
@@ -80,17 +80,16 @@ class LLWholeModelUploadObserver
 };
 
 
-class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder
+class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLUploadModelPermissionsResponder);
 public:
-
-	LLUploadModelPremissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);
-
-	void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-
-	void result(const LLSD& content);
+	LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);
 
 private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
+
 	LLHandle<LLUploadPermissionsObserver> mObserverHandle;
 };
 
diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp
index f81206ffecd27f57a1a3c8779c9b2d92f24ca94d..3f836efdd3ffcf0079f4c8c8c9993b77d9a60c62 100755
--- a/indra/newview/llviewerdisplayname.cpp
+++ b/indra/newview/llviewerdisplayname.cpp
@@ -58,12 +58,12 @@ namespace LLViewerDisplayName
 
 class LLSetDisplayNameResponder : public LLHTTPClient::Responder
 {
-public:
+	LOG_CLASS(LLSetDisplayNameResponder);
+private:
 	// only care about errors
-	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	/*virtual*/ void httpFailure()
 	{
-		llwarns << "LLSetDisplayNameResponder error [status:"
-				<< status << "]: " << content << llendl;
+		llwarns << dumpResponse() << llendl;
 		LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());
 		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
 	}
@@ -86,7 +86,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl
 	// People API can return localized error messages.  Indicate our
 	// language preference via header.
 	LLSD headers;
-	headers["Accept-Language"] = LLUI::getLanguage();
+	headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage();
 
 	// People API requires both the old and new value to change a variable.
 	// Our display name will be in cache before the viewer's UI is available
@@ -128,7 +128,7 @@ class LLSetDisplayNameReply : public LLHTTPNode
 		LLSD body = input["body"];
 
 		S32 status = body["status"].asInteger();
-		bool success = (status == 200);
+		bool success = (status == HTTP_OK);
 		std::string reason = body["reason"].asString();
 		LLSD content = body["content"];
 
@@ -137,7 +137,7 @@ class LLSetDisplayNameReply : public LLHTTPNode
 		// If viewer's concept of display name is out-of-date, the set request
 		// will fail with 409 Conflict.  If that happens, fetch up-to-date
 		// name information.
-		if (status == 409)
+		if (status == HTTP_CONFLICT)
 		{
 			LLUUID agent_id = gAgent.getID();
 			// Flush stale data
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index fff9821e86d0efa81fc939cd278529443f4be0b7..55575764b9045b2eaa201a48113960651f0ff5de 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -31,6 +31,7 @@
 #include "llsdserialize.h"
 #include "message.h"
 
+#include "llaisapi.h"
 #include "llagent.h"
 #include "llagentcamera.h"
 #include "llagentwearables.h"
@@ -65,6 +66,8 @@
 #include "llavataractions.h"
 #include "lllogininstance.h"
 #include "llfavoritesbar.h"
+#include "llclipboard.h"
+#include "llhttpretrypolicy.h"
 
 // Two do-nothing ops for use in callbacks.
 void no_op_inventory_func(const LLUUID&) {} 
@@ -256,7 +259,6 @@ class LLInventoryHandler : public LLCommandHandler
 };
 LLInventoryHandler gInventoryHandler;
 
-
 ///----------------------------------------------------------------------------
 /// Class LLViewerInventoryItem
 ///----------------------------------------------------------------------------
@@ -345,24 +347,6 @@ void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& ne
 	}
 }
 
-void LLViewerInventoryItem::removeFromServer()
-{
-	lldebugs << "Removing inventory item " << mUUID << " from server."
-			 << llendl;
-
-	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1);
-	gInventory.accountForUpdate(up);
-
-	LLMessageSystem* msg = gMessageSystem;
-	msg->newMessageFast(_PREHASH_RemoveInventoryItem);
-	msg->nextBlockFast(_PREHASH_AgentData);
-	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); 
-	msg->nextBlockFast(_PREHASH_InventoryData);
-	msg->addUUIDFast(_PREHASH_ItemID, mUUID);
-	gAgent.sendReliableMessage();
-}
-
 void LLViewerInventoryItem::updateServer(BOOL is_new) const
 {
 	if(!mIsComplete)
@@ -469,7 +453,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_
 {
 	mTransactionID = transaction_id;
 }
-// virtual
+
 void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
 {
 	msg->addUUIDFast(_PREHASH_ItemID, mUUID);
@@ -488,6 +472,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
 	U32 crc = getCRC32();
 	msg->addU32Fast(_PREHASH_CRC, crc);
 }
+
 // virtual
 BOOL LLViewerInventoryItem::importFile(LLFILE* fp)
 {
@@ -599,6 +584,15 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego
 }
 
 
+void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const
+{
+	msg->addUUIDFast(_PREHASH_FolderID, mUUID);
+	msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
+	S8 type = static_cast<S8>(mPreferredType);
+	msg->addS8Fast(_PREHASH_Type, type);
+	msg->addStringFast(_PREHASH_Name, mName);
+}
+
 void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const
 {
 	LLMessageSystem* msg = gMessageSystem;
@@ -637,30 +631,6 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const
 	gAgent.sendReliableMessage();
 }
 
-void LLViewerInventoryCategory::removeFromServer( void )
-{
-	llinfos << "Removing inventory category " << mUUID << " from server."
-			<< llendl;
-	// communicate that change with the server.
-	if(LLFolderType::lookupIsProtectedType(mPreferredType))
-	{
-		LLNotificationsUtil::add("CannotRemoveProtectedCategories");
-		return;
-	}
-
-	LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1);
-	gInventory.accountForUpdate(up);
-
-	LLMessageSystem* msg = gMessageSystem;
-	msg->newMessageFast(_PREHASH_RemoveInventoryFolder);
-	msg->nextBlockFast(_PREHASH_AgentData);
-	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-	msg->nextBlockFast(_PREHASH_FolderData);
-	msg->addUUIDFast(_PREHASH_FolderID, mUUID);
-	gAgent.sendReliableMessage();
-}
-
 S32 LLViewerInventoryCategory::getVersion() const
 {
 	return mVersion;
@@ -1179,6 +1149,316 @@ void move_inventory_item(
 	gAgent.sendReliableMessage();
 }
 
+// Note this only supports updating an existing item. Goes through AISv3
+// code path where available. Not all uses of item->updateServer() can
+// easily be switched to this paradigm.
+void update_inventory_item(
+	const LLUUID& item_id,
+	const LLSD& updates,
+	LLPointer<LLInventoryCallback> cb)
+{
+	LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
+	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+	if(obj)
+	{
+		LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
+		new_item->copyViewerItem(obj);	
+		new_item->fromLLSD(updates,false);
+		
+		std::string cap;
+		if (AISCommand::getCap(cap))
+		{
+			LLSD new_llsd;
+			new_item->asLLSD(new_llsd);
+			LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, new_llsd, cb);
+			cmd_ptr->run_command();
+		}
+		else // no cap
+		{
+			LLMessageSystem* msg = gMessageSystem;
+			msg->newMessageFast(_PREHASH_UpdateInventoryItem);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID());
+			msg->nextBlockFast(_PREHASH_InventoryData);
+			msg->addU32Fast(_PREHASH_CallbackID, 0);
+			new_item->packMessage(msg);
+			gAgent.sendReliableMessage();
+
+			LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0);
+			gInventory.accountForUpdate(up);
+			gInventory.updateItem(new_item);
+			if (cb)
+			{
+				cb->fire(item_id);
+			}
+		}
+	}
+}
+
+void update_inventory_category(
+	const LLUUID& cat_id,
+	const LLSD& updates,
+	LLPointer<LLInventoryCallback> cb)
+{
+	LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id);
+	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+	if(obj)
+	{
+		if (LLFolderType::lookupIsProtectedType(obj->getPreferredType()))
+		{
+			LLNotificationsUtil::add("CannotModifyProtectedCategories");
+			return;
+		}
+
+		LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj);
+		new_cat->fromLLSD(updates);
+		//std::string cap;
+		// FIXME - restore this once the back-end work has been done.
+		if (0) // if (AISCommand::getCap(cap))
+		{
+			LLSD new_llsd = new_cat->asLLSD();
+			LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb);
+			cmd_ptr->run_command();
+		}
+		else // no cap
+		{
+			LLMessageSystem* msg = gMessageSystem;
+			msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->nextBlockFast(_PREHASH_FolderData);
+			new_cat->packMessage(msg);
+			gAgent.sendReliableMessage();
+
+			LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0);
+			gInventory.accountForUpdate(up);
+			gInventory.updateCategory(new_cat);
+			if (cb)
+			{
+				cb->fire(cat_id);
+			}
+		}
+	}
+}
+
+void remove_inventory_item(
+	const LLUUID& item_id,
+	LLPointer<LLInventoryCallback> cb)
+{
+	LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
+	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+	if(obj)
+	{
+		std::string cap;
+		if (AISCommand::getCap(cap))
+		{
+			LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb);
+			cmd_ptr->run_command();
+		}
+		else // no cap
+		{
+			LLMessageSystem* msg = gMessageSystem;
+			msg->newMessageFast(_PREHASH_RemoveInventoryItem);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); 
+			msg->nextBlockFast(_PREHASH_InventoryData);
+			msg->addUUIDFast(_PREHASH_ItemID, item_id);
+			gAgent.sendReliableMessage();
+
+			// Update inventory and call callback immediately since
+			// message-based system has no callback mechanism (!)
+			gInventory.onObjectDeletedFromServer(item_id);
+			if (cb)
+			{
+				cb->fire(item_id);
+			}
+		}
+	}
+	else
+	{
+		llwarns << "remove_inventory_item called for invalid or nonexistent item " << item_id << llendl;
+	}
+}
+
+class LLRemoveCategoryOnDestroy: public LLInventoryCallback
+{
+public:
+	LLRemoveCategoryOnDestroy(const LLUUID& cat_id, LLPointer<LLInventoryCallback> cb):
+		mID(cat_id),
+		mCB(cb)
+	{
+	}
+	/* virtual */ void fire(const LLUUID& item_id) {}
+	~LLRemoveCategoryOnDestroy()
+	{
+		LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(mID);
+		if(children != LLInventoryModel::CHILDREN_NO)
+		{
+			llwarns << "remove descendents failed, cannot remove category " << llendl;
+		}
+		else
+		{
+			remove_inventory_category(mID, mCB);
+		}
+	}
+private:
+	LLUUID mID;
+	LLPointer<LLInventoryCallback> mCB;
+};
+
+void remove_inventory_category(
+	const LLUUID& cat_id,
+	LLPointer<LLInventoryCallback> cb)
+{
+	LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] " << llendl;
+	LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id);
+	if(obj)
+	{
+		if(LLFolderType::lookupIsProtectedType(obj->getPreferredType()))
+		{
+			LLNotificationsUtil::add("CannotRemoveProtectedCategories");
+			return;
+		}
+		std::string cap;
+		if (AISCommand::getCap(cap))
+		{
+			LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb);
+			cmd_ptr->run_command();
+		}
+		else // no cap
+		{
+			// RemoveInventoryFolder does not remove children, so must
+			// clear descendents first.
+			LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id);
+			if(children != LLInventoryModel::CHILDREN_NO)
+			{
+				LL_DEBUGS("Inventory") << "Will purge descendents first before deleting category " << cat_id << llendl;
+				LLPointer<LLInventoryCallback> wrap_cb = new LLRemoveCategoryOnDestroy(cat_id, cb); 
+				purge_descendents_of(cat_id, wrap_cb);
+				return;
+			}
+
+			LLMessageSystem* msg = gMessageSystem;
+			msg->newMessageFast(_PREHASH_RemoveInventoryFolder);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->nextBlockFast(_PREHASH_FolderData);
+			msg->addUUIDFast(_PREHASH_FolderID, cat_id);
+			gAgent.sendReliableMessage();
+
+			// Update inventory and call callback immediately since
+			// message-based system has no callback mechanism (!)
+			gInventory.onObjectDeletedFromServer(cat_id);
+			if (cb)
+			{
+				cb->fire(cat_id);
+			}
+		}
+	}
+	else
+	{
+		llwarns << "remove_inventory_category called for invalid or nonexistent item " << cat_id << llendl;
+	}
+}
+
+void remove_inventory_object(
+	const LLUUID& object_id,
+	LLPointer<LLInventoryCallback> cb)
+{
+	if (gInventory.getCategory(object_id))
+	{
+		remove_inventory_category(object_id, cb);
+	}
+	else
+	{
+		remove_inventory_item(object_id, cb);
+	}
+}
+
+// This is a method which collects the descendents of the id
+// provided. If the category is not found, no action is
+// taken. This method goes through the long winded process of
+// cancelling any calling cards, removing server representation of
+// folders, items, etc in a fairly efficient manner.
+void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
+{
+	LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(id);
+	if(children == LLInventoryModel::CHILDREN_NO)
+	{
+		LL_DEBUGS("Inventory") << "No descendents to purge for " << id << llendl;
+		return;
+	}
+	LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id);
+	if (cat.notNull())
+	{
+		if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode())
+		{
+			// Something on the clipboard is in "cut mode" and needs to be preserved
+			LL_DEBUGS("Inventory") << "purge_descendents_of clipboard case " << cat->getName()
+								   << " iterate and purge non hidden items" << llendl;
+			LLInventoryModel::cat_array_t* categories;
+			LLInventoryModel::item_array_t* items;
+			// Get the list of direct descendants in tha categoy passed as argument
+			gInventory.getDirectDescendentsOf(id, categories, items);
+			std::vector<LLUUID> list_uuids;
+			// Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently)
+			// Note: we need to do that shallow copy as purging things will invalidate the categories or items lists
+			for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it)
+			{
+				list_uuids.push_back((*it)->getUUID());
+			}
+			for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it)
+			{
+				list_uuids.push_back((*it)->getUUID());
+			}
+			// Iterate through the list and only purge the UUIDs that are not on the clipboard
+			for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it)
+			{
+				if (!LLClipboard::instance().isOnClipboard(*it))
+				{
+					remove_inventory_object(*it, NULL);
+				}
+			}
+		}
+		else
+		{
+			std::string cap;
+			if (AISCommand::getCap(cap))
+			{
+				LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb);
+				cmd_ptr->run_command();
+			}
+			else // no cap
+			{
+				// Fast purge
+				LL_DEBUGS("Inventory") << "purge_descendents_of fast case " << cat->getName() << llendl;
+
+				// send it upstream
+				LLMessageSystem* msg = gMessageSystem;
+				msg->newMessage("PurgeInventoryDescendents");
+				msg->nextBlock("AgentData");
+				msg->addUUID("AgentID", gAgent.getID());
+				msg->addUUID("SessionID", gAgent.getSessionID());
+				msg->nextBlock("InventoryData");
+				msg->addUUID("FolderID", id);
+				gAgent.sendReliableMessage();
+
+				// Update model immediately because there is no callback mechanism.
+				gInventory.onDescendentsPurgedFromServer(id);
+				if (cb)
+				{
+					cb->fire(id);
+				}
+			}
+		}
+	}
+}
+
 const LLUUID get_folder_by_itemtype(const LLInventoryItem *src)
 {
 	LLUUID retval = LLUUID::null;
@@ -1278,6 +1558,54 @@ void create_new_item(const std::string& name,
 	
 }	
 
+void slam_inventory_folder(const LLUUID& folder_id,
+						   const LLSD& contents,
+						   LLPointer<LLInventoryCallback> cb)
+{
+	std::string cap;
+	if (AISCommand::getCap(cap))
+	{
+		LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb);
+		cmd_ptr->run_command();
+	}
+	else // no cap
+	{
+		for (LLSD::array_const_iterator it = contents.beginArray();
+			 it != contents.endArray();
+			 ++it)
+		{
+			const LLSD& item_contents = *it;
+			link_inventory_item(gAgent.getID(),
+								item_contents["linked_id"].asUUID(),
+								folder_id,
+								item_contents["name"].asString(),
+								item_contents["desc"].asString(),
+								LLAssetType::EType(item_contents["type"].asInteger()),
+								cb);
+		}
+		remove_folder_contents(folder_id,false,cb);
+	}
+}
+
+void remove_folder_contents(const LLUUID& category, bool keep_outfit_links,
+							LLPointer<LLInventoryCallback> cb)
+{
+	LLInventoryModel::cat_array_t cats;
+	LLInventoryModel::item_array_t items;
+	gInventory.collectDescendents(category, cats, items,
+								  LLInventoryModel::EXCLUDE_TRASH);
+	for (S32 i = 0; i < items.count(); ++i)
+	{
+		LLViewerInventoryItem *item = items.get(i);
+		if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER))
+			continue;
+		if (item->getIsLinkType())
+		{
+			remove_inventory_item(item->getUUID(), cb);
+		}
+	}
+}
+
 const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)
 const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)
 const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not)
@@ -1713,3 +2041,5 @@ BOOL LLViewerInventoryItem::regenerateLink()
 	gInventory.notifyObservers();
 	return TRUE;
 }
+
+
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 61b1b8d84651ce46f6c54dbc722d0730c229e208..032efd954249509dcfefd927a3080f3d89f9e927 100755
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -118,12 +118,11 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr
 	void cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const;
 
 	// virtual methods
-	virtual void removeFromServer( void );
 	virtual void updateParentOnServer(BOOL restamp) const;
 	virtual void updateServer(BOOL is_new) const;
 	void fetchFromServer(void) const;
 
-	//virtual void packMessage(LLMessageSystem* msg) const;
+	virtual void packMessage(LLMessageSystem* msg) const;
 	virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
 	virtual BOOL unpackMessage(LLSD item);
 	virtual BOOL importFile(LLFILE* fp);
@@ -139,7 +138,6 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr
 	void setComplete(BOOL complete) { mIsComplete = complete; }
 	//void updateAssetOnServer() const;
 
-	virtual void packMessage(LLMessageSystem* msg) const;
 	virtual void setTransactionID(const LLTransactionID& transaction_id);
 	struct comparePointers
 	{
@@ -198,10 +196,11 @@ class LLViewerInventoryCategory  : public LLInventoryCategory
 	LLViewerInventoryCategory(const LLViewerInventoryCategory* other);
 	void copyViewerCategory(const LLViewerInventoryCategory* other);
 
-	virtual void removeFromServer();
 	virtual void updateParentOnServer(BOOL restamp_children) const;
 	virtual void updateServer(BOOL is_new) const;
 
+	virtual void packMessage(LLMessageSystem* msg) const;
+
 	const LLUUID& getOwnerID() const { return mOwnerID; }
 
 	// Version handling
@@ -274,7 +273,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback
 {
 public:
 
-	LLBoostFuncInventoryCallback(inventory_func_type fire_func,
+	LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func,
 								 nullary_func_type destroy_func = no_op):
 		mFireFunc(fire_func),
 		mDestroyFunc(destroy_func)
@@ -365,6 +364,32 @@ void move_inventory_item(
 	const std::string& new_name,
 	LLPointer<LLInventoryCallback> cb);
 
+void update_inventory_item(
+	const LLUUID& item_id,
+	const LLSD& updates,
+	LLPointer<LLInventoryCallback> cb);
+
+void update_inventory_category(
+	const LLUUID& cat_id,
+	const LLSD& updates,
+	LLPointer<LLInventoryCallback> cb);
+
+void remove_inventory_item(
+	const LLUUID& item_id,
+	LLPointer<LLInventoryCallback> cb);
+	
+void remove_inventory_category(
+	const LLUUID& cat_id,
+	LLPointer<LLInventoryCallback> cb);
+	
+void remove_inventory_object(
+	const LLUUID& object_id,
+	LLPointer<LLInventoryCallback> cb);
+
+void purge_descendents_of(
+	const LLUUID& cat_id,
+	LLPointer<LLInventoryCallback> cb);
+
 const LLUUID get_folder_by_itemtype(const LLInventoryItem *src);
 
 void copy_inventory_from_notecard(const LLUUID& destination_id,
@@ -379,4 +404,11 @@ void menu_create_inventory_item(LLInventoryPanel* root,
 								const LLSD& userdata,
 								const LLUUID& default_parent_uuid = LLUUID::null);
 
+void slam_inventory_folder(const LLUUID& folder_id,
+						   const LLSD& contents,
+						   LLPointer<LLInventoryCallback> cb);
+
+void remove_folder_contents(const LLUUID& folder_id, bool keep_outfit_links,
+							  LLPointer<LLInventoryCallback> cb);
+
 #endif // LL_LLVIEWERINVENTORY_H
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 2df028de69c098fcf3f58c64c4c0f316b62fa332..2cec808f19b7a2855c669fc81868c75a2a7361d6 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -158,7 +158,7 @@ LLViewerMediaObserver::~LLViewerMediaObserver()
 // on the Panel Land Media and to discover the MIME type
 class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
 {
-LOG_CLASS(LLMimeDiscoveryResponder);
+	LOG_CLASS(LLMimeDiscoveryResponder);
 public:
 	LLMimeDiscoveryResponder( viewer_media_t media_impl)
 		: mMediaImpl(media_impl),
@@ -177,13 +177,19 @@ LOG_CLASS(LLMimeDiscoveryResponder);
 		disconnectOwner();
 	}
 
-	virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+private:
+	/* virtual */ void httpCompleted()
 	{
-		std::string media_type = content["content-type"].asString();
+		if (!isGoodStatus())
+		{
+			llwarns << dumpResponse()
+					<< " [headers:" << getResponseHeaders() << "]" << llendl;
+		}
+		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE);
 		std::string::size_type idx1 = media_type.find_first_of(";");
 		std::string mime_type = media_type.substr(0, idx1);
 
-		lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl;
+		lldebugs << "status is " << getStatus() << ", media type \"" << media_type << "\"" << llendl;
 		
 		// 2xx status codes indicate success.
 		// Most 4xx status codes are successful enough for our purposes.
@@ -200,32 +206,27 @@ LOG_CLASS(LLMimeDiscoveryResponder);
 //			)
 		// We now no longer check the error code returned from the probe.
 		// If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting.
-		if(1)
+		//if(1)
 		{
 			// The probe was successful.
 			if(mime_type.empty())
 			{
 				// Some sites don't return any content-type header at all.
 				// Treat an empty mime type as text/html.
-				mime_type = "text/html";
+				mime_type = HTTP_CONTENT_TEXT_HTML;
 			}
-			
-			completeAny(status, mime_type);
 		}
-		else
-		{
-			llwarns << "responder failed with status " << status << ", reason " << reason << llendl;
-		
-			if(mMediaImpl)
-			{
-				mMediaImpl->mMediaSourceFailed = true;
-			}
-		}
-
-	}
+		//else
+		//{
+		//	llwarns << "responder failed with status " << dumpResponse() << llendl;
+		//
+		//	if(mMediaImpl)
+		//	{
+		//		mMediaImpl->mMediaSourceFailed = true;
+		//	}
+		//	return;
+		//}
 
-	void completeAny(U32 status, const std::string& mime_type)
-	{
 		// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
 		// Make a local copy so we can call loadURI() afterwards.
 		LLViewerMediaImpl *impl = mMediaImpl;
@@ -241,6 +242,7 @@ LOG_CLASS(LLMimeDiscoveryResponder);
 		}
 	}
 	
+public:
 	void cancelRequest()
 	{
 		disconnectOwner();
@@ -269,7 +271,7 @@ LOG_CLASS(LLMimeDiscoveryResponder);
 
 class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder
 {
-LOG_CLASS(LLViewerMediaOpenIDResponder);
+	LOG_CLASS(LLViewerMediaOpenIDResponder);
 public:
 	LLViewerMediaOpenIDResponder( )
 	{
@@ -279,23 +281,17 @@ LOG_CLASS(LLViewerMediaOpenIDResponder);
 	{
 	}
 
-	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
-	{
-		LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
-		LL_DEBUGS("MediaAuth") << content << LL_ENDL;
-		std::string cookie = content["set-cookie"].asString();
-		
-		LLViewerMedia::openIDCookieResponse(cookie);
-	}
-
 	/* virtual */ void completedRaw(
-		U32 status,
-		const std::string& reason,
 		const LLChannelDescriptors& channels,
 		const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		// This is just here to disable the default behavior (attempting to parse the response as llsd).
-		// We don't care about the content of the response, only the set-cookie header.
+		// We don't care about the content of the response, only the Set-Cookie header.
+		LL_DEBUGS("MediaAuth") << dumpResponse() 
+				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
+		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
+		
+		// *TODO: What about bad status codes?  Does this destroy previous cookies?
+		LLViewerMedia::openIDCookieResponse(cookie);
 	}
 
 };
@@ -313,17 +309,23 @@ LOG_CLASS(LLViewerMediaWebProfileResponder);
 	{
 	}
 
-	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+	 void completedRaw(
+		const LLChannelDescriptors& channels,
+		const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
+		// We don't care about the content of the response, only the set-cookie header.
+		LL_WARNS("MediaAuth") << dumpResponse() 
+				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
 
-		LLSD stripped_content = content;
-		stripped_content.erase("set-cookie");
+		LLSD stripped_content = getResponseHeaders();
+		// *TODO: Check that this works.
+		stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE);
 		LL_WARNS("MediaAuth") << stripped_content << LL_ENDL;
 
-		std::string cookie = content["set-cookie"].asString();
+		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
 		LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL;
 
+		// *TODO: What about bad status codes?  Does this destroy previous cookies?
 		LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
 
 		// Set cookie for snapshot publishing.
@@ -331,16 +333,6 @@ LOG_CLASS(LLViewerMediaWebProfileResponder);
 		LLWebProfile::setAuthCookie(auth_cookie);
 	}
 
-	 void completedRaw(
-		U32 status,
-		const std::string& reason,
-		const LLChannelDescriptors& channels,
-		const LLIOPipe::buffer_ptr_t& buffer)
-	{
-		// This is just here to disable the default behavior (attempting to parse the response as llsd).
-		// We don't care about the content of the response, only the set-cookie header.
-	}
-
 	std::string mHost;
 };
 
@@ -1387,10 +1379,12 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom
 LLSD LLViewerMedia::getHeaders()
 {
 	LLSD headers = LLSD::emptyMap();
-	headers["Accept"] = "*/*";
-	headers["Content-Type"] = "application/xml";
-	headers["Cookie"] = sOpenIDCookie;
-	headers["User-Agent"] = getCurrentUserAgent();
+	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
+	// *TODO: Should this be 'application/llsd+xml' ?
+	// *TODO: Should this even be set at all?   This header is only not overridden in 'GET' methods.
+	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML;
+	headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie;
+	headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();
 
 	return headers;
 }
@@ -1431,9 +1425,9 @@ void LLViewerMedia::setOpenIDCookie()
 
 		// Do a web profile get so we can store the cookie 
 		LLSD headers = LLSD::emptyMap();
-		headers["Accept"] = "*/*";
-		headers["Cookie"] = sOpenIDCookie;
-		headers["User-Agent"] = getCurrentUserAgent();
+		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
+		headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie;
+		headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();
 
 		std::string profile_url = getProfileURL("");
 		LLURL raw_profile_url( profile_url.c_str() );
@@ -1463,9 +1457,9 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string
 
 	LLSD headers = LLSD::emptyMap();
 	// Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header
-	headers["Accept"] = "*/*";
+	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
 	// and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream"
-	headers["Content-Type"] = "application/x-www-form-urlencoded";
+	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded";
 
 	// postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here.
 	size_t size = openid_token.size();
@@ -1537,7 +1531,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
 		// The null owner will keep the browser plugin from fully initializing 
 		// (specifically, it keeps LLPluginClassMedia from negotiating a size change, 
 		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
-		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
+		sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0);
 	}
 }
 
@@ -2633,16 +2627,16 @@ void LLViewerMediaImpl::navigateInternal()
 			//    Accept: application/llsd+xml
 			// which is really not what we want.
 			LLSD headers = LLSD::emptyMap();
-			headers["Accept"] = "*/*";
+			headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
 			// Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com
-			headers["Cookie"] = "";
+			headers[HTTP_OUT_HEADER_COOKIE] = "";
 			LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f);
 		}
 		else if("data" == scheme || "file" == scheme || "about" == scheme)
 		{
 			// FIXME: figure out how to really discover the type for these schemes
 			// We use "data" internally for a text/html url for loading the login screen
-			if(initializeMedia("text/html"))
+			if(initializeMedia(HTTP_CONTENT_TEXT_HTML))
 			{
 				loadURI();
 			}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ace16396dbe62f6a8e49ab53262645e4ae280b2e..751a9456c9c6105d3186e5a7afddb5914014249e 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3964,6 +3964,8 @@ void process_teleport_finish(LLMessageSystem* msg, void**)
 	gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );
 	gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]);
 
+	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == "
+			<< seedCap << LL_ENDL;
 	regionp->setSeedCapability(seedCap);
 
 	// Don't send camera updates to the new region until we're
@@ -4218,6 +4220,9 @@ void process_crossed_region(LLMessageSystem* msg, void**)
 	send_complete_agent_movement(sim_host);
 
 	LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
+
+	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == "
+			<< seedCap << LL_ENDL;
 	regionp->setSeedCapability(seedCap);
 }
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 064e96e3942905e6ca72a51440438565ad4c8587..63de1ab77a127bd2c35bcda44a975aa16d8ac5a4 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5038,6 +5038,28 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive)
 	}
 }
 
+BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const
+{
+	BOOL matches = FALSE;
+	if (mDrawable)
+	{
+		matches = mDrawable->isState(state);
+	}
+	if (recursive)
+	{
+		for (child_list_t::const_iterator iter = mChildList.begin();
+			 (iter != mChildList.end()) && matches; iter++)
+		{
+			LLViewerObject* child = *iter;
+			matches &= child->isDrawableState(state, recursive);
+		}
+	}
+
+	return matches;
+}
+
+
+
 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 // RN: these functions assume a 2-level hierarchy 
 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 316dbce7d07eca427072af14d06ef39f67c52e55..0390cbc5b00e42c29c4aaff3032c3341265d527a 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -394,6 +394,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 
 	void setDrawableState(U32 state, BOOL recursive = TRUE);
 	void clearDrawableState(U32 state, BOOL recursive = TRUE);
+	BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const;
 
 	// Called when the drawable shifts
 	virtual void onShift(const LLVector4a &shift_vector)	{ }
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index caacf26cb38ac23977b2bbee1b5f80c66230be42..ee970ceb5f478d4d4d909539a089d4778535a6bc 100755
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -671,6 +671,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 
 class LLObjectCostResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLObjectCostResponder);
 public:
 	LLObjectCostResponder(const LLSD& object_ids)
 		: mObjectIDs(object_ids)
@@ -691,20 +692,19 @@ class LLObjectCostResponder : public LLCurl::Responder
 		}
 	}
 
-	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+private:
+	/* virtual */ void httpFailure()
 	{
-		llwarns
-			<< "Transport error requesting object cost "
-			<< "[status: " << statusNum << "]: "
-			<< content << llendl;
+		llwarns << dumpResponse() << llendl;
 
 		// TODO*: Error message to user
 		// For now just clear the request from the pending list
 		clear_object_list_pending_requests();
 	}
 
-	void result(const LLSD& content)
+	/* virtual */ void httpSuccess()
 	{
+		const LLSD& content = getContent();
 		if ( !content.isMap() || content.has("error") )
 		{
 			// Improper response or the request had an error,
@@ -760,6 +760,7 @@ class LLObjectCostResponder : public LLCurl::Responder
 
 class LLPhysicsFlagsResponder : public LLCurl::Responder
 {
+	LOG_CLASS(LLPhysicsFlagsResponder);
 public:
 	LLPhysicsFlagsResponder(const LLSD& object_ids)
 		: mObjectIDs(object_ids)
@@ -780,20 +781,19 @@ class LLPhysicsFlagsResponder : public LLCurl::Responder
 		}
 	}
 
-	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+private:
+	/* virtual */ void httpFailure()
 	{
-		llwarns
-			<< "Transport error requesting object physics flags "
-			<< "[status: " << statusNum << "]: "
-			<< content << llendl;
+		llwarns << dumpResponse() << llendl;
 
 		// TODO*: Error message to user
 		// For now just clear the request from the pending list
 		clear_object_list_pending_requests();
 	}
 
-	void result(const LLSD& content)
+	/* virtual void */ void httpSuccess()
 	{
+		const LLSD& content = getContent();
 		if ( !content.isMap() || content.has("error") )
 		{
 			// Improper response or the request had an error,
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 386b2fd4001a4807f086322a7386c5e604430247..d7e14ac6f532fa60fb51af2a1ae52dddb59e830b 100755
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -99,7 +99,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel)
 			std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL());
 
 			// if we have a current (link sharing) url, use it instead
-			if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html")
+			if (mediaCurrentUrl != "" && parcel->getMediaType() == HTTP_CONTENT_TEXT_HTML)
 			{
 				mediaUrl = mediaCurrentUrl;
 			}
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 48c050f403445709122806200d4088bd73a40828..dca1a5b542f588bfbaffb99691bfe166d0dbc878 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -87,6 +87,8 @@ const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
 
 typedef std::map<std::string, std::string> CapabilityMap;
 
+static void log_capabilities(const CapabilityMap &capmap);
+
 class LLViewerRegionImpl {
 public:
 	LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host)
@@ -204,24 +206,30 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 {
 	LOG_CLASS(BaseCapabilitiesComplete);
 public:
-    BaseCapabilitiesComplete(U64 region_handle, S32 id)
+	BaseCapabilitiesComplete(U64 region_handle, S32 id)
 		: mRegionHandle(region_handle), mID(id)
-    { }
+	{ }
 	virtual ~BaseCapabilitiesComplete()
 	{ }
 
-    void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
-    {
-		LL_WARNS2("AppInit", "Capabilities") << "[status:" << statusNum << ":] " << content << LL_ENDL;
+	static BaseCapabilitiesComplete* build( U64 region_handle, S32 id )
+	{
+		return new BaseCapabilitiesComplete(region_handle, id);
+	}
+
+private:
+	/* virtual */void httpFailure()
+	{
+		LL_WARNS2("AppInit", "Capabilities") << dumpResponse() << LL_ENDL;
 		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
 		if (regionp)
 		{
 			regionp->failedSeedCapability();
 		}
-    }
+	}
 
-   void result(const LLSD& content)
-    {
+	/* virtual */ void httpSuccess()
+	{
 		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
 		if(!regionp) //region was removed
 		{
@@ -234,11 +242,17 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 			return ;
 		}
 
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		LLSD::map_const_iterator iter;
 		for(iter = content.beginMap(); iter != content.endMap(); ++iter)
 		{
 			regionp->setCapability(iter->first, iter->second);
-			
+
 			LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " 
 				<< iter->first << LL_ENDL;
 
@@ -257,11 +271,6 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 		}
 	}
 
-    static BaseCapabilitiesComplete* build( U64 region_handle, S32 id )
-    {
-		return new BaseCapabilitiesComplete(region_handle, id);
-    }
-
 private:
 	U64 mRegionHandle;
 	S32 mID;
@@ -278,19 +287,32 @@ class BaseCapabilitiesCompleteTracker :  public LLHTTPClient::Responder
 	virtual ~BaseCapabilitiesCompleteTracker()
 	{ }
 
-	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+	static BaseCapabilitiesCompleteTracker* build( U64 region_handle )
 	{
-		llwarns << "BaseCapabilitiesCompleteTracker error [status:"
-				<< statusNum << "]: " << content << llendl;
+		return new BaseCapabilitiesCompleteTracker( region_handle );
 	}
 
-	void result(const LLSD& content)
+private:
+	/* virtual */ void httpFailure()
+	{
+		llwarns << dumpResponse() << llendl;
+	}
+
+	/* virtual */ void httpSuccess()
 	{
 		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
 		if( !regionp ) 
 		{
+			LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;
 			return ;
-		}		
+		}
+
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		LLSD::map_const_iterator iter;
 		for(iter = content.beginMap(); iter != content.endMap(); ++iter)
 		{
@@ -300,27 +322,53 @@ class BaseCapabilitiesCompleteTracker :  public LLHTTPClient::Responder
 		
 		if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )
 		{
-			llinfos<<"BaseCapabilitiesCompleteTracker "<<"Sim sent duplicate seed caps that differs in size - most likely content."<<llendl;			
-			//todo#add cap debug versus original check?
-			/*CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin();
-			while (iter!=regionp->getRegionImpl()->mCapabilities.end() )
+			LL_WARNS2("AppInit", "Capabilities") 
+				<< "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. "
+				<< "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size()
+				<< " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size()
+				<< LL_ENDL;
+
+			//LL_WARNS2("AppInit", "Capabilities")
+			//	<< "Initial Base capabilities: " << LL_ENDL;
+
+			//log_capabilities(regionp->getRegionImpl()->mCapabilities);
+
+			//LL_WARNS2("AppInit", "Capabilities")
+			//				<< "Latest base capabilities: " << LL_ENDL;
+
+			//log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker);
+
+			// *TODO 
+			//add cap debug versus original check?
+			//CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin();
+			//while (iter!=regionp->getRegionImpl()->mCapabilities.end() )
+			//{
+			//	llinfos<<"BaseCapabilitiesCompleteTracker Original "<<iter->first<<" "<< iter->second<<llendl;
+			//	++iter;
+			//}
+
+			if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() )
 			{
-				llinfos<<"BaseCapabilitiesCompleteTracker Original "<<iter->first<<" "<< iter->second<<llendl;
-				++iter;
+				// *HACK Since we were granted more base capabilities in this grant request than the initial, replace
+				// the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a
+				// sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the
+				// inventory api capability grants.
+
+				// Need to clear a std::map before copying into it because old keys take precedence.
+				regionp->getRegionImplNC()->mCapabilities.clear();
+				regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker;
 			}
-			*/
-			regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();
 		}
-
+		else
+		{
+			LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL;
+		}
+		regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();
 	}
 
-	static BaseCapabilitiesCompleteTracker* build( U64 region_handle )
-	{
-		return new BaseCapabilitiesCompleteTracker( region_handle );
-	}
 
 private:
-	U64 mRegionHandle;	
+	U64 mRegionHandle;
 };
 
 
@@ -1597,6 +1645,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 		capabilityNames.append("FetchInventory2");
 		capabilityNames.append("FetchInventoryDescendents2");
 		capabilityNames.append("IncrementCOFVersion");
+		capabilityNames.append("InventoryAPIv3");
 	}
 
 	capabilityNames.append("GetDisplayNames");
@@ -1659,7 +1708,9 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 {
 	if (getCapability("Seed") == url)
     {	
-		//llwarns << "Ignoring duplicate seed capability" << llendl;
+		setCapabilityDebug("Seed", url);
+		LL_DEBUGS("CrossingCaps") <<  "Received duplicate seed capability, posting to seed " <<
+				url	<< llendl;
 		//Instead of just returning we build up a second set of seed caps and compare them 
 		//to the "original" seed cap received and determine why there is problem!
 		LLSD capabilityNames = LLSD::emptyArray();
@@ -1732,31 +1783,37 @@ class SimulatorFeaturesReceived : public LLHTTPClient::Responder
 {
 	LOG_CLASS(SimulatorFeaturesReceived);
 public:
-    SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, 
+	SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, 
 			S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS)
-	: mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts)
-    { }
-	
-	
-    void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
-    {
-		LL_WARNS2("AppInit", "SimulatorFeatures") << "[status:" << statusNum << "]: " << content << LL_ENDL;
+		: mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts)
+	{ }
+
+private:
+	/* virtual */ void httpFailure()
+	{
+		LL_WARNS2("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL;
 		retry();
-    }
+	}
 
-    void result(const LLSD& content)
-    {
+	/* virtual */ void httpSuccess()
+	{
 		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
 		if(!regionp) //region is removed or responder is not created.
 		{
-			LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL;
+			LL_WARNS2("AppInit", "SimulatorFeatures") 
+				<< "Received results for region that no longer exists!" << LL_ENDL;
 			return ;
 		}
-		
+
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		regionp->setSimulatorFeatures(content);
 	}
 
-private:
 	void retry()
 	{
 		if (mAttempt < mMaxAttempts)
@@ -1766,7 +1823,7 @@ class SimulatorFeaturesReceived : public LLHTTPClient::Responder
 			LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
 		}
 	}
-	
+
 	std::string mRetryURL;
 	U64 mRegionHandle;
 	S32 mAttempt;
@@ -1803,7 +1860,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
 
 void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url)
 {
-	mImpl->mSecondCapabilitiesTracker[name] = url;
+	// Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later.
+	if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) )
+	{
+		mImpl->mSecondCapabilitiesTracker[name] = url;
+		if(name == "GetTexture")
+		{
+			mHttpUrl = url ;
+		}
+	}
+
 }
 
 bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
@@ -1815,7 +1881,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
 {
 	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
 	{
-		llwarns << "getCapability called before caps received" << llendl;
+		llwarns << "getCapability called before caps received for " << name << llendl;
 	}
 	
 	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
@@ -1854,16 +1920,7 @@ boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(cons
 
 void LLViewerRegion::logActiveCapabilities() const
 {
-	int count = 0;
-	CapabilityMap::const_iterator iter;
-	for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count)
-	{
-		if (!iter->second.empty())
-		{
-			llinfos << iter->first << " URL is " << iter->second << llendl;
-		}
-	}
-	llinfos << "Dumped " << count << " entries." << llendl;
+	log_capabilities(mImpl->mCapabilities);
 }
 
 LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type)
@@ -1947,3 +2004,19 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const
 			 mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean());
 }
 
+/* Static Functions */
+
+void log_capabilities(const CapabilityMap &capmap)
+{
+	S32 count = 0;
+	CapabilityMap::const_iterator iter;
+	for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count)
+	{
+		if (!iter->second.empty())
+		{
+			llinfos << "log_capabilities: " << iter->first << " URL is " << iter->second << llendl;
+		}
+	}
+	llinfos << "log_capabilities: Dumped " << count << " entries." << llendl;
+}
+
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 35bba4184e63f342776ebe6f2d244d265626e44f..68633fba6ea96ccbc9e7c7bfab7fd7df5011a6cd 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -527,18 +527,19 @@ void update_statistics()
 
 class ViewerStatsResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(ViewerStatsResponder);
 public:
-    ViewerStatsResponder() { }
+	ViewerStatsResponder() { }
 
-    void error(U32 statusNum, const std::string& reason)
-    {
-		llinfos << "ViewerStatsResponder::error " << statusNum << " "
-				<< reason << llendl;
-    }
+private:
+	/* virtual */ void httpFailure()
+	{
+		llwarns << dumpResponse() << llendl;
+	}
 
-    void result(const LLSD& content)
-    {
-		llinfos << "ViewerStatsResponder::result" << llendl;
+	/* virtual */ void httpSuccess()
+	{
+		llinfos << "OK" << llendl;
 	}
 };
 
@@ -733,44 +734,28 @@ void send_stats()
 	LLHTTPClient::post(url, body, new ViewerStatsResponder());
 }
 
-LLFrameTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)
+LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)
 {
 	phase_map_t::iterator iter = mPhaseMap.find(phase_name);
 	if (iter == mPhaseMap.end())
 	{
-		LLFrameTimer timer;
+		LLTimer timer;
 		mPhaseMap[phase_name] = timer;
 	}
-	LLFrameTimer& timer = mPhaseMap[phase_name];
+	LLTimer& timer = mPhaseMap[phase_name];
 	return timer;
 }
 
 void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name)
 {
-	LLFrameTimer& timer = getPhaseTimer(phase_name);
-	lldebugs << "startPhase " << phase_name << llendl;
-	timer.unpause();
-}
-
-void LLViewerStats::PhaseMap::stopAllPhases()
-{
-	for (phase_map_t::iterator iter = mPhaseMap.begin();
-		 iter != mPhaseMap.end(); ++iter)
-	{
-		const std::string& phase_name = iter->first;
-		if (iter->second.getStarted())
-		{
-			// Going from started to paused state - record stats.
-			recordPhaseStat(phase_name,iter->second.getElapsedTimeF32());
-		}
-		lldebugs << "stopPhase (all) " << phase_name << llendl;
-		iter->second.pause();
-	}
+	LLTimer& timer = getPhaseTimer(phase_name);
+	timer.start();
+	LL_DEBUGS("Avatar") << "startPhase " << phase_name << llendl;
 }
 
 void LLViewerStats::PhaseMap::clearPhases()
 {
-	lldebugs << "clearPhases" << llendl;
+	LL_DEBUGS("Avatar") << "clearPhases" << llendl;
 
 	mPhaseMap.clear();
 }
@@ -795,7 +780,6 @@ LLViewerStats::PhaseMap::PhaseMap()
 {
 }
 
-
 void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)
 {
 	phase_map_t::iterator iter = mPhaseMap.find(phase_name);
@@ -808,6 +792,7 @@ void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)
 		}
 	}
 }
+
 // static
 LLViewerStats::StatsAccumulator& LLViewerStats::PhaseMap::getPhaseStats(const std::string& phase_name)
 {
@@ -831,14 +816,18 @@ void LLViewerStats::PhaseMap::recordPhaseStat(const std::string& phase_name, F32
 bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed)
 {
 	phase_map_t::iterator iter = mPhaseMap.find(phase_name);
+	bool found = false;
 	if (iter != mPhaseMap.end())
 	{
+		found = true;
 		elapsed =  iter->second.getElapsedTimeF32();
 		completed = !iter->second.getStarted();
-		return true;
+		LL_DEBUGS("Avatar") << " phase_name " << phase_name << " elapsed " << elapsed << " completed " << completed << " timer addr " << (S32)(&iter->second) << llendl;
 	}
 	else
 	{
-		return false;
+		LL_DEBUGS("Avatar") << " phase_name " << phase_name << " NOT FOUND"  << llendl;
 	}
+
+	return found;
 }
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 6b2461be41fb51fd9eca307590412fa09de80ad2..eaa0b6beff0da4eacb9a53bf2e033553e12d2bb7 100755
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -279,7 +279,7 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 
 	// Phase tracking (originally put in for avatar rezzing), tracking
 	// progress of active/completed phases for activities like outfit changing.
-	typedef std::map<std::string,LLFrameTimer>	phase_map_t;
+	typedef std::map<std::string,LLTimer>	phase_map_t;
 	typedef std::map<std::string,StatsAccumulator>	phase_stats_t;
 	class PhaseMap
 	{
@@ -288,11 +288,10 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 		static phase_stats_t sStats;
 	public:
 		PhaseMap();
-		LLFrameTimer& 	getPhaseTimer(const std::string& phase_name);
+		LLTimer& 		getPhaseTimer(const std::string& phase_name);
 		bool 			getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed);
 		void			startPhase(const std::string& phase_name);
 		void			stopPhase(const std::string& phase_name);
-		void			stopAllPhases();
 		void			clearPhases();
 		LLSD			dumpPhases();
 		static StatsAccumulator& getPhaseStats(const std::string& phase_name);
diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp
old mode 100755
new mode 100644
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index eb6c453e765d74bbcc984d12006fc5587be1aa10..4c9ca8b1d7b693b8f97a8148e2f236f7bba2dace 100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -901,6 +901,27 @@ void LLViewerTexture::updateBindStatsForTester()
 //end of LLViewerTexture
 //----------------------------------------------------------------------------------------------
 
+const std::string& fttype_to_string(const FTType& fttype)
+{
+	static const std::string ftt_unknown("FTT_UNKNOWN");
+	static const std::string ftt_default("FTT_DEFAULT");
+	static const std::string ftt_server_bake("FTT_SERVER_BAKE");
+	static const std::string ftt_host_bake("FTT_HOST_BAKE");
+	static const std::string ftt_map_tile("FTT_MAP_TILE");
+	static const std::string ftt_local_file("FTT_LOCAL_FILE");
+	static const std::string ftt_error("FTT_ERROR");
+	switch(fttype)
+	{
+		case FTT_UNKNOWN: return ftt_unknown; break;
+		case FTT_DEFAULT: return ftt_default; break;
+		case FTT_SERVER_BAKE: return ftt_server_bake; break;
+		case FTT_HOST_BAKE: return ftt_host_bake; break;
+		case FTT_MAP_TILE: return ftt_map_tile; break;
+		case FTT_LOCAL_FILE: return ftt_local_file; break;
+	}
+	return ftt_error;
+}
+
 //----------------------------------------------------------------------------------------------
 //start of LLViewerFetchedTexture
 //----------------------------------------------------------------------------------------------
@@ -1758,7 +1779,8 @@ bool LLViewerFetchedTexture::updateFetch()
 		
 		if (mRawImage.notNull()) sRawCount--;
 		if (mAuxRawImage.notNull()) sAuxCount--;
-		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
+		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage,
+																		   mLastHttpGetStatus);
 		if (mRawImage.notNull()) sRawCount++;
 		if (mAuxRawImage.notNull()) sAuxCount++;
 		if (finished)
@@ -1823,10 +1845,15 @@ bool LLViewerFetchedTexture::updateFetch()
 				// We finished but received no data
 				if (current_discard < 0)
 				{
-					llwarns << "!mIsFetching, setting as missing, decode_priority " << decode_priority
-							<< " mRawDiscardLevel " << mRawDiscardLevel
-							<< " current_discard " << current_discard
-							<< llendl;
+					if (getFTType() != FTT_MAP_TILE)
+					{
+						llwarns << mID
+								<< " Fetch failure, setting as missing, decode_priority " << decode_priority
+								<< " mRawDiscardLevel " << mRawDiscardLevel
+								<< " current_discard " << current_discard
+								<< " stats " << mLastHttpGetStatus.toHex()
+								<< llendl;
+					}
 					setIsMissingAsset();
 					desired_discard = -1;
 				}
@@ -2005,29 +2032,43 @@ void LLViewerFetchedTexture::forceToDeleteRequest()
 	mDesiredDiscardLevel = getMaxDiscardLevel() + 1;
 }
 
-void LLViewerFetchedTexture::setIsMissingAsset()
+void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing)
 {
-	if (mUrl.empty())
+	if (is_missing == mIsMissingAsset)
 	{
-		llwarns << mID << ": Marking image as missing" << llendl;
+		return;
 	}
-	else
+	if (is_missing)
 	{
-		// This may or may not be an error - it is normal to have no
-		// map tile on an empty region, but bad if we're failing on a
-		// server bake texture.
-		llwarns << mUrl << ": Marking image as missing" << llendl;
+		if (mUrl.empty())
+		{
+			llwarns << mID << ": Marking image as missing" << llendl;
+		}
+		else
+		{
+			// This may or may not be an error - it is normal to have no
+			// map tile on an empty region, but bad if we're failing on a
+			// server bake texture.
+			if (getFTType() != FTT_MAP_TILE)
+			{
+				llwarns << mUrl << ": Marking image as missing" << llendl;
+			}
+		}
+		if (mHasFetcher)
+		{
+			LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
+			mHasFetcher = FALSE;
+			mIsFetching = FALSE;
+			mLastPacketTimer.reset();
+			mFetchState = 0;
+			mFetchPriority = 0;
+		}
 	}
-	if (mHasFetcher)
+	else
 	{
-		LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
-		mHasFetcher = FALSE;
-		mIsFetching = FALSE;
-		mLastPacketTimer.reset();
-		mFetchState = 0;
-		mFetchPriority = 0;
+		llinfos << mID << ": un-flagging missing asset" << llendl;
 	}
-	mIsMissingAsset = TRUE;
+	mIsMissingAsset = is_missing;
 }
 
 void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback,
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index f2e1a90713afade6a10f4ed4432648eac3c8395e..e99d52741dd255735cd01d20714c43cf472185ad 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -34,6 +34,7 @@
 #include "llgltypes.h"
 #include "llrender.h"
 #include "llmetricperformancetester.h"
+#include "httpcommon.h"
 
 #include <map>
 #include <list>
@@ -120,7 +121,7 @@ class LLViewerTexture : public LLGLTexture
 	LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ;
 
 	virtual S8 getType() const;
-	virtual BOOL isMissingAsset()const ;
+	virtual BOOL isMissingAsset() const ;
 	virtual void dump();	// debug info to llinfos
 	
 	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
@@ -242,6 +243,8 @@ enum FTType
 	FTT_LOCAL_FILE // fetch directly from a local file.
 };
 
+const std::string& fttype_to_string(const FTType& fttype);
+
 //
 //textures are managed in gTextureList.
 //raw image data is fetched from remote or local cache
@@ -338,8 +341,8 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	// more data.
 	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
 
-	void setIsMissingAsset();
-	/*virtual*/ BOOL isMissingAsset()	const		{ return mIsMissingAsset; }
+	void setIsMissingAsset(BOOL is_missing = true);
+	/*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; }
 
 	// returns dimensions of original image for local files (before power of two scaling)
 	// and returns 0 for all asset system images
@@ -446,10 +449,11 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	S8  mIsRawImageValid;
 	S8  mHasFetcher;				// We've made a fecth request
 	S8  mIsFetching;				// Fetch request is active
-	bool mCanUseHTTP ;              //This texture can be fetched through http if true.
+	bool mCanUseHTTP;              //This texture can be fetched through http if true.
+	LLCore::HttpStatus mLastHttpGetStatus; // Result of the most recently completed http request for this texture.
 
 	FTType mFTType; // What category of image is this - map tile, server bake, etc?
-	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
+	mutable BOOL mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
 
 	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
 	S8              mLoadedCallbackDesiredDiscardLevel;
diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h
index 65566f23a5a9981d6b3a5dc7ecac34a5d8d12a6e..047b2ce143d232ff1dd4ebebda51379329e65082 100644
--- a/indra/newview/llviewerwearable.h
+++ b/indra/newview/llviewerwearable.h
@@ -68,6 +68,8 @@ class LLViewerWearable : public LLWearable
 	
 	void				setParamsToDefaults();
 	void				setTexturesToDefaults();
+	void				setVolitile(BOOL volitle) { mVolitle = volitle; } // TRUE when doing preview renders, some updates will be suppressed.
+	BOOL				getVolitile() { return mVolitle; }
 
 	/*virtual*/ LLUUID	getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const;
 
@@ -96,6 +98,8 @@ class LLViewerWearable : public LLWearable
 	LLAssetID			mAssetID;
 	LLTransactionID		mTransactionID;
 
+	BOOL 				mVolitle; // True when rendering preview images. Can suppress some updates.
+
 	LLUUID				mItemID;  // ID of the inventory item in the agent's inventory	
 };
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index fe4d5b3e4de55c5ee5f697d63b7e521365807ea3..f95cc9e572ff43ae0c816053547799ff27dd4260 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1965,7 +1965,7 @@ void LLViewerWindow::initWorldUI()
 		destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
 		std::string url = gSavedSettings.getString("DestinationGuideURL");
 		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		destinations->navigateTo(url, "text/html");
+		destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
 	}
 	LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents");
 	if (avatar_picker)
@@ -1973,7 +1973,7 @@ void LLViewerWindow::initWorldUI()
 		avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
 		std::string url = gSavedSettings.getString("AvatarPickerURL");
 		url = LLWeb::expandURLSubstitutions(url, LLSD());
-		avatar_picker->navigateTo(url, "text/html");
+		avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
 	}
 }
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 06fb23b84b3a5fdc16d7220e3924108273a282d7..46b909c4a14068801c5090ace60ffc16543828e5 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1881,13 +1881,17 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
 		const std::string url = getImageURL(te,uuid);
 		if (!url.empty())
 		{
-			LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl;
+			LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << llendl;
 			result = LLViewerTextureManager::getFetchedTextureFromUrl(
 				url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
+			if (result->isMissingAsset())
+			{
+				result->setIsMissingAsset(false);
+			}
 		}
 		else
 		{
-			LL_DEBUGS("Avatar") << avString() << "from host " << uuid << llendl;
+			LL_DEBUGS("Avatar") << avString() << "get old-bake image from host " << uuid << llendl;
 			LLHost host = getObjectHost();
 			result = LLViewerTextureManager::getFetchedTexture(
 				uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
@@ -2144,7 +2148,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 		{
 			LLVector3 tagPos = mRoot->getWorldPosition();
 			tagPos[VZ] -= mPelvisToFoot;
-			tagPos[VZ] += ( mBodySize[VZ] + 0.125f );
+			tagPos[VZ] += ( mBodySize[VZ] + 0.125f ); // does not need mAvatarOffset -Nyx
 			mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );
 		}
 	}//if ( voiceEnabled )
@@ -2885,6 +2889,8 @@ void LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
 	local_camera_up.normalize();
 	local_camera_up = local_camera_up * inv_root_rot;
 
+
+	// position is based on head position, does not require mAvatarOffset here. - Nyx
 	LLVector3 avatar_ellipsoid(mBodySize.mV[VX] * 0.4f,
 								mBodySize.mV[VY] * 0.4f,
 								mBodySize.mV[VZ] * NAMETAG_VERT_OFFSET_WEIGHT);
@@ -4408,7 +4414,7 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture
 }
 
 const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames.	
-const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames
+const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = S32_MAX ; //frames
 void LLVOAvatar::checkTextureLoading()
 {
 	static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds
@@ -4471,11 +4477,11 @@ const F32  ADDITIONAL_PRI = 0.5f;
 void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level)
 {
 	//Note:
-	//if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, 
+	//if this function is not called for the last MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL frames, 
 	//the texture pipeline will stop fetching this texture.
 
 	imagep->resetTextureStats();
-	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
+	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);
 	imagep->resetMaxVirtualSizeResetCounter() ;
 
 	mMaxPixelArea = llmax(pixel_area, mMaxPixelArea);
@@ -5208,6 +5214,72 @@ void LLVOAvatar::updateVisualParams()
 	updateHeadOffset();
 }
 
+/*virtual*/ 
+void LLVOAvatar::computeBodySize()
+{
+	LLAvatarAppearance::computeBodySize();
+
+	// Certain configurations of avatars can force the overall height (with offset) to go negative.
+	// Enforce a constraint to make sure we don't go below 1.1 meters (server-enforced limit)
+	// Camera positioning and other things start to break down when your avatar is "walking" while being fully underground
+	const LLViewerObject * last_object = NULL;
+	if (isSelf() && getWearableData() && isFullyLoaded() && !LLApp::isQuitting())
+	{
+		// Do not force a hover parameter change while we have pending attachments, which may be mesh-based with 
+		// joint offsets.
+		if (LLAppearanceMgr::instance().getNumAttachmentsInCOF() == getNumAttachments())
+		{
+			LLViewerWearable* shape = (LLViewerWearable*)getWearableData()->getWearable(LLWearableType::WT_SHAPE, 0);
+			BOOL loaded = TRUE;
+			for (attachment_map_t::const_iterator points_iter = mAttachmentPoints.begin();
+				 points_iter != mAttachmentPoints.end() && loaded;
+				 ++points_iter)
+			{
+				const LLViewerJointAttachment *attachment_pt = (*points_iter).second;
+				if (attachment_pt) 
+				{
+					for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attach_iter = attachment_pt->mAttachedObjects.begin(); attach_iter != attachment_pt->mAttachedObjects.end(); attach_iter++) 
+					{
+						const LLViewerObject* object = (LLViewerObject*)*attach_iter;
+						if (object) 
+						{
+							last_object = object;
+							llwarns << "attachment at point: " << (*points_iter).first << " object exists: " << object->getAttachmentItemID() << llendl;
+							loaded &=!object->isDrawableState(LLDrawable::REBUILD_ALL);
+							if (!loaded && shape && !shape->getVolitile()) 
+							{
+								llwarns << "caught unloaded attachment! skipping enforcement" << llendl;
+							}
+						}
+					}
+				}
+			}
+
+			if (last_object) 
+			{
+				LL_DEBUGS("Avatar") << "scanned at least one object!"  << LL_ENDL;
+			}
+			if (loaded && shape && !shape->getVolitile()) 
+			{
+				F32 hover_value = shape->getVisualParamWeight(AVATAR_HOVER);
+				if (hover_value < 0.0f && (mBodySize.mV[VZ] + hover_value < 1.1f))
+				{
+					hover_value = -(mBodySize.mV[VZ] - 1.1f); // avoid floating point rounding making the above check continue to fail.
+					llassert(mBodySize.mV[VZ] + hover_value >= 1.1f);
+
+					hover_value =  llmin(hover_value, 0.0f); // don't force the hover value to be greater than 0.
+
+					LL_DEBUGS("Avatar") << "changed hover value to: " << hover_value << " from: " << mAvatarOffset.mV[VZ] << LL_ENDL;
+
+					mAvatarOffset.mV[VZ] = hover_value;
+					shape->setVisualParamWeight(AVATAR_HOVER,hover_value, FALSE);
+				}
+			}
+		}
+	}
+}
+
+
 //-----------------------------------------------------------------------------
 // isActive()
 //-----------------------------------------------------------------------------
@@ -5977,9 +6049,12 @@ void LLVOAvatar::clearPhases()
 
 void LLVOAvatar::startPhase(const std::string& phase_name)
 {
-	F32 elapsed;
-	bool completed;
-	if (getPhases().getPhaseValues(phase_name, elapsed, completed))
+	F32 elapsed = 0.0;
+	bool completed = false;
+	bool found = getPhases().getPhaseValues(phase_name, elapsed, completed);
+	//LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name
+	//					<< " found " << found << " elapsed " << elapsed << " completed " << completed << llendl;
+	if (found)
 	{
 		if (!completed)
 		{
@@ -5987,15 +6062,18 @@ void LLVOAvatar::startPhase(const std::string& phase_name)
 			return;
 		}
 	}
-	LL_DEBUGS("Avatar") << "started phase " << phase_name << llendl;
+	LL_DEBUGS("Avatar") << avString() << " started phase " << phase_name << llendl;
 	getPhases().startPhase(phase_name);
 }
 
 void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
 {
-	F32 elapsed;
-	bool completed;
-	if (getPhases().getPhaseValues(phase_name, elapsed, completed))
+	F32 elapsed = 0.0;
+	bool completed = false;
+	bool found = getPhases().getPhaseValues(phase_name, elapsed, completed);
+	//LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name
+	//					<< " found " << found << " elapsed " << elapsed << " completed " << completed << llendl;
+	if (found)
 	{
 		if (!completed)
 		{
@@ -7015,9 +7093,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 			&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT
 			&& baked_index != BAKED_SKIRT)
 		{
+			LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << llendl;
 			setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, 
 				LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
 		}
+		else
+		{
+			LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using texture id "
+								<< getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << llendl;
+		}
 	}
 
 	// runway - was
@@ -7301,7 +7385,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
 		LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 );
 		if (id == image_baked->getID())
 		{
-			LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL;
+			//LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL;
 			mBakedTextureDatas[i].mIsLoaded = true;
 			mBakedTextureDatas[i].mLastTextureID = id;
 			mBakedTextureDatas[i].mIsUsed = true;
@@ -7374,6 +7458,15 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,
 	return outfilename;
 }
 
+void dump_sequential_xml(const std::string outprefix, const LLSD& content)
+{
+	std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml");
+	std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
+	std::ofstream ofs(fullpath.c_str(), std::ios_base::out);
+	ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY);
+	LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL;
+}
+
 void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables )
 {
 	std::string outprefix(prefix);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 85f6f25009644fd924decf48af9f1fcdc279dcfe..fad2fd962c66d35c2261fc1e2909ed29afe07ea4 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -212,6 +212,9 @@ class LLVOAvatar :
 	/*virtual*/ LLVector3		getPosAgentFromGlobal(const LLVector3d &position);
 	virtual void			updateVisualParams();
 
+	/*virtual*/ void		computeBodySize();
+
+
 
 /**                    Inherited
  **                                                                            **
@@ -991,10 +994,11 @@ class LLVOAvatar :
 
 }; // LLVOAvatar
 extern const F32 SELF_ADDITIONAL_PRI;
-extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL;
+extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL;
 
 std::string get_sequential_numbered_file_name(const std::string& prefix,
 											  const std::string& suffix);
+void dump_sequential_xml(const std::string outprefix, const LLSD& content);
 void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);
 
 #endif // LL_VOAVATAR_H
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d54eb5f0400c6f812f23cb1f484e1051de25cdc4..232bf3e478322023a5df3184a61807ffea1be57f 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -234,6 +234,33 @@ void LLVOAvatarSelf::initInstance()
 	//doPeriodically(output_self_av_texture_diagnostics, 30.0);
 	doPeriodically(update_avatar_rez_metrics, 5.0);
 	doPeriodically(check_for_unsupported_baked_appearance, 120.0);
+	doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0);
+}
+
+bool LLVOAvatarSelf::checkStuckAppearance()
+{
+	const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0;
+	const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0;
+	
+	if (gAgentWearables.isCOFChangeInProgress())
+	{
+		LL_DEBUGS("Avatar") << "checking for stuck appearance" << llendl;
+		F32 change_time = gAgentWearables.getCOFChangeTime();
+		LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << llendl;
+		S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns();
+		LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << llendl;
+		S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations();
+		LL_DEBUGS("Avatar") << "active copy operations " << active_copies << llendl;
+
+		if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) ||
+			(change_time > UNCONDITIONAL_UNSTICK_INTERVAL))
+		{
+			gAgentWearables.notifyLoadingFinished();
+		}
+	}
+
+	// Return false to continue running check periodically.
+	return LLApp::isExiting();
 }
 
 // virtual
@@ -2241,6 +2268,7 @@ LLSD LLVOAvatarSelf::metricsData()
 
 class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder
 {
+	LOG_CLASS(ViewerAppearanceChangeMetricsResponder);
 public:
 	ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,
 											volatile const S32 & live_sequence,
@@ -2251,32 +2279,25 @@ class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder
 	{
 	}
 
-	virtual void completed(U32 status,
-						   const std::string& reason,
-						   const LLSD& content)
+private:
+	/* virtual */ void httpSuccess()
 	{
-		gPendingMetricsUploads--; // if we add retry, this should be moved to the isGoodStatus case.
-		if (isGoodStatus(status))
-		{
-			LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
-			result(content);
-		}
-		else
-		{
-			LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL;
-			errorWithContent(status,reason,content);
-		}
-	}
+		LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
 
-	// virtual
-	void result(const LLSD & content)
-	{
+		gPendingMetricsUploads--;
 		if (mLiveSequence == mExpectedSequence)
 		{
 			mReportingStarted = true;
 		}
 	}
 
+	/* virtual */ void httpFailure()
+	{
+		// if we add retry, this should be removed from the httpFailure case
+		LL_WARNS("Avatar") << dumpResponse() << LL_ENDL;
+		gPendingMetricsUploads--;
+	}
+
 private:
 	S32 mExpectedSequence;
 	volatile const S32 & mLiveSequence;
@@ -2359,7 +2380,6 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,
 
 void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
 {
-	// gAgentAvatarp->stopAllPhases();
 	static volatile bool reporting_started(false);
 	static volatile S32 report_sequence(0);
 
@@ -2425,6 +2445,7 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
 
 class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder
 {
+	LOG_CLASS(CheckAgentAppearanceServiceResponder);
 public:
 	CheckAgentAppearanceServiceResponder()
 	{
@@ -2434,22 +2455,24 @@ class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder
 	{
 	}
 
-	/* virtual */ void result(const LLSD& content)
+private:
+	/* virtual */ void httpSuccess()
 	{
-		LL_DEBUGS("Avatar") << "status OK" << llendl;
+		LL_DEBUGS("Avatar") << "OK" << llendl;
 	}
 
 	// Error
-	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+	/*virtual*/ void httpFailure()
 	{
 		if (isAgentAvatarValid())
 		{
-			LL_DEBUGS("Avatar") << "failed, will rebake [status:"
-					<< status << "]: " << content << llendl;
+			LL_DEBUGS("Avatar") << "failed, will rebake "
+					<< dumpResponse() << LL_ENDL;
 			forceAppearanceUpdate();
 		}
-	}	
+	}
 
+public:
 	static void forceAppearanceUpdate()
 	{
 		// Trying to rebake immediately after crossing region boundary
@@ -2590,7 +2613,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
 				imagep->setBoostLevel(getAvatarBoostLevel());
 				imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
 				imagep->resetTextureStats();
-				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
+				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);
 				imagep->addTextureStats( desired_pixels / texel_area_ratio );
 				imagep->forceUpdateBindStats() ;
 				if (imagep->getDiscardLevel() < 0)
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 3b7b6bac64a07ed801ef9aa9b4f5905cc687ff02..e8b9a253276fe5f41c84a70c9d9e48bae4981516 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -138,6 +138,7 @@ class LLVOAvatarSelf :
 public:
 	/*virtual*/ BOOL 	updateCharacter(LLAgent &agent);
 	/*virtual*/ void 	idleUpdateTractorBeam();
+	bool				checkStuckAppearance();
 
 	//--------------------------------------------------------------------
 	// Loading state
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index ac2a34ba1e90fdc399a0fd9278a394db58ca2c58..397c5cd81f3deaee3924bc5302f1b2022794ca3c 100755
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -53,26 +53,27 @@ const U32 DEFAULT_RETRIES_COUNT = 3;
 
 class LLVoiceCallCapResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLVoiceCallCapResponder);
 public:
 	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
 
+protected:
 	// called with bad status codes
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-	virtual void result(const LLSD& content);
+	virtual void httpFailure();
+	virtual void httpSuccess();
 
 private:
 	LLUUID mSessionID;
 };
 
 
-void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLVoiceCallCapResponder::httpFailure()
 {
-	LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:"
-		<< status << "]: " << content << LL_ENDL;
+	LL_WARNS("Voice") << dumpResponse() << LL_ENDL;
 	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
 	if ( channelp )
 	{
-		if ( 403 == status )
+		if ( HTTP_FORBIDDEN == getStatus() )
 		{
 			//403 == no ability
 			LLNotificationsUtil::add(
@@ -89,12 +90,18 @@ void LLVoiceCallCapResponder::errorWithContent(U32 status, const std::string& re
 	}
 }
 
-void LLVoiceCallCapResponder::result(const LLSD& content)
+void LLVoiceCallCapResponder::httpSuccess()
 {
 	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
 	if (channelp)
 	{
 		//*TODO: DEBUG SPAM
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		LLSD::map_const_iterator iter;
 		for(iter = content.beginMap(); iter != content.endMap(); ++iter)
 		{
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 9b5d981aa5ccfc7cf5a62cfd119474a2bfdb5a96..838845df80aca9c072d231704a9b41bf5592a831 100755
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -124,17 +124,19 @@ static int scale_speaker_volume(float volume)
 class LLVivoxVoiceAccountProvisionResponder :
 	public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLVivoxVoiceAccountProvisionResponder);
 public:
 	LLVivoxVoiceAccountProvisionResponder(int retries)
 	{
 		mRetries = retries;
 	}
 
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+private:
+	/* virtual */ void httpFailure()
 	{
 		LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, "
 			<<  ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" )
-			<< status << "]: " << content << LL_ENDL;
+			<< " " << dumpResponse() << LL_ENDL;
 
 		if ( mRetries > 0 )
 		{
@@ -146,14 +148,19 @@ class LLVivoxVoiceAccountProvisionResponder :
 		}
 	}
 
-	virtual void result(const LLSD& content)
+	/* virtual */ void httpSuccess()
 	{
-
 		std::string voice_sip_uri_hostname;
 		std::string voice_account_server_uri;
 		
-		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
+		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL;
 		
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		if(content.has("voice_sip_uri_hostname"))
 			voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString();
 		
@@ -166,7 +173,6 @@ class LLVivoxVoiceAccountProvisionResponder :
 			content["password"].asString(),
 			voice_sip_uri_hostname,
 			voice_account_server_uri);
-
 	}
 
 private:
@@ -197,33 +203,34 @@ static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL;
 
 class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder
 {
+	LOG_CLASS(LLVivoxVoiceClientCapResponder);
 public:
 	LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {};
 
+private:
 	// called with bad status codes
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
-	virtual void result(const LLSD& content);
+	/* virtual */ void httpFailure();
+	/* virtual */ void httpSuccess();
 
-private:
 	LLVivoxVoiceClient::state mRequestingState;  // state 
 };
 
-void LLVivoxVoiceClientCapResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLVivoxVoiceClientCapResponder::httpFailure()
 {
-	LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder error [status:"
-		<< status << "]: " << content << LL_ENDL;
+	LL_WARNS("Voice") << dumpResponse() << LL_ENDL;
 	LLVivoxVoiceClient::getInstance()->sessionTerminate();
 }
 
-void LLVivoxVoiceClientCapResponder::result(const LLSD& content)
+void LLVivoxVoiceClientCapResponder::httpSuccess()
 {
 	LLSD::map_const_iterator iter;
 	
-	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
+	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL;
 
 	std::string uri;
 	std::string credentials;
 	
+	const LLSD& content = getContent();
 	if ( content.has("voice_credentials") )
 	{
 		LLSD voice_credentials = content["voice_credentials"];
@@ -2979,7 +2986,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString
 	
 	// Status code of 20200 means "bad password".  We may want to special-case that at some point.
 	
-	if ( statusCode == 401 )
+	if ( statusCode == HTTP_UNAUTHORIZED )
 	{
 		// Login failure which is probably caused by the delay after a user's password being updated.
 		LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL;
@@ -3481,7 +3488,7 @@ void LLVivoxVoiceClient::mediaStreamUpdatedEvent(
 		switch(statusCode)
 		{
 			case 0:
-			case 200:
+			case HTTP_OK:
 				// generic success
 				// Don't change the saved error code (it may have been set elsewhere)
 			break;
@@ -3831,7 +3838,7 @@ void LLVivoxVoiceClient::messageEvent(
 	LL_DEBUGS("Voice") << "Message event, session " << sessionHandle << " from " << uriString << LL_ENDL;
 //	LL_DEBUGS("Voice") << "    header " << messageHeader << ", body: \n" << messageBody << LL_ENDL;
 	
-	if(messageHeader.find("text/html") != std::string::npos)
+	if(messageHeader.find(HTTP_CONTENT_TEXT_HTML) != std::string::npos)
 	{
 		std::string message;
 
@@ -6111,9 +6118,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta
 		{
 			switch(mAudioSession->mErrorStatusCode)
 			{
-				case 404:	// NOT_FOUND
+				case HTTP_NOT_FOUND:	// NOT_FOUND
+				// *TODO: Should this be 503?
 				case 480:	// TEMPORARILY_UNAVAILABLE
-				case 408:	// REQUEST_TIMEOUT
+				case HTTP_REQUEST_TIME_OUT:	// REQUEST_TIMEOUT
 					// call failed because other user was not available
 					// treat this as an error case
 					status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 8730ef66bbaa503fcbbc7ed00efac0bf5edbed03..b7f7a11a15c0021004d9917db9e57ebec4f2f665 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -76,6 +76,7 @@
 #include "llviewershadermgr.h"
 #include "llvoavatar.h"
 #include "llvocache.h"
+#include "llappearancemgr.h"
 
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -4239,6 +4240,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	{
 		LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST);
 
+		bool requiredAppearanceUpdate = false;
+
 		//get all the faces into a list
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
@@ -4337,6 +4340,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 								const int jointCnt = pSkinData->mJointNames.size();
 								const F32 pelvisZOffset = pSkinData->mPelvisOffset;
 								bool fullRig = (jointCnt>=20) ? true : false;
+								requiredAppearanceUpdate = true;
 								if ( fullRig )
 								{
 									for ( int i=0; i<jointCnt; ++i )
@@ -4361,12 +4365,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 													pelvisGotSet = true;											
 												}										
 											}										
-										}
+										}									
 									}
 								}							
 							}
 						}
-					}
+					}					
+					
+
 					//If we've set the pelvis to a new position we need to also rebuild some information that the
 					//viewer does at launch (e.g. body size etc.)
 					if ( pelvisGotSet )
@@ -4606,6 +4612,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				drawablep->clearState(LLDrawable::RIGGED);
 			}
 		}
+
+		if ( requiredAppearanceUpdate && gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion() ) 
+		{ 
+			LLAppearanceMgr::instance().requestServerAppearanceUpdate();
+		}
 	}
 
 	group->mBufferUsage = useage;
diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp
index 641f338f2c6be343f352a010a6d0ca3849310dbd..567138e1606e92c7f7c0a5f7c7e7e9059e843299 100755
--- a/indra/newview/llwebprofile.cpp
+++ b/indra/newview/llwebprofile.cpp
@@ -67,9 +67,8 @@ class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::Responder
 	{
 	}
 
+	// *TODO: Check for 'application/json' content type, and parse json at the base class.
 	/*virtual*/ void completedRaw(
-		U32 status,
-		const std::string& reason,
 		const LLChannelDescriptors& channels,
 		const LLIOPipe::buffer_ptr_t& buffer)
 	{
@@ -78,9 +77,9 @@ class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::Responder
 		strstrm << istr.rdbuf();
 		const std::string body = strstrm.str();
 
-		if (status != 200)
+		if (getStatus() != HTTP_OK)
 		{
-			llwarns << "Failed to get upload config (" << status << ")" << llendl;
+			llwarns << "Failed to get upload config " << dumpResponse() << llendl;
 			LLWebProfile::reportImageUploadStatus(false);
 			return;
 		}
@@ -128,14 +127,12 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::
 
 public:
 	/*virtual*/ void completedRaw(
-		U32 status,
-		const std::string& reason,
 		const LLChannelDescriptors& channels,
 		const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		if (status != 200)
+		if (getStatus() != HTTP_OK)
 		{
-			llwarns << "Failed to upload image: " << status << " " << reason << llendl;
+			llwarns << "Failed to upload image " << dumpResponse() << llendl;
 			LLWebProfile::reportImageUploadStatus(false);
 			return;
 		}
@@ -161,33 +158,36 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde
 	LOG_CLASS(LLWebProfileResponders::PostImageResponder);
 
 public:
-	/*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+	/*virtual*/ void completedRaw(const LLChannelDescriptors& channels,
+								  const LLIOPipe::buffer_ptr_t& buffer)
 	{
 		// Viewer seems to fail to follow a 303 redirect on POST request
 		// (URLRequest Error: 65, Send failed since rewinding of the data stream failed).
 		// Handle it manually.
-		if (status == 303)
+		if (getStatus() == HTTP_SEE_OTHER)
 		{
 			LLSD headers = LLViewerMedia::getHeaders();
-			headers["Cookie"] = LLWebProfile::getAuthCookie();
-			const std::string& redir_url = content["location"];
-			LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl;
-			LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers);
+			headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie();
+			const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+			if (redir_url.empty())
+			{
+				llwarns << "Received empty redirection URL " << dumpResponse() << llendl;
+				LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+				LLWebProfile::reportImageUploadStatus(false);
+			}
+			else
+			{
+				LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl;
+				LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers);
+			}
 		}
 		else
 		{
-			llwarns << "Unexpected POST status: " << status << " " << reason << llendl;
-			LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << llendl;
+			llwarns << "Unexpected POST response " << dumpResponse() << llendl;
+			LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
 			LLWebProfile::reportImageUploadStatus(false);
 		}
 	}
-
-	// Override just to suppress warnings.
-	/*virtual*/ void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
-	{
-	}
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -206,7 +206,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str
 
 	LL_DEBUGS("Snapshots") << "Requesting " << config_url << llendl;
 	LLSD headers = LLViewerMedia::getHeaders();
-	headers["Cookie"] = getAuthCookie();
+	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();
 	LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers);
 }
 
@@ -230,8 +230,8 @@ void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, c
 	const std::string boundary = "----------------------------0123abcdefab";
 
 	LLSD headers = LLViewerMedia::getHeaders();
-	headers["Cookie"] = getAuthCookie();
-	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();
+	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary;
 
 	std::ostringstream body;
 
diff --git a/indra/newview/llwebsharing.cpp b/indra/newview/llwebsharing.cpp
index 3a80051b9b7896a06ac604ae025d3d5750b23db3..70361620140f44bb36abe9bb28d50c0b2f15374b 100755
--- a/indra/newview/llwebsharing.cpp
+++ b/indra/newview/llwebsharing.cpp
@@ -32,7 +32,7 @@
 #include "llagentui.h"
 #include "llbufferstream.h"
 #include "llhttpclient.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 #include "llsdserialize.h"
 #include "llsdutil.h"
 #include "llurl.h"
@@ -45,36 +45,79 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 //
-class LLWebSharingConfigResponder : public LLHTTPClient::Responder
+
+class LLWebSharingJSONResponder : public LLHTTPClient::Responder
 {
-	LOG_CLASS(LLWebSharingConfigResponder);
+	LOG_CLASS(LLWebSharingJSONResponder);
 public:
 	/// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response.
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
+	virtual void completedRaw(const LLChannelDescriptors& channels,
 							  const LLIOPipe::buffer_ptr_t& buffer)
 	{
-		LLSD content;
 		LLBufferStream istr(channels, buffer.get());
+		// *TODO: LLSD notation is not actually JSON.
 		LLPointer<LLSDParser> parser = new LLSDNotationParser();
 
-		if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
+		std::string debug_body("(empty)");
+		bool parsed=true;
+		if (EOF == istr.peek())
 		{
-			LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL;
+			parsed=false;
 		}
-		else
+		// Try to parse body as llsd, no matter what 'content-type' says.
+		else if (parser->parse(istr, mContent, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
 		{
-			completed(status, reason, content);
+			parsed=false;
+			char body[1025]; 
+			body[1024] = '\0';
+			istr.seekg(0, std::ios::beg);
+			istr.get(body,1024);
+			if (strlen(body) > 0)
+			{
+				mContent = body;
+				debug_body = body;
+			}
 		}
+
+		// Only emit a warning if we failed to parse when 'content-type' == 'application/json'
+		if (!parsed && (HTTP_CONTENT_JSON == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE)))
+		{
+			llwarns << "Failed to deserialize LLSD from JSON response. " << getURL()
+				<< " [status:" << mStatus << "] " 
+				<< "(" << mReason << ") body: " << debug_body << llendl;
+		}
+
+		if (!parsed)
+		{
+			// *TODO: This isn't necessarily the server's fault.  Using a 5xx code
+			// isn't really appropriate here.
+			// Also, this hides the actual status returned by the server....
+			mStatus = HTTP_INTERNAL_ERROR;
+			mReason = "Failed to deserialize LLSD from JSON response.";
+		}
+
+		httpCompleted();
 	}
+};
 
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+class LLWebSharingConfigResponder : public LLWebSharingJSONResponder
+{
+	LOG_CLASS(LLWebSharingConfigResponder);
+private:
+
+	virtual void httpFailure()
 	{
-		LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL;
+		LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;
 	}
 
-	virtual void result(const LLSD& content)
+	virtual void httpSuccess()
 	{
+		const LLSD& content = getContent();
+		if (!content.isMap())
+		{
+			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+			return;
+		}
 		LLWebSharing::instance().receiveConfig(content);
 	}
 };
@@ -87,39 +130,34 @@ class LLWebSharingOpenIDAuthResponder : public LLHTTPClient::Responder
 {
 	LOG_CLASS(LLWebSharingOpenIDAuthResponder);
 public:
-	/* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
-	{
-		completed(status, reason, content);
-	}
-
-	/* virtual */ void completedRaw(U32 status, const std::string& reason,
-									const LLChannelDescriptors& channels,
+	/* virtual */ void completedRaw(const LLChannelDescriptors& channels,
 									const LLIOPipe::buffer_ptr_t& buffer)
 	{
 		/// Left empty to override the default LLSD parsing behaviour.
+		httpCompleted();
 	}
 
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+private:
+	virtual void httpFailure()
 	{
-		if (HTTP_UNAUTHORIZED == status)
+		if (HTTP_UNAUTHORIZED == getStatus())
 		{
 			LL_WARNS("WebSharing") << "AU account not authenticated." << LL_ENDL;
 			// *TODO: No account found on AU, so start the account creation process here.
 		}
 		else
 		{
-			LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL;
+			LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;
 			LLWebSharing::instance().retryOpenIDAuth();
 		}
-
 	}
 
-	virtual void result(const LLSD& content)
+	virtual void httpSuccess()
 	{
-		if (content.has("set-cookie"))
+		if (hasResponseHeader(HTTP_IN_HEADER_SET_COOKIE))
 		{
 			// OpenID request succeeded and returned a session cookie.
-			LLWebSharing::instance().receiveSessionCookie(content["set-cookie"].asString());
+			LLWebSharing::instance().receiveSessionCookie(getResponseHeader(HTTP_IN_HEADER_SET_COOKIE));
 		}
 	}
 };
@@ -128,38 +166,19 @@ class LLWebSharingOpenIDAuthResponder : public LLHTTPClient::Responder
 
 ///////////////////////////////////////////////////////////////////////////////
 //
-class LLWebSharingSecurityTokenResponder : public LLHTTPClient::Responder
+class LLWebSharingSecurityTokenResponder : public LLWebSharingJSONResponder
 {
 	LOG_CLASS(LLWebSharingSecurityTokenResponder);
-public:
-	/// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response.
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
+private:
+	virtual void httpFailure()
 	{
-		LLSD content;
-		LLBufferStream istr(channels, buffer.get());
-		LLPointer<LLSDParser> parser = new LLSDNotationParser();
-
-		if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
-		{
-			LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL;
-			LLWebSharing::instance().retryOpenIDAuth();
-		}
-		else
-		{
-			completed(status, reason, content);
-		}
-	}
-
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
-	{
-		LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL;
+		LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;
 		LLWebSharing::instance().retryOpenIDAuth();
 	}
 
-	virtual void result(const LLSD& content)
+	virtual void httpSuccess()
 	{
+		const LLSD& content = getContent();
 		if (content[0].has("st") && content[0].has("expires"))
 		{
 			const std::string& token   = content[0]["st"].asString();
@@ -172,7 +191,8 @@ class LLWebSharingSecurityTokenResponder : public LLHTTPClient::Responder
 		}
 		else
 		{
-			LL_WARNS("WebSharing") << "No security token received." << LL_ENDL;
+			failureResult(HTTP_INTERNAL_ERROR, "No security token received.", content);
+			return;
 		}
 
 		LLWebSharing::instance().retryOpenIDAuth();
@@ -183,51 +203,18 @@ class LLWebSharingSecurityTokenResponder : public LLHTTPClient::Responder
 
 ///////////////////////////////////////////////////////////////////////////////
 //
-class LLWebSharingUploadResponder : public LLHTTPClient::Responder
+class LLWebSharingUploadResponder : public LLWebSharingJSONResponder
 {
 	LOG_CLASS(LLWebSharingUploadResponder);
-public:
-	/// Overrides the default LLSD parsing behaviour, to allow parsing a JSON response.
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
-	{
-/*
-		 // Dump the body, for debugging.
-
-		 LLBufferStream istr1(channels, buffer.get());
-		 std::ostringstream ostr;
-		 std::string body;
-
-		 while (istr1.good())
-		 {
-			char buf[1024];
-			istr1.read(buf, sizeof(buf));
-			body.append(buf, istr1.gcount());
-		 }
-		 LL_DEBUGS("WebSharing") << body << LL_ENDL;
-*/
-		LLSD content;
-		LLBufferStream istr(channels, buffer.get());
-		LLPointer<LLSDParser> parser = new LLSDNotationParser();
-
-		if (parser->parse(istr, content, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
-		{
-			LL_WARNS("WebSharing") << "Failed to deserialize LLSD from JSON response. " << " [" << status << "]: " << reason << LL_ENDL;
-		}
-		else
-		{
-			completed(status, reason, content);
-		}
-	}
-
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+private:
+	virtual void httpFailure()
 	{
-		LL_WARNS("WebSharing") << "Error [status:" << status << "]: " << content << LL_ENDL;
+		LL_WARNS("WebSharing") << dumpResponse() << LL_ENDL;
 	}
 
-	virtual void result(const LLSD& content)
+	virtual void httpSuccess()
 	{
+		const LLSD& content = getContent();
 		if (content[0].has("result") && content[0].has("id") &&
 			content[0]["id"].asString() == "newMediaItem")
 		{
@@ -235,8 +222,8 @@ class LLWebSharingUploadResponder : public LLHTTPClient::Responder
 		}
 		else
 		{
-			LL_WARNS("WebSharing") << "Error [" << content[0]["code"].asString()
-								   << "]: " << content[0]["message"].asString() << LL_ENDL;
+			failureResult(HTTP_INTERNAL_ERROR, "Invalid response content", content);
+			return;
 		}
 	}
 };
@@ -333,7 +320,7 @@ void LLWebSharing::sendConfigRequest()
 	LL_DEBUGS("WebSharing") << "Requesting Snapshot Sharing config data from: " << config_url << LL_ENDL;
 
 	LLSD headers = LLSD::emptyMap();
-	headers["Accept"] = "application/json";
+	headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON;
 
 	LLHTTPClient::get(config_url, new LLWebSharingConfigResponder(), headers);
 }
@@ -344,8 +331,8 @@ void LLWebSharing::sendOpenIDAuthRequest()
 	LL_DEBUGS("WebSharing") << "Starting OpenID Auth: " << auth_url << LL_ENDL;
 
 	LLSD headers = LLSD::emptyMap();
-	headers["Cookie"] = mOpenIDCookie;
-	headers["Accept"] = "*/*";
+	headers[HTTP_OUT_HEADER_COOKIE] = mOpenIDCookie;
+	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
 
 	// Send request, successful login will trigger fetching a security token.
 	LLHTTPClient::get(auth_url, new LLWebSharingOpenIDAuthResponder(), headers);
@@ -371,10 +358,10 @@ void LLWebSharing::sendSecurityTokenRequest()
 	LL_DEBUGS("WebSharing") << "Fetching security token from: " << token_url << LL_ENDL;
 
 	LLSD headers = LLSD::emptyMap();
-	headers["Cookie"] = mSessionCookie;
+	headers[HTTP_OUT_HEADER_COOKIE] = mSessionCookie;
 
-	headers["Accept"] = "application/json";
-	headers["Content-Type"] = "application/json";
+	headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON;
+	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_JSON;
 
 	std::ostringstream body;
 	body << "{ \"gadgets\": [{ \"url\":\""
@@ -400,10 +387,10 @@ void LLWebSharing::sendUploadRequest()
 	static const std::string BOUNDARY("------------abcdef012345xyZ");
 
 	LLSD headers = LLSD::emptyMap();
-	headers["Cookie"] = mSessionCookie;
+	headers[HTTP_OUT_HEADER_COOKIE] = mSessionCookie;
 
-	headers["Accept"] = "application/json";
-	headers["Content-Type"] = "multipart/form-data; boundary=" + BOUNDARY;
+	headers[HTTP_OUT_HEADER_ACCEPT] = HTTP_CONTENT_JSON;
+	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + BOUNDARY;
 
 	std::ostringstream body;
 	body << "--" << BOUNDARY << "\r\n"
diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp
index 93eba5b6048aeddcf4552df38f76c295fee5eef0..3bedfbe502af09f22717da6c035bf5e8e7c47c96 100755
--- a/indra/newview/llwlhandlers.cpp
+++ b/indra/newview/llwlhandlers.cpp
@@ -95,8 +95,9 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()
 {
 	mID = ++sCount;
 }
-/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content)
+/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess()
 {
+	const LLSD& unvalidated_content = getContent();
 	LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;
 
 	if (mID != sCount)
@@ -122,10 +123,10 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()
 	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content);
 }
 /*virtual*/
-void LLEnvironmentRequestResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLEnvironmentRequestResponder::httpFailure()
 {
-	LL_INFOS("WindlightCaps") << "Got an error, not using region windlight... [status:" 
-		<< status << "]: " << content << LL_ENDL;
+	LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... "
+			<< dumpResponse() << LL_ENDL;
 	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());
 }
 
@@ -169,8 +170,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)
 /****
  * LLEnvironmentApplyResponder
  ****/
-/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content)
+/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess()
 {
+	const LLSD& content = getContent();
+	if (!content.isMap() || !content.has("regionID"))
+	{
+		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+		return;
+	}
 	if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID())
 	{
 		LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently "
@@ -185,7 +192,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)
 	}
 	else
 	{
-		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  Reason from sim: " << content["fail_reason"].asString() << LL_ENDL;
+		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  " << dumpResponse() << LL_ENDL;
 		LLSD args(LLSD::emptyMap());
 		args["FAIL_REASON"] = content["fail_reason"].asString();
 		LLNotificationsUtil::add("WLRegionApplyFail", args);
@@ -193,14 +200,14 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)
 	}
 }
 /*virtual*/
-void LLEnvironmentApplyResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void LLEnvironmentApplyResponder::httpFailure()
 {
-	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region!  [status:"
-		<< status << "]: " << content << LL_ENDL;
+	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! "
+		<< dumpResponse() << LL_ENDL;
 
 	LLSD args(LLSD::emptyMap());
 	std::stringstream msg;
-	msg << reason << " (Code " << status << ")";
+	msg << getReason() << " (Code " << getStatus() << ")";
 	args["FAIL_REASON"] = msg.str();
 	LLNotificationsUtil::add("WLRegionApplyFail", args);
 }
diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h
index 598ce6d52ac52c6c54989ce6d5498237564b92b5..089c799da7cac21dd37228c41411fe0acd7854f4 100755
--- a/indra/newview/llwlhandlers.h
+++ b/indra/newview/llwlhandlers.h
@@ -45,9 +45,9 @@ class LLEnvironmentRequest
 class LLEnvironmentRequestResponder: public LLHTTPClient::Responder
 {
 	LOG_CLASS(LLEnvironmentRequestResponder);
-public:
-	virtual void result(const LLSD& content);
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+private:
+	/* virtual */ void httpSuccess();
+	/* virtual */ void httpFailure();
 
 private:
 	friend class LLEnvironmentRequest;
@@ -72,7 +72,7 @@ class LLEnvironmentApply
 class LLEnvironmentApplyResponder: public LLHTTPClient::Responder
 {
 	LOG_CLASS(LLEnvironmentApplyResponder);
-public:
+private:
 	/*
 	 * Expecting reply from sim in form of:
 	 * {
@@ -87,10 +87,10 @@ class LLEnvironmentApplyResponder: public LLHTTPClient::Responder
 	 *   fail_reason : string
 	 * }
 	 */
-	virtual void result(const LLSD& content);
+	/* virtual */ void httpSuccess();
 
-	// non-200 errors only
-	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
+	// non-2xx errors only
+	/* virtual */ void httpFailure();
 
 private:
 	friend class LLEnvironmentApply;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 793becf0c82e14397692d9838e7d0ccb4926129b..d9da639af9865dc51f70f6c70fa077e176578801 100755
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1065,6 +1065,8 @@ class LLEstablishAgentCommunication : public LLHTTPNode
 					<< sim << llendl;
 			return;
 		}
+		LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == "
+				<< input["body"]["seed-capability"] << LL_ENDL;
 		regionp->setSeedCapability(input["body"]["seed-capability"]);
 	}
 };
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index 0da70d398b06ca0b35e50a7c40cc737b3efa1491..7c5f8be1b52cc937d5038b69bc2cc0d3aeb27746 100755
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -331,7 +331,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
 	   This might help with bug #503 */
 	mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
 
-    mCurlRequest->slist_append("Content-Type: text/xml");
+    mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
 
 	if (useGzip)
 	{
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 970a11c6c48c939e3d0371f61fa0bf4a7ccbb7bd..c3d8a528c56caf33a92125a41958c96fc8c4c216 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -10112,5 +10112,7 @@ Cannot create large prims that intersect other players.  Please re-try when othe
      name="okignore"
      yestext="OK"/>
   </notification>
-  
+
+
+ 
 </notifications>
diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..25e6de46d9572b19246f599db643b5363a37d8ff
--- /dev/null
+++ b/indra/newview/tests/llhttpretrypolicy_test.cpp
@@ -0,0 +1,328 @@
+/** 
+ * @file llhttpretrypolicy_test.cpp
+ * @brief Header tests to exercise the LLHTTPRetryPolicy classes.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "../llviewerprecompiledheaders.h"
+#include "../llhttpretrypolicy.h"
+#include "lltut.h"
+
+namespace tut
+{
+struct TestData
+{
+};
+
+typedef test_group<TestData>	RetryPolicyTestGroup;
+typedef RetryPolicyTestGroup::object		RetryPolicyTestObject;
+RetryPolicyTestGroup retryPolicyTestGroup("retry_policy");
+
+template<> template<>
+void RetryPolicyTestObject::test<1>()
+{
+	LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0);
+	LLSD headers;
+	F32 wait_seconds;
+	
+	// No retry until we've failed a try.
+	ensure("never retry 0", !never_retry.shouldRetry(wait_seconds));
+
+	// 0 retries max.
+	never_retry.onFailure(500,headers);
+	ensure("never retry 1", !never_retry.shouldRetry(wait_seconds)); 
+}
+
+template<> template<>
+void RetryPolicyTestObject::test<2>()
+{
+	LLSD headers;
+	F32 wait_seconds;
+
+	// Normally only retry on server error (5xx)
+	LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10);
+	noRetry404.onFailure(404,headers);
+	ensure("no retry on 404", !noRetry404.shouldRetry(wait_seconds)); 
+
+	// Can retry on 4xx errors if enabled by flag.
+	bool do_retry_4xx = true;
+	LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx);
+	doRetry404.onFailure(404,headers);
+	ensure("do retry on 404", doRetry404.shouldRetry(wait_seconds)); 
+}
+
+template<> template<>
+void RetryPolicyTestObject::test<3>()
+{
+	// Should retry after 1.0, 2.0, 3.0, 3.0 seconds.
+	LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4);
+	LLSD headers;
+	F32 wait_seconds;
+	bool should_retry;
+	U32 frac_bits = 6;
+
+	// No retry until we've failed a try.
+	ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds));
+
+	// Starting wait 1.0
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 1", should_retry);
+	ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits);
+
+	// Double wait to 2.0
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 2", should_retry);
+	ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits);
+
+	// Hit max wait of 3.0 (4.0 clamped to max 3)
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 3", should_retry);
+	ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits);
+
+	// At max wait, should stay at 3.0
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 4", should_retry);
+	ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits);
+
+	// Max retries, should fail now.
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 5", !should_retry);
+
+	// Max retries, should fail now.
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 5", !should_retry);
+
+	// After a success, should reset to the starting state.
+	basic_retry.onSuccess();
+
+	// No retry until we've failed a try.
+	ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds));
+
+	// Starting wait 1.0
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 7", should_retry);
+	ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits);
+
+	// Double wait to 2.0
+	basic_retry.onFailure(500,headers);
+	should_retry = basic_retry.shouldRetry(wait_seconds);
+	ensure("basic_retry 8", should_retry);
+	ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits);
+}
+
+// Retries should stop as soon as a non-5xx error is received.
+template<> template<>
+void RetryPolicyTestObject::test<4>()
+{
+	// Should retry after 1.0, 2.0, 3.0, 3.0 seconds.
+	LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4);
+	LLSD headers;
+	F32 wait_seconds;
+	bool should_retry;
+	U32 frac_bits = 6;
+
+	// Starting wait 1.0
+	killer404.onFailure(500,headers);
+	should_retry = killer404.shouldRetry(wait_seconds);
+	ensure("killer404 1", should_retry);
+	ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits);
+
+	// Double wait to 2.0
+	killer404.onFailure(500,headers);
+	should_retry = killer404.shouldRetry(wait_seconds);
+	ensure("killer404 2", should_retry);
+	ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits);
+
+	// Should fail on non-5xx
+	killer404.onFailure(404,headers);
+	should_retry = killer404.shouldRetry(wait_seconds);
+	ensure("killer404 3", !should_retry);
+
+	// After a non-5xx, should keep failing.
+	killer404.onFailure(500,headers);
+	should_retry = killer404.shouldRetry(wait_seconds);
+	ensure("killer404 4", !should_retry);
+}
+
+// Test handling of "retry-after" header. If present, this header
+// value overrides the computed delay, but does not affect the
+// progression of delay values.  For example, if the normal
+// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls
+// get a retry header of 33, the pattern would become 1,33,33,8...
+template<> template<>
+void RetryPolicyTestObject::test<5>()
+{
+	LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6);
+	LLSD headers_with_retry;
+	headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666";
+	LLSD headers_without_retry;
+	F32 wait_seconds;
+	bool should_retry;
+	U32 frac_bits = 6;
+
+	policy.onFailure(500,headers_without_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 1", should_retry);
+	ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits);
+
+	policy.onFailure(500,headers_without_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 2", should_retry);
+	ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits);
+
+	policy.onFailure(500,headers_with_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 3", should_retry);
+	// 4.0 overrides by header -> 666.0
+	ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits);
+
+	policy.onFailure(500,headers_with_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 4", should_retry);
+	// 8.0 overrides by header -> 666.0
+	ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits);
+
+	policy.onFailure(500,headers_without_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 5", should_retry);
+	ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits);
+
+	policy.onFailure(500,headers_without_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 6", should_retry);
+	ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits);
+
+	policy.onFailure(500,headers_with_retry);
+	should_retry = policy.shouldRetry(wait_seconds);
+	ensure("retry header 7", !should_retry);
+}
+
+// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait),
+// used by header parsing of the retry policy.
+template<> template<>
+void RetryPolicyTestObject::test<6>()
+{
+	F32 seconds_to_wait;
+	bool success;
+
+	std::string str1("0");
+	seconds_to_wait = F32_MAX;
+	success = getSecondsUntilRetryAfter(str1, seconds_to_wait);
+	ensure("parse 1", success);
+	ensure_equals("parse 1", seconds_to_wait, 0.0);
+
+	std::string str2("999.9");
+	seconds_to_wait = F32_MAX;
+	success = getSecondsUntilRetryAfter(str2, seconds_to_wait);
+	ensure("parse 2", success);
+	ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8);
+
+	time_t nowseconds;
+	time(&nowseconds);
+	std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123();
+	seconds_to_wait = F32_MAX;
+	success = getSecondsUntilRetryAfter(str3, seconds_to_wait);
+	std::cerr << " str3 [" << str3 << "]" << std::endl;
+	ensure("parse 3", success);
+	ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F);
+}
+
+// Test retry-after field in both llmessage and CoreHttp headers.
+template<> template<>
+void RetryPolicyTestObject::test<7>()
+{
+	std::cerr << "7 starts" << std::endl;
+	
+	LLSD sd_headers;
+	time_t nowseconds;
+	time(&nowseconds);
+	LLAdaptiveRetryPolicy policy(17.0,644.0,3.0,5);
+	F32 seconds_to_wait;
+	bool should_retry;
+
+	// No retry until we've failed a try.
+	ensure("header 0", !policy.shouldRetry(seconds_to_wait));
+	
+	// no retry header, use default.
+	policy.onFailure(500,LLSD());
+	should_retry = policy.shouldRetry(seconds_to_wait);
+	ensure("header 1", should_retry);
+	ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6);
+
+	// retry header should override, give delay of 0
+	std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123();
+	sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string;
+	policy.onFailure(503,sd_headers);
+	should_retry = policy.shouldRetry(seconds_to_wait);
+	ensure("header 2", should_retry);
+	ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F);
+
+	LLCore::HttpResponse *response;
+	LLCore::HttpHeaders *headers;
+
+	response = new LLCore::HttpResponse();
+	headers = new LLCore::HttpHeaders();
+	response->setStatus(503);
+	response->setHeaders(headers);
+	headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600"));
+	policy.onFailure(response);
+	should_retry = policy.shouldRetry(seconds_to_wait);
+	ensure("header 3",should_retry);
+	ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6);
+	response->release();
+
+	response = new LLCore::HttpResponse();
+	headers = new LLCore::HttpHeaders();
+	response->setStatus(503);
+	response->setHeaders(headers);
+	time(&nowseconds);
+	date_string = LLDate((F64)(nowseconds+77)).asRFC1123();
+	std::cerr << "date_string [" << date_string << "]" << std::endl;
+	headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string);
+	policy.onFailure(response);
+	should_retry = policy.shouldRetry(seconds_to_wait);
+	ensure("header 4",should_retry);
+	ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F);
+	response->release();
+
+	// Timeout should be clamped at max.
+	policy.onFailure(500,LLSD());
+	should_retry = policy.shouldRetry(seconds_to_wait);
+	ensure("header 5", should_retry);
+	ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6);
+
+	// No more retries.
+	policy.onFailure(500,LLSD());
+	should_retry = policy.shouldRetry(seconds_to_wait);
+	ensure("header 6", !should_retry);
+}
+
+}
+
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index 41cb344808371cf9dc9c87fe31c28b7f09a9782d..01195d1269b5fae8db3240f8e17e296162cb0136 100755
--- a/indra/newview/tests/llmediadataclient_test.cpp
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -33,7 +33,7 @@
 #include "llsdserialize.h"
 #include "llsdutil.h"
 #include "llerrorcontrol.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
 
 #include "../llmediadataclient.h"
 #include "../llvovolume.h"
@@ -128,7 +128,7 @@ void LLHTTPClient::post(
 	{
 		LLSD content;
 		content["reason"] = "fake reason";
-		responder->errorWithContent(HTTP_SERVICE_UNAVAILABLE, "fake reason", content);
+		responder->failureResult(HTTP_SERVICE_UNAVAILABLE, "fake reason", content);
 		return;
 	}
 	else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR) 
@@ -136,8 +136,8 @@ void LLHTTPClient::post(
 		LLSD error;
 		error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;
 		result["error"] = error;
-	}	
-	responder->result(result);
+	}
+	responder->successResult(result);
 }
 
 const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp
index ed66066b0ad840f97dc044d79c2b9396b0dac239..c49b0350e9b279925145c3674de7861cbd8a9297 100755
--- a/indra/newview/tests/llremoteparcelrequest_test.cpp
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -40,12 +40,14 @@ namespace {
 
 LLCurl::Responder::Responder() { }
 LLCurl::Responder::~Responder() { }
-void LLCurl::Responder::error(U32,std::string const &) { }
-void LLCurl::Responder::result(LLSD const &) { }
-void LLCurl::Responder::errorWithContent(U32 status,std::string const &,LLSD const &) { }
-void LLCurl::Responder::completedRaw(U32 status, std::string const &, LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
-void LLCurl::Responder::completed(U32 status, std::string const &, LLSD const &) { }
-void LLCurl::Responder::completedHeader(U32 status, std::string const &, LLSD const &) { }
+void LLCurl::Responder::httpFailure() { }
+void LLCurl::Responder::httpSuccess() { }
+void LLCurl::Responder::httpCompleted() { }
+void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) { }
+void LLCurl::Responder::successResult(const LLSD& content) { }
+void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { }
+std::string LLCurl::Responder::dumpResponse() const { return "(failure)"; }
+void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
 void LLMessageSystem::getF32(char const *,char const *,F32 &,S32) { }
 void LLMessageSystem::getU8(char const *,char const *,U8 &,S32) { }
 void LLMessageSystem::getS32(char const *,char const *,S32 &,S32) { }
@@ -85,7 +87,7 @@ namespace tut
 
 		virtual void setParcelID(const LLUUID& parcel_id) { }
 
-		virtual void setErrorStatus(U32 status, const std::string& reason) { }
+		virtual void setErrorStatus(S32 status, const std::string& reason) { }
 
 		bool mProcessed;
 	};
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
index fd9527d631a921ce957e8b41e1b56a1c98ec4123..b28eb5db435d1e055982c3cf9d5ba4d0a918493a 100755
--- a/indra/newview/tests/lltranslate_test.cpp
+++ b/indra/newview/tests/lltranslate_test.cpp
@@ -34,6 +34,8 @@
 #include "lltrans.h"
 #include "llui.h"
 
+#include "../../llmessage/llhttpconstants.cpp"
+
 static const std::string GOOGLE_VALID_RESPONSE1 =
 "{\
  \"data\": {\
@@ -300,12 +302,10 @@ std::string LLControlGroup::getString(const std::string& name) { return "dummy";
 LLControlGroup::~LLControlGroup() {}
 
 LLCurl::Responder::Responder() {}
-void LLCurl::Responder::completedHeader(U32, std::string const&, LLSD const&) {}
-void LLCurl::Responder::completedRaw(U32, const std::string&, const LLChannelDescriptors&, const LLIOPipe::buffer_ptr_t& buffer) {}
-void LLCurl::Responder::completed(U32, std::string const&, LLSD const&) {}
-void LLCurl::Responder::error(U32, std::string const&) {}
-void LLCurl::Responder::errorWithContent(U32, std::string const&, LLSD const&) {}
-void LLCurl::Responder::result(LLSD const&) {}
+void LLCurl::Responder::httpFailure() { }
+void LLCurl::Responder::httpSuccess() { }
+void LLCurl::Responder::httpCompleted() { }
+void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { }
 LLCurl::Responder::~Responder() {}
 
 void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32) {}
diff --git a/indra/test/llassetuploadqueue_tut.cpp b/indra/test/llassetuploadqueue_tut.cpp
index ec952e0058c47aa0224066f4f53913f408161f87..25efe63d3fa84d41f43be6a497b46b915958c4cc 100755
--- a/indra/test/llassetuploadqueue_tut.cpp
+++ b/indra/test/llassetuploadqueue_tut.cpp
@@ -45,11 +45,11 @@ LLAssetUploadResponder::~LLAssetUploadResponder()
 {
 }
 
-void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason)
+void LLAssetUploadResponder::httpFailure()
 {
 }
 
-void LLAssetUploadResponder::result(const LLSD& content)
+void LLAssetUploadResponder::httpSuccess()
 {
 }
 
diff --git a/indra/test/llblowfish_tut.cpp b/indra/test/llblowfish_tut.cpp
index 2573cab81faf5cae056677098d1a51d0746742b3..20e7960829f4a7f6269a69359c4dbdc615d47de9 100755
--- a/indra/test/llblowfish_tut.cpp
+++ b/indra/test/llblowfish_tut.cpp
@@ -65,7 +65,7 @@ namespace tut
 			}
 			if (!fp)
 			{
-				llwarns << "unabled to open " << filename << llendl;
+				llwarns << "unable to open " << filename << llendl;
 				return false;
 			}
 
diff --git a/indra/test/llhttpnode_tut.cpp b/indra/test/llhttpnode_tut.cpp
index 216c59d766de0620f73e62c472c3beb02a16e2c7..c528a3412927ea9032eb839ef14bf18c4f42b32f 100755
--- a/indra/test/llhttpnode_tut.cpp
+++ b/indra/test/llhttpnode_tut.cpp
@@ -44,7 +44,7 @@ namespace tut
 			std::ostringstream pathOutput;
 			bool addSlash = false;
 			
-			LLSD& remainder = mContext["request"]["remainder"];
+			LLSD& remainder = mContext[CONTEXT_REQUEST]["remainder"];
 			for (LLSD::array_const_iterator i = remainder.beginArray();
 				i != remainder.endArray();
 				++i)
@@ -81,6 +81,7 @@ namespace tut
 			void result(const LLSD& result) { mResult = result; }
 			void status(S32 code, const std::string& message) { }
 			void extendedResult(S32 code, const std::string& message, const LLSD& headers) { }
+			void extendedResult(S32 code, const LLSD& result, const LLSD& headers) { }
 			
 		private:
 			Response() {;} // Must be accessed through LLPointer.
diff --git a/indra/test/llsd_new_tut.cpp b/indra/test/llsd_new_tut.cpp
index f928a1bad0e6176af82a175428298f3b4f637ad4..03df1d339bc4f1856e3decdb97847a845fc6530d 100755
--- a/indra/test/llsd_new_tut.cpp
+++ b/indra/test/llsd_new_tut.cpp
@@ -93,6 +93,18 @@ namespace tut
 			ensure(			s + " type",	traits.checkType(actual));
 			ensure_equals(	s + " value",	traits.get(actual), expectedValue);
 		}
+
+		template<class T>
+		static void ensureTypeAndRefValue(const char* msg, const LLSD& actual,
+			const T& expectedValue)
+		{
+			LLSDTraits<const T&> traits;
+			
+			std::string s(msg);
+			
+			ensure(			s + " type",	traits.checkType(actual));
+			ensure_equals(	s + " value",	traits.get(actual), expectedValue);
+		}
 	};
 	
 	typedef test_group<SDTestData>	SDTestGroup;
@@ -162,7 +174,7 @@ namespace tut
 		std::vector<U8> data;
 		copy(&source[0], &source[sizeof(source)], back_inserter(data));
 		
-		v = data;		ensureTypeAndValue("set to data", v, data);
+		v = data;		ensureTypeAndRefValue("set to data", v, data);
 		
 		v.clear();
 		ensure("reset to undefined", v.type() == LLSD::TypeUndefined);
@@ -213,8 +225,8 @@ namespace tut
 		const char source[] = "once in a blue moon";
 		std::vector<U8> data;
 		copy(&source[0], &source[sizeof(source)], back_inserter(data));
-		LLSD x1(data);	ensureTypeAndValue("construct vector<U8>", x1, data);
-		LLSD x2 = data;	ensureTypeAndValue("initialize vector<U8>", x2, data);
+		LLSD x1(data);	ensureTypeAndRefValue("construct vector<U8>", x1, data);
+		LLSD x2 = data;	ensureTypeAndRefValue("initialize vector<U8>", x2, data);
 	}
 	
 	void checkConversions(const char* msg, const LLSD& v,
@@ -754,42 +766,6 @@ namespace tut
 			w = "nice day";
 		}
 
-		{
-			SDAllocationCheck check("shared values test for threaded work", 9);
-
-			//U32 start_llsd_count = llsd::outstandingCount();
-
-			LLSD m = LLSD::emptyMap();
-
-			m["one"] = 1;
-			m["two"] = 2;
-			m["one_copy"] = m["one"];			// 3 (m, "one" and "two")
-
-			m["undef_one"] = LLSD();
-			m["undef_two"] = LLSD();
-			m["undef_one_copy"] = m["undef_one"];
-
-			{	// Ensure first_array gets freed to avoid counting it
-				LLSD first_array = LLSD::emptyArray();
-				first_array.append(1.0f);
-				first_array.append(2.0f);			
-				first_array.append(3.0f);			// 7
-
-				m["array"] = first_array;
-				m["array_clone"] = first_array;
-				m["array_copy"] = m["array"];		// 7
-			}
-
-			m["string_one"] = "string one value";
-			m["string_two"] = "string two value";
-			m["string_one_copy"] = m["string_one"];		// 9
-
-			//U32 llsd_object_count = llsd::outstandingCount();
-			//std::cout << "Using " << (llsd_object_count - start_llsd_count) << " LLSD objects" << std::endl;
-
-			//m.dumpStats();
-		}
-
 		{
 			SDAllocationCheck check("shared values test for threaded work", 9);
 
@@ -852,3 +828,4 @@ namespace tut
 		test serializations
 	*/
 }
+
diff --git a/indra/test/llsdtraits.h b/indra/test/llsdtraits.h
index 8144aaee948924dde8ab43e659ec6f1e2cefd888..07f6193ce247fdd98ce797964dcc3c8eaa42702e 100755
--- a/indra/test/llsdtraits.h
+++ b/indra/test/llsdtraits.h
@@ -93,7 +93,7 @@ LLSDTraits<LLSD::URI>::LLSDTraits()
 { }
 
 template<> inline
-LLSDTraits<LLSD::Binary>::LLSDTraits()
+LLSDTraits<const LLSD::Binary&>::LLSDTraits()
 	: type(LLSD::TypeBinary), getter(&LLSD::asBinary)
 { }
 
diff --git a/indra/test/lltut.h b/indra/test/lltut.h
index 55d84bcaca3d5199ee88ba95a6222f465ced845b..243e869be7f6c3a89eeb4a7c7d14e9c61864a6b4 100755
--- a/indra/test/lltut.h
+++ b/indra/test/lltut.h
@@ -65,6 +65,16 @@ namespace tut
 		ensure_approximately_equals(NULL, actual, expected, frac_bits);
 	}
 
+	inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta)
+	{
+		if (fabs(actual-expected)>delta)
+		{
+			std::stringstream ss;
+			ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta;
+			throw tut::failure(ss.str().c_str());
+		}
+	}
+
 	inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len)
 	{
 		if((expected_len != actual_len) || 
diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp
index d971b334752dc1c99e5c7bc80d62f84430a62a10..0dae5178be2a4266d114bcdf8946b41b5b6263ca 100755
--- a/indra/test/message_tut.cpp
+++ b/indra/test/message_tut.cpp
@@ -46,6 +46,7 @@ namespace
 			mStatus = code;
 		}
 		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) { }
+		virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers) { }
 		S32 mStatus;
 	};
 }
@@ -142,7 +143,7 @@ namespace tut
 		const LLSD message;
 		const LLPointer<Response> response = new Response();
 		gMessageSystem->dispatch(name, message, response);
-		ensure_equals(response->mStatus, 404);
+		ensure_equals(response->mStatus, HTTP_NOT_FOUND);
 	}
 }
 
diff --git a/indra/test/mock_http_client.cpp b/indra/test/mock_http_client.cpp
index d7ef407d52e450c79d5ed97a2734f75256ec2dfd..e72902bfc2bbeb931ac934dacfba1990b00543ec 100755
--- a/indra/test/mock_http_client.cpp
+++ b/indra/test/mock_http_client.cpp
@@ -25,8 +25,7 @@
  */
 
 #include "linden_common.h"
-#include "llsdhttpserver.h"
-#include "lliohttpserver.h"
+#include "llhttpnode.h"
 
 namespace tut
 {
diff --git a/indra/test/mock_http_client.h b/indra/test/mock_http_client.h
index 7668a43fdf94ebc58a9d51aac09910c9c450527b..a2b9b435fb1db995e0108cbc65bcb6c1923b2b86 100755
--- a/indra/test/mock_http_client.h
+++ b/indra/test/mock_http_client.h
@@ -98,7 +98,7 @@ namespace tut
 			if (mSawError)
 			{
 				std::string msg =
-					llformat("error() called when not expected, status %d",
+					llformat("httpFailure() called when not expected, status %d",
 						mStatus); 
 				fail(msg);
 			}
@@ -108,7 +108,7 @@ namespace tut
 		{
 			if (!mSawError)
 			{
-				fail("error() wasn't called");
+				fail("httpFailure() wasn't called");
 			}
 		}
 		
@@ -119,7 +119,7 @@ namespace tut
 	
 	protected:
 		bool mSawError;
-		U32 mStatus;
+		S32 mStatus;
 		std::string mReason;
 		bool mSawCompleted;
 		LLSD mResult;
@@ -144,23 +144,22 @@ namespace tut
 				mClient.mResultDeleted = true;
 			}
 			
-			virtual void error(U32 status, const std::string& reason)
+		protected:
+			virtual void httpFailure()
 			{
 				mClient.mSawError = true;
-				mClient.mStatus = status;
-				mClient.mReason = reason;
+				mClient.mStatus = getStatus();
+				mClient.mReason = getReason();
 			}
 
-			virtual void result(const LLSD& content)
+			virtual void httpSuccess()
 			{
-				mClient.mResult = content;
+				mClient.mResult = getContent();
 			}
 
-			virtual void completed(
-							U32 status, const std::string& reason,
-							const LLSD& content)
+			virtual void httpCompleted()
 			{
-				LLHTTPClient::Responder::completed(status, reason, content);
+				LLHTTPClient::Responder::httpCompleted();
 				
 				mClient.mSawCompleted = true;
 			}
diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
index 1e768f52d9d5ebac40a3e5eadbbbaf3f1e49029b..cdb9b456824226a2c240c7013c12706561cf7f8c 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -134,12 +134,13 @@ void LLUpdateChecker::Implementation::checkVersion(std::string const & hostUrl,
 	}
 }
 
-void LLUpdateChecker::Implementation::completed(U32 status,
-												const std::string & reason,
-												const LLSD & content)
+void LLUpdateChecker::Implementation::httpCompleted()
 {
 	mInProgress = false;	
-	
+
+	S32 status = getStatus();
+	const LLSD& content = getContent();
+	const std::string& reason = getReason();
 	if(status != 200)
 	{
 		std::string server_error;
@@ -195,8 +196,9 @@ void LLUpdateChecker::Implementation::completed(U32 status,
 }
 
 
-void LLUpdateChecker::Implementation::error(U32 status, const std::string & reason)
+void LLUpdateChecker::Implementation::httpFailure()
 {
+	const std::string& reason = getReason();
 	mInProgress = false;
 	LL_WARNS("UpdaterService") << "update check failed; " << reason << LL_ENDL;
 	mClient.error(reason);
diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h
index 8e8558749030b5368b143612b00e431a345bfa6f..2624869e61bdf8f897661d1d8dc903f9bde37245 100755
--- a/indra/viewer_components/updater/llupdatechecker.h
+++ b/indra/viewer_components/updater/llupdatechecker.h
@@ -53,11 +53,10 @@ class LLUpdateChecker {
 						  bool                willing_to_test
 						  );
 	
+    protected:
 		// Responder:
-		virtual void completed(U32 status,
-							   const std::string & reason,
-							   const LLSD& content);
-		virtual void error(U32 status, const std::string & reason);
+		virtual void httpCompleted();
+		virtual void httpFailure();
 	
 	private:	
 		static const char * sLegacyProtocolVersion;