diff options
205 files changed, 7066 insertions, 4665 deletions
diff --git a/autobuild.xml b/autobuild.xml index 148ca1710b..331e3d8cec 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> @@ -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 0094e313c7..7fc6957254 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 e003ed7788..48e8b566a6 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 3bb759d458..e3497c107d 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 bce2540258..0a6a236d34 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -137,7 +137,7 @@ public:  	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 3a4a8facc2..72a997cd89 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 0173461dad..0000000000 --- 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 8276ec836a..9e4b92227e 100755 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -126,7 +126,9 @@ public:  	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 5eb69059ac..b9f490718c 100755 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -249,7 +249,10 @@ public:  		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 ad4fce6f35..774d827762 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> @@ -1261,12 +1261,37 @@ 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 e7a5507385..23a0c8cfb1 100755 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -416,7 +416,8 @@ public:  	typedef enum e_formatter_options_type  	{  		OPTIONS_NONE = 0, -		OPTIONS_PRETTY = 1 +		OPTIONS_PRETTY = 1, +		OPTIONS_PRETTY_BINARY = 2  	} EFormatterOptions;  	/**  @@ -507,6 +508,17 @@ public:  	 * @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 @@ protected:   *  </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 @@ public:  		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 cef743a7be..3ef7a7e4c1 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 803417d368..562fd26658 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 6fe0bfc7d1..d49f615ac4 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 51a8eaf998..95e0f72c0b 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 40ad4f047d..909dc5b0cb 100755 --- a/indra/llcorehttp/examples/http_texture_load.cpp +++ b/indra/llcorehttp/examples/http_texture_load.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -328,7 +328,7 @@ WorkingSet::WorkingSet()  	mTextures.reserve(30000);  	mHeaders = new LLCore::HttpHeaders; -	mHeaders->mHeaders.push_back("Accept: image/x-j2c"); +	mHeaders->append("Accept", "image/x-j2c");  } diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp index 2832696271..23ebea361c 100755 --- a/indra/llcorehttp/httpheaders.cpp +++ b/indra/llcorehttp/httpheaders.cpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc.   *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,8 @@  #include "httpheaders.h" +#include "llstring.h" +  namespace LLCore  { @@ -40,5 +42,142 @@ HttpHeaders::~HttpHeaders()  {} +void +HttpHeaders::clear() +{ +	mHeaders.clear(); +} + + +void HttpHeaders::append(const std::string & name, const std::string & value) +{ +	mHeaders.push_back(value_type(name, value)); +} + + +void HttpHeaders::append(const char * name, const char * value) +{ +	mHeaders.push_back(value_type(name, value)); +} + + +void HttpHeaders::appendNormal(const char * header, size_t size) +{ +	std::string name; +	std::string value; + +	int col_pos(0); +	for (; col_pos < size; ++col_pos) +	{ +		if (':' == header[col_pos]) +			break; +	} +	 +	if (col_pos < size) +	{ +		// Looks like a header, split it and normalize. +		// Name is everything before the colon, may be zero-length. +		name.assign(header, col_pos); + +		// Value is everything after the colon, may also be zero-length. +		const size_t val_len(size - col_pos - 1); +		if (val_len) +		{ +			value.assign(header + col_pos + 1, val_len); +		} + +		// Clean the strings +		LLStringUtil::toLower(name); +		LLStringUtil::trim(name); +		LLStringUtil::trimHead(value); +	} +	else +	{ +		// Uncertain what this is, we'll pack it as +		// a name without a value.  Won't clean as we don't +		// know what it is... +		name.assign(header, size); +	} + +	mHeaders.push_back(value_type(name, value)); +} + + +// Find from end to simulate a tradition of using single-valued +// std::map for this in the past. +const std::string * HttpHeaders::find(const char * name) const +{ +	const_reverse_iterator iend(rend()); +	for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) +	{ +		if ((*iter).first == name) +		{ +			return &(*iter).second; +		} +	} +	return NULL; +} + + +// Standard Iterators +HttpHeaders::iterator HttpHeaders::begin() +{ +	return mHeaders.begin(); +} + + +HttpHeaders::const_iterator HttpHeaders::begin() const +{ +	return mHeaders.begin(); +} + + +HttpHeaders::iterator HttpHeaders::end() +{ +	return mHeaders.end(); +} + + +HttpHeaders::const_iterator HttpHeaders::end() const +{ +	return mHeaders.end(); +} + + +// Standard Reverse Iterators +HttpHeaders::reverse_iterator HttpHeaders::rbegin() +{ +	return mHeaders.rbegin(); +} + + +HttpHeaders::const_reverse_iterator HttpHeaders::rbegin() const +{ +	return mHeaders.rbegin(); +} + + +HttpHeaders::reverse_iterator HttpHeaders::rend() +{ +	return mHeaders.rend(); +} + + +HttpHeaders::const_reverse_iterator HttpHeaders::rend() const +{ +	return mHeaders.rend(); +} + + +// Return the raw container to the caller. +// +// To be used FOR UNIT TESTS ONLY. +// +HttpHeaders::container_t & HttpHeaders::getContainerTESTONLY() +{ +	return mHeaders; +} + +  }   // end namespace LLCore diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index 3449daa3a1..f70cd898f3 100755 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc.   *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -43,13 +43,26 @@ namespace LLCore  /// caller has asked that headers be returned (not the default  /// option).  /// -/// @note -/// This is a minimally-functional placeholder at the moment -/// to fill out the class hierarchy.  The final class will be -/// something else, probably more pair-oriented.  It's also -/// an area where shared values are desirable so refcounting is -/// already specced and a copy-on-write scheme imagined. -/// Expect changes here. +/// Class is mostly a thin wrapper around a vector of pairs +/// of strings.  Methods provided are few and intended to +/// reflect actual use patterns.  These include: +/// - Clearing the list +/// - Appending a name/value pair to the vector +/// - Processing a raw byte string into a normalized name/value +///   pair and appending the result. +/// - Simple case-sensitive find-last-by-name search +/// - Forward and reverse iterators over all pairs +/// +/// Container is ordered and multi-valued.  Headers are +/// written in the order in which they are appended and +/// are stored in the order in which they're received from +/// the wire.  The same header may appear two or more times +/// in any container.  Searches using the simple find() +/// interface will find only the last occurrence (somewhat +/// simulates the use of std::map).  Fuller searches require +/// the use of an iterator.  Headers received from the wire +/// are only returned from the last request when redirections +/// are involved.  ///  /// Threading:  Not intrinsically thread-safe.  It *is* expected  /// that callers will build these objects and then share them @@ -64,6 +77,16 @@ namespace LLCore  class HttpHeaders : public LLCoreInt::RefCounted  {  public: +	typedef std::pair<std::string, std::string> header_t; +	typedef std::vector<header_t> container_t; +	typedef container_t::iterator iterator; +	typedef container_t::const_iterator const_iterator; +	typedef container_t::reverse_iterator reverse_iterator; +	typedef container_t::const_reverse_iterator const_reverse_iterator; +	typedef container_t::value_type value_type; +	typedef container_t::size_type size_type; + +public:  	/// @post In addition to the instance, caller has a refcount  	/// to the instance.  A call to @see release() will destroy  	/// the instance. @@ -76,7 +99,78 @@ protected:  	void operator=(const HttpHeaders &);		// Not defined  public: -	typedef std::vector<std::string> container_t; +	// Empty the list of headers. +	void clear(); + +	// Append a name/value pair supplied as either std::strings +	// or NUL-terminated char * to the header list.  No normalization +	// is performed on the strings.  No conformance test is +	// performed (names may contain spaces, colons, etc.). +	// +	void append(const std::string & name, const std::string & value); +	void append(const char * name, const char * value); + +	// Extract a name/value pair from a raw byte array using +	// the first colon character as a separator.  Input string +	// does not need to be NUL-terminated.  Resulting name/value +	// pair is appended to the header list. +	// +	// Normalization is performed on the name/value pair as +	// follows: +	// - name is lower-cased according to mostly ASCII rules +	// - name is left- and right-trimmed of spaces and tabs +	// - value is left-trimmed of spaces and tabs +	// - either or both of name and value may be zero-length +	// +	// By convention, headers read from the wire will be normalized +	// in this fashion prior to delivery to any HttpHandler code. +	// Headers to be written to the wire are left as appended to +	// the list. +	void appendNormal(const char * header, size_t size); + +	// Perform a simple, case-sensitive search of the header list +	// returning a pointer to the value of the last matching header +	// in the header list.  If none is found, a NULL pointer is returned. +	// +	// Any pointer returned references objects in the container itself +	// and will have the same lifetime as this class.  If you want +	// the value beyond the lifetime of this instance, make a copy. +	// +	// @arg		name	C-style string giving the name of a header +	//					to search.  The comparison is case-sensitive +	//					though list entries may have been normalized +	//					to lower-case. +	// +	// @return			NULL if the header wasn't found otherwise +	//					a pointer to a std::string in the container. +	//					Pointer is valid only for the lifetime of +	//					the container or until container is modifed. +	// +	const std::string * find(const char * name) const; + +	// Count of headers currently in the list. +	size_type size() const +		{ +			return mHeaders.size(); +		} + +	// Standard std::vector-based forward iterators. +	iterator begin(); +	const_iterator begin() const; +	iterator end(); +	const_iterator end() const; + +	// Standard std::vector-based reverse iterators. +	reverse_iterator rbegin(); +	const_reverse_iterator rbegin() const; +	reverse_iterator rend(); +	const_reverse_iterator rend() const; + +public: +	// For unit tests only - not a public API +	container_t &		getContainerTESTONLY(); +	 +protected:  	container_t			mHeaders;  }; // end class HttpHeaders diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp index ce0d19b058..668c36dc66 100755 --- a/indra/llcorehttp/tests/test_httpheaders.hpp +++ b/indra/llcorehttp/tests/test_httpheaders.hpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc.   *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -36,7 +36,6 @@  using namespace LLCoreInt; -  namespace tut  { @@ -63,7 +62,7 @@ void HttpHeadersTestObjectType::test<1>()  	HttpHeaders * headers = new HttpHeaders();  	ensure("One ref on construction of HttpHeaders", headers->getRefCount() == 1);  	ensure("Memory being used", mMemTotal < GetMemTotal()); -	ensure("Nothing in headers", 0 == headers->mHeaders.size()); +	ensure("Nothing in headers", 0 == headers->size());  	// release the implicit reference, causing the object to be released  	headers->release(); @@ -85,14 +84,340 @@ void HttpHeadersTestObjectType::test<2>()  	{  		// Append a few strings -		std::string str1("Pragma:"); -		headers->mHeaders.push_back(str1); -		std::string str2("Accept: application/json"); -		headers->mHeaders.push_back(str2); +		std::string str1n("Pragma"); +		std::string str1v(""); +		headers->append(str1n, str1v); +		std::string str2n("Accept"); +		std::string str2v("application/json"); +		headers->append(str2n, str2v); +	 +		ensure("Headers retained", 2 == headers->size()); +		HttpHeaders::container_t & c(headers->getContainerTESTONLY()); +		 +		ensure("First name is first name", c[0].first == str1n); +		ensure("First value is first value", c[0].second == str1v); +		ensure("Second name is second name", c[1].first == str2n); +		ensure("Second value is second value", c[1].second == str2v); +	} +	 +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +template <> template <> +void HttpHeadersTestObjectType::test<3>() +{ +	set_test_name("HttpHeaders basic find"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); +	 +	{ +		// Append a few strings +		std::string str1n("Uno"); +		std::string str1v("1"); +		headers->append(str1n, str1v); +		std::string str2n("doS"); +		std::string str2v("2-2-2-2"); +		headers->append(str2n, str2v); +		std::string str3n("TRES"); +		std::string str3v("trois gymnopedie"); +		headers->append(str3n, str3v); +	 +		ensure("Headers retained", 3 == headers->size()); + +		const std::string * result(NULL); + +		// Find a header +		result = headers->find("TRES"); +		ensure("Found the last item", result != NULL); +		ensure("Last item is a nice", result != NULL && str3v == *result); + +		// appends above are raw and find is case sensitive +		result = headers->find("TReS"); +		ensure("Last item not found due to case", result == NULL); + +		result = headers->find("TRE"); +		ensure("Last item not found due to prefixing (1)", result == NULL); + +		result = headers->find("TRESS"); +		ensure("Last item not found due to prefixing (2)", result == NULL); +	} +	 +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +template <> template <> +void HttpHeadersTestObjectType::test<4>() +{ +	set_test_name("HttpHeaders normalized header entry"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); +	 +	{ +		static char line1[] = " AcCePT : image/yourfacehere"; +		static char line1v[] = "image/yourfacehere"; +		headers->appendNormal(line1, sizeof(line1) - 1); +		 +		ensure("First append worked in some fashion", 1 == headers->size()); + +		const std::string * result(NULL); + +		// Find a header +		result = headers->find("accept"); +		ensure("Found 'accept'", result != NULL); +		ensure("accept value has face", result != NULL && *result == line1v); + +		// Left-clean on value +		static char line2[] = " next : \t\tlinejunk \t"; +		headers->appendNormal(line2, sizeof(line2) - 1); +		ensure("Second append worked", 2 == headers->size()); +		result = headers->find("next"); +		ensure("Found 'next'", result != NULL); +		ensure("next value is left-clean", result != NULL && +			   *result == "linejunk \t"); + +		// First value unmolested +		result = headers->find("accept"); +		ensure("Found 'accept' again", result != NULL); +		ensure("accept value has face", result != NULL && *result == line1v); + +		// Colons in value are okay +		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; +		static char line3v[] = ":plop:-neuf-=vleem="; +		headers->appendNormal(line3, sizeof(line3) - 1); +		ensure("Third append worked", 3 == headers->size()); +		result = headers->find("fancy-pants"); +		ensure("Found 'fancy-pants'", result != NULL); +		ensure("fancy-pants value has colons", result != NULL && *result == line3v); + +		// Zero-length value +		static char line4[] = "all-talk-no-walk:"; +		headers->appendNormal(line4, sizeof(line4) - 1); +		ensure("Fourth append worked", 4 == headers->size()); +		result = headers->find("all-talk-no-walk"); +		ensure("Found 'all-talk'", result != NULL); +		ensure("al-talk value is zero-length", result != NULL && result->size() == 0); + +		// Zero-length name +		static char line5[] = ":all-talk-no-walk"; +		static char line5v[] = "all-talk-no-walk"; +		headers->appendNormal(line5, sizeof(line5) - 1); +		ensure("Fifth append worked", 5 == headers->size()); +		result = headers->find(""); +		ensure("Found no-name", result != NULL); +		ensure("no-name value is something", result != NULL && *result == line5v); + +		// Lone colon is still something +		headers->clear(); +		static char line6[] = "  :"; +		headers->appendNormal(line6, sizeof(line6) - 1); +		ensure("Sixth append worked", 1 == headers->size()); +		result = headers->find(""); +		ensure("Found 2nd no-name", result != NULL); +		ensure("2nd no-name value is nothing", result != NULL && result->size() == 0); + +		// Line without colons is taken as-is and unstripped in name +		static char line7[] = " \toskdgioasdghaosdghoowg28342908tg8902hg0hwedfhqew890v7qh0wdebv78q0wdevbhq>?M>BNM<ZV>?NZ? \t"; +		headers->appendNormal(line7, sizeof(line7) - 1); +		ensure("Seventh append worked", 2 == headers->size()); +		result = headers->find(line7); +		ensure("Found whatsit line", result != NULL); +		ensure("Whatsit line has no value", result != NULL && result->size() == 0); + +		// Normaling interface heeds the byte count, doesn't look for NUL-terminator +		static char line8[] = "binary:ignorestuffontheendofthis"; +		headers->appendNormal(line8, 13); +		ensure("Eighth append worked", 3 == headers->size()); +		result = headers->find("binary"); +		ensure("Found 'binary'", result != NULL); +		ensure("binary value was limited to 'ignore'", result != NULL && +			   *result == "ignore"); + +	} -		ensure("Headers retained", 2 == headers->mHeaders.size()); -		ensure("First is first", headers->mHeaders[0] == str1); -		ensure("Second is second", headers->mHeaders[1] == str2); +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +// Verify forward iterator finds everything as expected +template <> template <> +void HttpHeadersTestObjectType::test<5>() +{ +	set_test_name("HttpHeaders iterator tests"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); + +	HttpHeaders::iterator end(headers->end()), begin(headers->begin()); +	ensure("Empty container has equal begin/end const iterators", end == begin); +	HttpHeaders::const_iterator cend(headers->end()), cbegin(headers->begin()); +	ensure("Empty container has equal rbegin/rend const iterators", cend == cbegin); + +	ensure("Empty container has equal begin/end iterators", headers->end() == headers->begin()); +	 +	{ +		static char line1[] = " AcCePT : image/yourfacehere"; +		static char line1v[] = "image/yourfacehere"; +		headers->appendNormal(line1, sizeof(line1) - 1); + +		static char line2[] = " next : \t\tlinejunk \t"; +		static char line2v[] = "linejunk \t"; +		headers->appendNormal(line2, sizeof(line2) - 1); + +		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; +		static char line3v[] = ":plop:-neuf-=vleem="; +		headers->appendNormal(line3, sizeof(line3) - 1); + +		static char line4[] = "all-talk-no-walk:"; +		static char line4v[] = ""; +		headers->appendNormal(line4, sizeof(line4) - 1); + +		static char line5[] = ":all-talk-no-walk"; +		static char line5v[] = "all-talk-no-walk"; +		headers->appendNormal(line5, sizeof(line5) - 1); + +		static char line6[] = "  :"; +		static char line6v[] = ""; +		headers->appendNormal(line6, sizeof(line6) - 1); + +		ensure("All entries accounted for", 6 == headers->size()); + +		static char * values[] = { +			line1v, +			line2v, +			line3v, +			line4v, +			line5v, +			line6v +		}; +			 +		int i(0); +		HttpHeaders::const_iterator cend(headers->end()); +		for (HttpHeaders::const_iterator it(headers->begin()); +			 cend != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Const Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		} + +		// Rewind, do non-consts +		i = 0; +		HttpHeaders::iterator end(headers->end()); +		for (HttpHeaders::iterator it(headers->begin()); +			 end != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Const Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		} +	} +	 +	// release the implicit reference, causing the object to be released +	headers->release(); + +	// make sure we didn't leak any memory +	ensure(mMemTotal == GetMemTotal()); +} + +// Reverse iterators find everything as expected +template <> template <> +void HttpHeadersTestObjectType::test<6>() +{ +	set_test_name("HttpHeaders reverse iterator tests"); + +	// record the total amount of dynamically allocated memory +	mMemTotal = GetMemTotal(); + +	// create a new ref counted object with an implicit reference +	HttpHeaders * headers = new HttpHeaders(); + +	HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin()); +	ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin); +	HttpHeaders::const_reverse_iterator crend(headers->rend()), crbegin(headers->rbegin()); +	ensure("Empty container has equal rbegin/rend const iterators", crend == crbegin); +	 +	{ +		static char line1[] = " AcCePT : image/yourfacehere"; +		static char line1v[] = "image/yourfacehere"; +		headers->appendNormal(line1, sizeof(line1) - 1); + +		static char line2[] = " next : \t\tlinejunk \t"; +		static char line2v[] = "linejunk \t"; +		headers->appendNormal(line2, sizeof(line2) - 1); + +		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem="; +		static char line3v[] = ":plop:-neuf-=vleem="; +		headers->appendNormal(line3, sizeof(line3) - 1); + +		static char line4[] = "all-talk-no-walk:"; +		static char line4v[] = ""; +		headers->appendNormal(line4, sizeof(line4) - 1); + +		static char line5[] = ":all-talk-no-walk"; +		static char line5v[] = "all-talk-no-walk"; +		headers->appendNormal(line5, sizeof(line5) - 1); + +		static char line6[] = "  :"; +		static char line6v[] = ""; +		headers->appendNormal(line6, sizeof(line6) - 1); + +		ensure("All entries accounted for", 6 == headers->size()); + +		static char * values[] = { +			line6v, +			line5v, +			line4v, +			line3v, +			line2v, +			line1v +		}; +			 +		int i(0); +		HttpHeaders::const_reverse_iterator cend(headers->rend()); +		for (HttpHeaders::const_reverse_iterator it(headers->rbegin()); +			 cend != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Const Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		} + +		// Rewind, do non-consts +		i = 0; +		HttpHeaders::reverse_iterator end(headers->rend()); +		for (HttpHeaders::reverse_iterator it(headers->rbegin()); +			 end != it; +			 ++it, ++i) +		{ +			std::ostringstream str; +			str << "Iterator value # " << i << " was " << values[i]; +			ensure(str.str(), (*it).second == values[i]); +		}  	}  	// release the implicit reference, causing the object to be released diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index e5488cf941..27d65f171e 100755 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -4,7 +4,7 @@   *   * $LicenseInfo:firstyear=2012&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, Linden Research, Inc.   *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -60,6 +60,8 @@ void usleep(unsigned long usec);  namespace tut  { +typedef std::vector<std::pair<boost::regex, boost::regex> > regex_container_t; +  struct HttpRequestTestData  {  	// the test objects inherit from this so the member functions and variables @@ -109,11 +111,17 @@ public:  					for (int i(0); i < mHeadersRequired.size(); ++i)  					{  						bool found = false; -						for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin()); -							 header->mHeaders.end() != iter; +						for (HttpHeaders::const_iterator iter(header->begin()); +							 header->end() != iter;  							 ++iter)  						{ -							if (boost::regex_match(*iter, mHeadersRequired[i])) +							// std::cerr << "Header: " << (*iter).first +							//		  << ": " << (*iter).second << std::endl; +							 +							if (boost::regex_match((*iter).first, +												   mHeadersRequired[i].first) && +								boost::regex_match((*iter).second, +												   mHeadersRequired[i].second))  							{  								found = true;  								break; @@ -129,11 +137,14 @@ public:  				{  					for (int i(0); i < mHeadersDisallowed.size(); ++i)  					{ -						for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin()); -							 header->mHeaders.end() != iter; +						for (HttpHeaders::const_iterator iter(header->begin()); +							 header->end() != iter;  							 ++iter)  						{ -							if (boost::regex_match(*iter, mHeadersDisallowed[i])) +							if (boost::regex_match((*iter).first, +												   mHeadersDisallowed[i].first) && +								boost::regex_match((*iter).second, +												   mHeadersDisallowed[i].second))  							{  								std::ostringstream str;  								str << "Disallowed header # " << i << " not found in response"; @@ -159,8 +170,8 @@ public:  	std::string mName;  	HttpHandle mExpectHandle;  	std::string mCheckContentType; -	std::vector<boost::regex> mHeadersRequired; -	std::vector<boost::regex> mHeadersDisallowed; +	regex_container_t mHeadersRequired; +	regex_container_t mHeadersDisallowed;  };  typedef test_group<HttpRequestTestData> HttpRequestTestGroupType; @@ -1335,7 +1346,9 @@ void HttpRequestTestObjectType::test<13>()  		// Issue a GET that succeeds  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("\\W*X-LL-Special:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase), +										  boost::regex(".*", boost::regex::icase)));  		HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,  													 0U,  													 url_base, @@ -1702,18 +1715,54 @@ void HttpRequestTestObjectType::test<16>()  		// Issue a GET that *can* connect  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase)));  		HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -1735,23 +1784,60 @@ void HttpRequestTestObjectType::test<16>()  		// Do a texture-style fetch  		headers = new HttpHeaders; -		headers->mHeaders.push_back("Accept: image/x-j2c"); +		headers->append("Accept", "image/x-j2c");  		mStatus = HttpStatus(200);  		handler.mHeadersRequired.clear();  		handler.mHeadersDisallowed.clear(); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*image/x-j2c", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("\\W*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("image/x-j2c", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("\\W*X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase)));  		handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,  										  0U,  										  url_base + "reflect/", @@ -1892,20 +1978,63 @@ void HttpRequestTestObjectType::test<17>()  		// Issue a default POST  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer_encoding", boost::regex::icase), +				boost::regex(".*chunked.*", boost::regex::icase)));  		HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,  											 0U,  											 url_base + "reflect/", @@ -2052,20 +2181,64 @@ void HttpRequestTestObjectType::test<18>()  		// Issue a default PUT  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*chunked.*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +  		HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -2206,27 +2379,73 @@ void HttpRequestTestObjectType::test<19>()  		// headers  		headers = new HttpHeaders; -		headers->mHeaders.push_back("Keep-Alive: 120"); -		headers->mHeaders.push_back("Accept-encoding: deflate"); -		headers->mHeaders.push_back("Accept: text/plain"); +		headers->append("Keep-Alive", "120"); +		headers->append("Accept-encoding", "deflate"); +		headers->append("Accept", "text/plain");  		// Issue a GET with modified headers  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/plain", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*deflate", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("text/plain", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("deflate", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("120", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("300", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase)));  		HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", @@ -2359,10 +2578,10 @@ void HttpRequestTestObjectType::test<20>()  		// headers  		headers = new HttpHeaders(); -		headers->mHeaders.push_back("keep-Alive: 120"); -		headers->mHeaders.push_back("Accept:  text/html"); -		headers->mHeaders.push_back("content-type:  application/llsd+xml"); -		headers->mHeaders.push_back("cache-control: no-store"); +		headers->append("keep-Alive", "120"); +		headers->append("Accept", "text/html"); +		headers->append("content-type", "application/llsd+xml"); +		headers->append("cache-control", "no-store");  		// And a buffer array  		const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); @@ -2371,23 +2590,76 @@ void HttpRequestTestObjectType::test<20>()  		// Issue a default POST  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/html", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("\\s*X-Reflect-cache-control:\\s*no-store", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("text/html", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("120", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/llsd\\+xml", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex("no-store", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/x-www-form-urlencoded", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("300", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +  		HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,  											 0U,  											 url_base + "reflect/", @@ -2529,9 +2801,9 @@ void HttpRequestTestObjectType::test<21>()  		// headers  		headers = new HttpHeaders; -		headers->mHeaders.push_back("content-type:  text/plain"); -		headers->mHeaders.push_back("content-type:  text/html"); -		headers->mHeaders.push_back("content-type:  application/llsd+xml"); +		headers->append("content-type", "text/plain"); +		headers->append("content-type", "text/html"); +		headers->append("content-type", "application/llsd+xml");  		// And a buffer array  		const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>"); @@ -2540,22 +2812,71 @@ void HttpRequestTestObjectType::test<21>()  		// Issue a default PUT  		mStatus = HttpStatus(200); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase)); -		handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/plain", boost::regex::icase)); -		handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/html", boost::regex::icase)); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-connection", boost::regex::icase), +				boost::regex("keep-alive", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept", boost::regex::icase), +				boost::regex("\\*/\\*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-accept-encoding", boost::regex::icase), +				boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-keep-alive", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-host", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-length", boost::regex::icase), +				boost::regex("\\d+", boost::regex::icase))); +		handler.mHeadersRequired.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("application/llsd\\+xml", boost::regex::icase))); + +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-cache-control", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-pragma", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-range", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-referer", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-expect", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-transfer-encoding", boost::regex::icase), +				boost::regex(".*", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("text/plain", boost::regex::icase))); +		handler.mHeadersDisallowed.push_back( +			regex_container_t::value_type( +				boost::regex("X-Reflect-content-type", boost::regex::icase), +				boost::regex("text/html", boost::regex::icase)));  		HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,  											0U,  											url_base + "reflect/", diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index fb2d43e3b0..b86e73c690 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 41d58c6deb..6336d02f22 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 99716ed7be..b718f0f9b7 100755 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -86,22 +86,19 @@ public:  	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 @@ public:  	//--------------------------------------------------------------------  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 @@ public:  	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 1a90c32fe4..6fa2669be6 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 9a68093427..e0b71acbd5 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 @@ public:  		}  		// 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 @@ public:                                   << 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 2a8eb46187..1f50c48961 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 47041a2880..68282626ae 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 7bcf61e233..8a65c783be 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 @@ public:  		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 @@ public:  	// 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 @@ public:  	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 7dcf160c9b..e841c8e3ed 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 3561459bb4..53cef54559 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 @@ public:  		return content;  	} -	std::string asString() +	const std::string& asString()  	{  		return mBuffer;  	} @@ -430,7 +426,7 @@ private:    */  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 a7236ba169..4e7495495f 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -74,6 +74,14 @@ public:  		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 0b59209af1..b56a804f94 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 aae6426a59..270282c66f 100755 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -37,6 +37,14 @@ public:  	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 0000000000..016f1f1970 --- /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 0000000000..aa947af414 --- /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 5c2f73eccb..5058fdaf51 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 148647ddde..1144d88be1 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 @@ public:  		/**  		 * @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 @@ public:  		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 @@ public:  			 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 @@ public:  	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 1236fc8b71..293e74d0da 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 @@ private:  		// 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 @@ private:  		STATE_LOCKED,  		STATE_GOOD_RESULT,  		STATE_STATUS_RESULT, -		STATE_EXTENDED_RESULT +		STATE_EXTENDED_RESULT, +		STATE_EXTENDED_LLSD_RESULT  	};  	State mState; @@ -132,7 +125,7 @@ private:  	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 5c1b0531ff..a23eafe58a 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 2043bae5e7..a60b840067 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 be0f7dfcc6..08c21a1b97 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 9d9c4ebd68..0000000000 --- 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 e6617fb503..0000000000 --- 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 932cbf375e..0000000000 --- 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 5e8251e519..0000000000 --- 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 8bab91b0c0..c593027802 100755 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -121,7 +121,7 @@ public:  	{  		//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 @@ public:  		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 @@ public:  		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 @@ public:  		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 @@ public:  		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 5c8fc7b2bb..8ac6b3cb12 100755 --- a/indra/llmessage/llsdhttpserver.cpp +++ b/indra/llmessage/llsdhttpserver.cpp @@ -109,7 +109,7 @@ public:      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 1c93c12d99..376f69ea36 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 0d34847ff2..e5d532d6a4 100755 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -123,6 +123,7 @@ private:      /// 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 @@ private:              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 0cecf4f688..dfd3b7e1d0 100755 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -240,7 +240,7 @@ public:  	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 @@ public:  		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 @@ public:  	{  		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 @@ public:  		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 fea7fc72c4..a67ba35879 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 688937ac2c..12a37bb535 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 627d591839..cadff49cb8 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 44d358d906..f3d32f5419 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 @@ public:  	 *   	 */  	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 @@ protected:  		STATE_HAVE_RESPONSE,  	};  	EState mState; -	ERequestAction mAction; +	EHTTPMethod mAction;  	LLURLRequestDetail* mDetail;  	LLIOPipe::ptr_t mCompletionCallback;  	 S32 mRequestTransferedBytes; @@ -315,7 +296,7 @@ public:  	// 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 @@ protected:  	//@}  	// 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 ae95087377..5a63da628d 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 9b298d0c04..b7fdf4f437 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 87cbafa404..43fac83c57 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 13ce0a0edd..cc7feeab4f 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 0000000000..cc2108fed5 --- /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 aed5c4589c..0000000000 --- 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 5b89f2a8c6..0000000000 --- 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 b287a29841..55748ad27e 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 6c798aa4ed..1b1799aaa2 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 09e27a264a..0807b497a7 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 4dba1e645f..1d0d3cb050 100755 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -305,7 +305,7 @@ public:  	/*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 227644f14f..d35180afc9 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 92a241857e..6594fdb249 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 f356cff9d8..bb12cd59bc 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 7662a9689d..55d453cdcc 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 @@ public:  		}  	} -	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 0bca1f54ef..3ade34c81d 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -38,7 +38,7 @@ public:  	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 8c42defa73..21625815b9 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 index c88694ef76..80c8364223 100755..100644 --- 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 5be4648636..0adf545aab 100755 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -77,6 +77,7 @@ public:  	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 @@ private:  	 * 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 0000000000..21f6482a06 --- /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 0000000000..1f9555f004 --- /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 652f199e28..f5f6faf6b6 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 @@ public:  		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 @@ public:  			);  		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 @@ public:  	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 @@ public:  		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 @@ private:  // 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 @@ public:  		}  	}	 -	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 @@ public:  				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 @@ public:  		{  			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 @@ public:  	{  	} -	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 @@ public:  		}  	} +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 46252afbde..9eb26767c4 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 @@ public:  								   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 @@ public:  	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 @@ public:  				 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 @@ public:  	//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 @@ public:  	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 @@ private:  	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 @@ public:  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 4bdb690225..cde9bc9dc0 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 @@ public:  		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 2564802387..ea511b18e2 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 a6d1016136..abfdc4ca77 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 @@ public:  							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 @@ protected:  // TODO*: Remove this once deprecated  class LLNewAgentInventoryResponder : public LLAssetUploadResponder  { +	LOG_CLASS(LLNewAgentInventoryResponder);  public:  	LLNewAgentInventoryResponder(  		const LLSD& post_data, @@ -67,9 +73,10 @@ public:  		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 @@ public:  class LLNewAgentInventoryVariablePriceResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLNewAgentInventoryVariablePriceResponder);  public:  	LLNewAgentInventoryVariablePriceResponder(  		const LLUUID& vfile_id, @@ -91,12 +99,11 @@ public:  		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 @@ public:  	~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 e3cd83e174..923662e887 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 06dcb62fd0..efa4d82411 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 2669b0340f..db2c15a444 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 e0f7223a8c..c3b53d5e4a 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 ddb9d3bc43..691a24e2df 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 @@ public:  	} -	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 @@ public:  				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 d13f85baa2..89d74666f7 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 83fb887d81..801a24f472 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 113aa9a8f2..0844a70e25 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 @@ public:  		// 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 013cf74c7b..6e641e7d40 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 56051ff684..af5c11e12c 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 4cb632bd6a..c0bb213540 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 8ec85e1160..7b72c1e930 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 100f1d580b..5830156fdd 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 e588418f7b..6c0c60b87f 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -200,11 +200,11 @@ public:  	/*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 6d3800bfa4..9f1fc06e14 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 a52bc28687..d9a8879687 100755 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -37,13 +37,13 @@ public:  	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 0862cd2897..c11a0568a6 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 9a244573be..1a2c317bad 100755 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -63,7 +63,7 @@ public:  	/*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 3a7ca17b73..efc04ac358 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 50c013a49d..ddfae005bb 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 @@ public:  // 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 @@ public:  	}  	// 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 35b63c5480..cc4199a758 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -707,16 +707,18 @@ public:  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 13cb3c2eb0..11a0d3ebe4 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 f8732ef94b..a5cb1b6184 100755 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -85,49 +85,49 @@ protected:  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 @@ protected:  // 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 2a946b1edf..a446b767ac 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 a242b224cd..0613ffc94d 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 e85d849c9a..e26f1e9ea5 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 dfb49fe5ac..bdd1ebe592 100755 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -40,7 +40,7 @@ public:  	// 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 3fe2518de6..21b171446f 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 5c6ce9d311..0ce0534802 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 9aa86297fc..5eaa83d872 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 cbd844cdac..472e3862ea 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 37428c4a44..b1286cccf2 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 9bf4b12c4e..adc6c8cb58 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 0000000000..1512b46103 --- /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 0000000000..5b1a1d79e0 --- /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 59272d721f..8a02dde88c 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 2c20409381..aed0414c50 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 @@ public:  		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 @@ public:  				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 @@ public:  		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 @@ public:  		}  	} -	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 9c6db3676f..6ff16742dd 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 a5043a30ac..89c56ab82c 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 517153e171..2a937b574d 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -248,7 +248,7 @@ public:  	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 @@ public:  	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 f1a4889f5a..faa5d70952 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 f1066a4dc9..6b3861aa79 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -186,6 +186,13 @@ protected:  	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 935fe2b4d0..aadf87ab35 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 @@ public:  	{  	} -	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 8aac879a93..5de951ed05 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -81,11 +81,12 @@ public:  	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 @@ public:  		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 @@ public:  							  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 @@ public:  	// 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 @@ public:  	// 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 @@ public:  	/// 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 @@ private:  	//--------------------------------------------------------------------  public:  	void dumpInventory() const; +	bool validate() const;  /**                    Miscellaneous   **                                                                            ** diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index f2b39e7186..864f38cbde 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 @@ private:  };  // 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 0b009b68f7..28e1df725a 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 2075aeed63..cb5640b4da 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 e3b46d5d2f..691be13610 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 89e20a28d0..231b883c32 100755 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -74,8 +74,9 @@ public:  // 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 @@ protected:  	// 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 @@ private:  // 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 @@ protected:      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 @@ private:  // 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 @@ protected:      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 b47fe9d4b1..95289f7167 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 @@ public:  		}  	} -	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 @@ public:  		}  	} -	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 @@ public:  		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 @@ public:  		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 @@ public:  		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 @@ public:  		}  	} -	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 @@ public:  		}  		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 @@ public:  class LLWholeModelUploadResponder: public LLCurl::Responder  { +	LOG_CLASS(LLWholeModelUploadResponder);  	LLMeshUploadThread* mThread;  	LLSD mModelData;  	LLHandle<LLWholeModelUploadObserver> mObserverHandle; @@ -487,11 +489,10 @@ public:  		}  	} -	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 @@ public:  		// 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 @@ public:  		}  		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 862e4be203..4f5e07c566 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 e71dba5cae..580e31591c 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 88400e4ef2..d1a18fdc8c 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 8fae0f0b67..a39338304c 100755 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -106,7 +106,7 @@ protected:  	//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 bcb90bcb56..c4ba097914 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 c09d4393c8..0e3057dcad 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 f90236f6f2..d6c927ab58 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 3c1f14759c..7a8bd66fcf 100755 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -86,7 +86,7 @@ public:  	//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 4ae0c0eb12..4e7c5f6ed2 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 64f0b6b550..30327378ef 100755 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -86,7 +86,7 @@ public:  	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 6c2a01fc82..730df2ea23 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -217,7 +217,7 @@ public:  			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 c277359133..a9c755de35 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 @@ private:  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 @@ private:  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 @@ private:  //---------------------------------------------------------------------------  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 @@ public:  	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 @@ private:  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 @@ private:  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 0c23e5ac92..555105cf40 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 b872ccad7c..87f32b8d56 100755 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -74,7 +74,7 @@ public:  	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 04934b13f1..452efad291 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 1390000fc5..94a6389f8a 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 500dec7ee5..7418bbf615 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 b87056573b..0f8ae41d76 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 @@ public:  	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 74fa5a87bb..e082859767 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 a4582071e8..bf209df863 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 82596a86b9..8890df199b 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 be5fde9e2b..70e2c0f2dc 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 @@ public:  	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 @@ private:  	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 902a3d7a25..237912cde7 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 @@ public:  	// 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 @@ private:  	// 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 @@ private:  	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 148e5a015b..fa94b52362 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 f3d8de1904..ae934d9f5a 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 db5ad9479c..972274714a 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -95,9 +95,6 @@ public:  	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 1d777b3f7f..88c48ba0a3 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 b43ddb44d9..4ff4a827a5 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 @@ public:  	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 @@ public:  	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 @@ protected:  }; -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 f81206ffec..3f836efdd3 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 @@ public:  		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 @@ public:  		// 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 fff9821e86..55575764b9 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 @@ public:  };  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 61b1b8d846..032efd9542 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -118,12 +118,11 @@ public:  	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 @@ public:  	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 @@ public:  	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 2df028de69..2cec808f19 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 @@ public:  		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 @@ public:  //			)  		// 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 @@ public:  		}  	} +public:  	void cancelRequest()  	{  		disconnectOwner(); @@ -269,7 +271,7 @@ public:  class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder  { -LOG_CLASS(LLViewerMediaOpenIDResponder); +	LOG_CLASS(LLViewerMediaOpenIDResponder);  public:  	LLViewerMediaOpenIDResponder( )  	{ @@ -279,23 +281,17 @@ public:  	{  	} -	/* 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 @@ public:  	{  	} -	/* 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 @@ public:  		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 ace16396db..751a9456c9 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 064e96e394..63de1ab77a 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 316dbce7d0..0390cbc5b0 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -394,6 +394,7 @@ public:  	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 caacf26cb3..ee970ceb5f 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 @@ public:  		}  	} -	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 @@ private:  class LLPhysicsFlagsResponder : public LLCurl::Responder  { +	LOG_CLASS(LLPhysicsFlagsResponder);  public:  	LLPhysicsFlagsResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -780,20 +781,19 @@ public:  		}  	} -	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 386b2fd400..d7e14ac6f5 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 48c050f403..dca1a5b542 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 @@ public:  			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 @@ public:  		}  	} -    static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) -    { -		return new BaseCapabilitiesComplete(region_handle, id); -    } -  private:  	U64 mRegionHandle;  	S32 mID; @@ -278,19 +287,32 @@ public:  	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 @@ public:  		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 @@ private:  			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 35bba4184e..68633fba6e 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 6b2461be41..eaa0b6beff 100755 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -279,7 +279,7 @@ public:  	// 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 @@ public:  		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 index 777e1f9c76..777e1f9c76 100755..100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index eb6c453e76..4c9ca8b1d7 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 f2e1a90713..e99d52741d 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 @@ public:  	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 @@ public:  	// 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 @@ protected:  	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 65566f23a5..047b2ce143 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -68,6 +68,8 @@ public:  	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 @@ protected:  	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 fe4d5b3e4d..f95cc9e572 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 06fb23b84b..46b909c4a1 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 85f6f25009..fad2fd962c 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -212,6 +212,9 @@ public:  	/*virtual*/ LLVector3		getPosAgentFromGlobal(const LLVector3d &position);  	virtual void			updateVisualParams(); +	/*virtual*/ void		computeBodySize(); + +  /**                    Inherited   **                                                                            ** @@ -991,10 +994,11 @@ protected: // Shared with LLVOAvatarSelf  }; // 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 d54eb5f040..232bf3e478 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 @@ public:  	{  	} -	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 @@ public:  	{  	} -	/* 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 3b7b6bac64..e8b9a25327 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -138,6 +138,7 @@ public:  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 ac2a34ba1e..397c5cd81f 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 9b5d981aa5..838845df80 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 @@ public:  		}  	} -	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 @@ public:  			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 8730ef66bb..b7f7a11a15 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 641f338f2c..567138e160 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -67,9 +67,8 @@ public:  	{  	} +	// *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 @@ public:  		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 3a80051b9b..7036162014 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 @@ public:  ///////////////////////////////////////////////////////////////////////////////  // -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 @@ public:  		}  		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 @@ public:  ///////////////////////////////////////////////////////////////////////////////  // -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 @@ public:  		}  		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 93eba5b604..3bedfbe502 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 598ce6d52a..089c799da7 100755 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -45,9 +45,9 @@ private:  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 @@ private:  class LLEnvironmentApplyResponder: public LLHTTPClient::Responder  {  	LOG_CLASS(LLEnvironmentApplyResponder); -public: +private:  	/*  	 * Expecting reply from sim in form of:  	 * { @@ -87,10 +87,10 @@ public:  	 *   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 793becf0c8..d9da639af9 100755 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1065,6 +1065,8 @@ public:  					<< 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 0da70d398b..7c5f8be1b5 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 970a11c6c4..c3d8a528c5 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 0000000000..25e6de46d9 --- /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 41cb344808..01195d1269 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 ed66066b0a..c49b0350e9 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 fd9527d631..b28eb5db43 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 ec952e0058..25efe63d3f 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 2573cab81f..20e7960829 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 216c59d766..c528a34129 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 f928a1bad0..03df1d339b 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, @@ -757,42 +769,6 @@ namespace tut  		{  			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); -  			//U32 start_llsd_count = LLSD::outstandingCount();  			LLSD m = LLSD::emptyMap(); @@ -852,3 +828,4 @@ namespace tut  		test serializations  	*/  } + diff --git a/indra/test/llsdtraits.h b/indra/test/llsdtraits.h index 8144aaee94..07f6193ce2 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 55d84bcaca..243e869be7 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 d971b33475..0dae5178be 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 d7ef407d52..e72902bfc2 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 7668a43fdf..a2b9b435fb 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 1e768f52d9..cdb9b45682 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 8e85587490..2624869e61 100755 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -53,11 +53,10 @@ public:  						  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;  | 
