summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xautobuild.xml4
-rwxr-xr-xindra/cmake/BuildVersion.cmake5
-rwxr-xr-xindra/edit-me-to-trigger-new-build.txt6
-rw-r--r--indra/llappearance/llavatarappearance.cpp19
-rw-r--r--indra/llappearance/llavatarappearance.h2
-rwxr-xr-xindra/llcommon/CMakeLists.txt1
-rwxr-xr-xindra/llcommon/llhttpstatuscodes.h89
-rwxr-xr-xindra/llcommon/llsd.cpp11
-rwxr-xr-xindra/llcommon/llsd.h5
-rwxr-xr-xindra/llcommon/llsdserialize.cpp65
-rwxr-xr-xindra/llcommon/llsdserialize.h28
-rwxr-xr-xindra/llcommon/llsdserialize_xml.cpp15
-rwxr-xr-xindra/llcorehttp/_httplibcurl.cpp19
-rwxr-xr-xindra/llcorehttp/_httpoprequest.cpp17
-rwxr-xr-xindra/llcorehttp/examples/http_texture_load.cpp4
-rwxr-xr-xindra/llcorehttp/httpheaders.cpp141
-rwxr-xr-xindra/llcorehttp/httpheaders.h112
-rwxr-xr-xindra/llcorehttp/tests/test_httpheaders.hpp345
-rwxr-xr-xindra/llcorehttp/tests/test_httprequest.hpp563
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.cpp9
-rwxr-xr-xindra/llinventory/llinventory.cpp7
-rwxr-xr-xindra/llinventory/llinventory.h1
-rwxr-xr-xindra/llmessage/CMakeLists.txt11
-rwxr-xr-xindra/llmessage/llavatarnamecache.cpp49
-rwxr-xr-xindra/llmessage/llavatarnamecache.h2
-rwxr-xr-xindra/llmessage/llcurl.cpp210
-rwxr-xr-xindra/llmessage/llcurl.h112
-rwxr-xr-xindra/llmessage/llhttpassetstorage.cpp21
-rwxr-xr-xindra/llmessage/llhttpclient.cpp162
-rwxr-xr-xindra/llmessage/llhttpclientadapter.cpp23
-rwxr-xr-xindra/llmessage/llhttpclientadapter.h8
-rwxr-xr-xindra/llmessage/llhttpconstants.cpp224
-rw-r--r--indra/llmessage/llhttpconstants.h229
-rwxr-xr-xindra/llmessage/llhttpnode.cpp33
-rwxr-xr-xindra/llmessage/llhttpnode.h30
-rwxr-xr-xindra/llmessage/lliohttpserver.cpp86
-rwxr-xr-xindra/llmessage/lliohttpserver.h12
-rwxr-xr-xindra/llmessage/lliosocket.cpp7
-rwxr-xr-xindra/llmessage/lliosocket.h3
-rwxr-xr-xindra/llmessage/llmime.cpp629
-rwxr-xr-xindra/llmessage/llmime.h292
-rwxr-xr-xindra/llmessage/llregionpresenceverifier.cpp153
-rwxr-xr-xindra/llmessage/llregionpresenceverifier.h98
-rwxr-xr-xindra/llmessage/llsdappservices.cpp10
-rwxr-xr-xindra/llmessage/llsdhttpserver.cpp2
-rwxr-xr-xindra/llmessage/llsdmessage.cpp21
-rwxr-xr-xindra/llmessage/llsdmessage.h6
-rwxr-xr-xindra/llmessage/llsdrpcclient.h8
-rwxr-xr-xindra/llmessage/lltrustedmessageservice.cpp8
-rwxr-xr-xindra/llmessage/lltrustedmessageservice.h4
-rwxr-xr-xindra/llmessage/llurlrequest.cpp48
-rwxr-xr-xindra/llmessage/llurlrequest.h54
-rwxr-xr-xindra/llmessage/message.cpp14
-rwxr-xr-xindra/llmessage/tests/llcurl_stub.cpp59
-rwxr-xr-xindra/llmessage/tests/llhttpclient_test.cpp33
-rwxr-xr-xindra/llmessage/tests/llhttpclientadapter_test.cpp81
-rw-r--r--indra/llmessage/tests/llhttpnode_stub.cpp112
-rwxr-xr-xindra/llmessage/tests/llmime_test.cpp445
-rwxr-xr-xindra/llmessage/tests/llregionpresenceverifier_test.cpp108
-rwxr-xr-xindra/llmessage/tests/lltrustedmessageservice_test.cpp1
-rwxr-xr-xindra/llrender/llgl.cpp1
-rwxr-xr-xindra/llui/llfloater.cpp31
-rwxr-xr-xindra/llui/llfloater.h3
-rwxr-xr-xindra/llui/llpanel.cpp22
-rwxr-xr-xindra/llui/llpanel.h10
-rwxr-xr-xindra/newview/CMakeLists.txt18
-rwxr-xr-xindra/newview/app_settings/logcontrol.xml1
-rwxr-xr-xindra/newview/app_settings/settings.xml11
-rwxr-xr-xindra/newview/llaccountingcostmanager.cpp14
-rwxr-xr-xindra/newview/llaccountingcostmanager.h2
-rwxr-xr-xindra/newview/llagent.cpp54
-rw-r--r--[-rwxr-xr-x]indra/newview/llagentwearables.cpp9
-rwxr-xr-xindra/newview/llappearancemgr.cpp649
-rwxr-xr-xindra/newview/llappearancemgr.h50
-rwxr-xr-xindra/newview/llassetuploadqueue.cpp83
-rwxr-xr-xindra/newview/llassetuploadresponders.cpp81
-rwxr-xr-xindra/newview/llassetuploadresponders.h28
-rwxr-xr-xindra/newview/llclassifiedstatsresponder.cpp13
-rwxr-xr-xindra/newview/llclassifiedstatsresponder.h8
-rwxr-xr-xindra/newview/llestateinfomodel.cpp10
-rwxr-xr-xindra/newview/lleventpoll.cpp45
-rwxr-xr-xindra/newview/llfeaturemanager.cpp20
-rwxr-xr-xindra/newview/llfilepicker.cpp13
-rwxr-xr-xindra/newview/llfloaterabout.cpp39
-rwxr-xr-xindra/newview/llfloateravatarpicker.cpp11
-rwxr-xr-xindra/newview/llfloaterbuycurrencyhtml.cpp3
-rwxr-xr-xindra/newview/llfloatergesture.cpp3
-rwxr-xr-xindra/newview/llfloaterhelpbrowser.cpp6
-rwxr-xr-xindra/newview/llfloaterimsession.cpp7
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp4
-rwxr-xr-xindra/newview/llfloatermodelpreview.h4
-rwxr-xr-xindra/newview/llfloatermodeluploadbase.cpp2
-rwxr-xr-xindra/newview/llfloatermodeluploadbase.h4
-rwxr-xr-xindra/newview/llfloaterobjectweights.cpp2
-rwxr-xr-xindra/newview/llfloaterobjectweights.h2
-rwxr-xr-xindra/newview/llfloaterregiondebugconsole.cpp16
-rwxr-xr-xindra/newview/llfloaterregioninfo.cpp25
-rwxr-xr-xindra/newview/llfloaterreporter.cpp14
-rwxr-xr-xindra/newview/llfloaterscriptlimits.cpp63
-rwxr-xr-xindra/newview/llfloaterscriptlimits.h62
-rwxr-xr-xindra/newview/llfloatersearch.cpp3
-rwxr-xr-xindra/newview/llfloatersidepanelcontainer.cpp80
-rwxr-xr-xindra/newview/llfloatersidepanelcontainer.h10
-rwxr-xr-xindra/newview/llfloatertos.cpp68
-rwxr-xr-xindra/newview/llfloaterurlentry.cpp47
-rwxr-xr-xindra/newview/llfloaterurlentry.h2
-rwxr-xr-xindra/newview/llfloaterwebcontent.cpp7
-rwxr-xr-xindra/newview/llgesturemgr.cpp13
-rwxr-xr-xindra/newview/llgroupmgr.cpp26
-rwxr-xr-xindra/newview/llhomelocationresponder.cpp35
-rwxr-xr-xindra/newview/llhomelocationresponder.h6
-rwxr-xr-xindra/newview/llhttpretrypolicy.cpp137
-rwxr-xr-xindra/newview/llhttpretrypolicy.h94
-rwxr-xr-xindra/newview/llimpanel.cpp7
-rwxr-xr-xindra/newview/llimview.cpp30
-rwxr-xr-xindra/newview/llinspectavatar.cpp6
-rwxr-xr-xindra/newview/llinventorybridge.cpp73
-rwxr-xr-xindra/newview/llinventorybridge.h4
-rwxr-xr-xindra/newview/llinventorymodel.cpp795
-rwxr-xr-xindra/newview/llinventorymodel.h39
-rwxr-xr-xindra/newview/llinventorymodelbackgroundfetch.cpp98
-rwxr-xr-xindra/newview/llmarketplacefunctions.cpp62
-rwxr-xr-xindra/newview/llmediactrl.cpp5
-rwxr-xr-xindra/newview/llmediadataclient.cpp52
-rwxr-xr-xindra/newview/llmediadataclient.h29
-rwxr-xr-xindra/newview/llmeshrepository.cpp140
-rwxr-xr-xindra/newview/llpanelclassified.cpp10
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp23
-rwxr-xr-xindra/newview/llpanellandmarks.cpp2
-rwxr-xr-xindra/newview/llpanellandmarks.h2
-rwxr-xr-xindra/newview/llpanellogin.cpp4
-rwxr-xr-xindra/newview/llpaneloutfitedit.cpp4
-rwxr-xr-xindra/newview/llpaneloutfitsinventory.cpp3
-rwxr-xr-xindra/newview/llpanelpick.h2
-rwxr-xr-xindra/newview/llpanelplaceinfo.cpp6
-rwxr-xr-xindra/newview/llpanelplaceinfo.h2
-rwxr-xr-xindra/newview/llpanelplaces.cpp2
-rwxr-xr-xindra/newview/llpathfindingmanager.cpp176
-rwxr-xr-xindra/newview/llpathfindingnavmesh.cpp4
-rwxr-xr-xindra/newview/llpathfindingnavmesh.h2
-rwxr-xr-xindra/newview/llpreview.cpp7
-rwxr-xr-xindra/newview/llproductinforequest.cpp18
-rwxr-xr-xindra/newview/llremoteparcelrequest.cpp17
-rwxr-xr-xindra/newview/llremoteparcelrequest.h9
-rwxr-xr-xindra/newview/llsidepanelappearance.cpp130
-rwxr-xr-xindra/newview/llsidepanelappearance.h18
-rwxr-xr-xindra/newview/llspeakers.cpp13
-rwxr-xr-xindra/newview/llstartup.cpp2
-rwxr-xr-xindra/newview/lltexturefetch.cpp179
-rwxr-xr-xindra/newview/lltexturefetch.h9
-rwxr-xr-xindra/newview/lltoolmorph.cpp16
-rwxr-xr-xindra/newview/lltranslate.cpp18
-rwxr-xr-xindra/newview/lltranslate.h7
-rwxr-xr-xindra/newview/lluploadfloaterobservers.cpp20
-rwxr-xr-xindra/newview/lluploadfloaterobservers.h19
-rwxr-xr-xindra/newview/llviewerdisplayname.cpp14
-rwxr-xr-xindra/newview/llviewerinventory.cpp434
-rwxr-xr-xindra/newview/llviewerinventory.h20
-rwxr-xr-xindra/newview/llviewermedia.cpp120
-rwxr-xr-xindra/newview/llviewermessage.cpp5
-rwxr-xr-xindra/newview/llviewerobjectlist.cpp24
-rwxr-xr-xindra/newview/llviewerparcelmedia.cpp2
-rwxr-xr-xindra/newview/llviewerregion.cpp193
-rwxr-xr-xindra/newview/llviewerstats.cpp19
-rw-r--r--[-rwxr-xr-x]indra/newview/llviewertexlayer.cpp0
-rwxr-xr-xindra/newview/llviewertexture.cpp62
-rwxr-xr-xindra/newview/llviewertexture.h12
-rw-r--r--indra/newview/llviewerwearable.h4
-rwxr-xr-xindra/newview/llviewerwindow.cpp4
-rwxr-xr-xindra/newview/llvoavatar.cpp46
-rwxr-xr-xindra/newview/llvoavatar.h5
-rwxr-xr-xindra/newview/llvoavatarself.cpp47
-rwxr-xr-xindra/newview/llvoicechannel.cpp21
-rwxr-xr-xindra/newview/llvoicevivox.cpp46
-rwxr-xr-xindra/newview/llwebprofile.cpp52
-rwxr-xr-xindra/newview/llwebsharing.cpp193
-rwxr-xr-xindra/newview/llwlhandlers.cpp27
-rwxr-xr-xindra/newview/llwlhandlers.h14
-rwxr-xr-xindra/newview/llworld.cpp2
-rwxr-xr-xindra/newview/llxmlrpctransaction.cpp2
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml16
-rwxr-xr-xindra/newview/tests/llhttpretrypolicy_test.cpp328
-rwxr-xr-xindra/newview/tests/llmediadataclient_test.cpp8
-rwxr-xr-xindra/newview/tests/llremoteparcelrequest_test.cpp16
-rwxr-xr-xindra/newview/tests/lltranslate_test.cpp12
-rwxr-xr-xindra/test/llassetuploadqueue_tut.cpp4
-rwxr-xr-xindra/test/llblowfish_tut.cpp2
-rwxr-xr-xindra/test/llhttpnode_tut.cpp3
-rwxr-xr-xindra/test/llsd_new_tut.cpp55
-rwxr-xr-xindra/test/llsdtraits.h2
-rwxr-xr-xindra/test/lltut.h10
-rwxr-xr-xindra/test/message_tut.cpp3
-rwxr-xr-xindra/test/mock_http_client.cpp3
-rwxr-xr-xindra/test/mock_http_client.h23
-rwxr-xr-xindra/viewer_components/updater/llupdatechecker.cpp11
-rwxr-xr-xindra/viewer_components/updater/llupdatechecker.h7
196 files changed, 6276 insertions, 4506 deletions
diff --git a/autobuild.xml b/autobuild.xml
index 148ca1710b..06a70ea5ed 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1291,9 +1291,9 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>5bc44db15eb3cca021382e40e04a9a38</string>
+ <string>df8857aeb5f44dfd95f9f9f57814423a</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/275707/arch/Linux/installer/llappearanceutility_source-0.1-linux-20130511.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index c494355746..1c30abe32d 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 95b1d536fe..0bc9b97488 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/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..a4cd8333cf 100755
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -249,13 +249,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'
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 99716ed7be..8b865f044d 100755
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -101,7 +101,6 @@ public:
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;
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..5830a5eca0 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)
{
- 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,7 @@ 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::post(
@@ -565,7 +563,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 +574,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 +584,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 +595,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 +605,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 +617,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/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 100644
index 0000000000..8cc3459654
--- /dev/null
+++ b/indra/llmessage/llhttpconstants.h
@@ -0,0 +1,229 @@
+/**
+ * @file llhttpconstants.h
+ * @brief Constants for HTTP requests and responses
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2013, 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$
+ */
+
+#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_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..49cfef2771 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,7 +480,7 @@ 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);
@@ -504,11 +490,11 @@ bool LLURLRequest::configure()
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 +624,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..28dfda8faf 100755
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -704,9 +704,15 @@ void LLFloater::openFloater(const LLSD& key)
dirtyRect();
}
+void LLFloater::verifyClose()
+{
+ LLPanel::handleCloseConfirmation();
+}
+
void LLFloater::closeFloater(bool app_quitting)
{
llinfos << "Closing floater " << getName() << llendl;
+
if (app_quitting)
{
LLFloater::sQuitting = true;
@@ -781,7 +787,7 @@ void LLFloater::closeFloater(bool app_quitting)
dirtyRect();
// Close callbacks
- onClose(app_quitting);
+ onClose(app_quitting);
mCloseSignal(this, LLSD(app_quitting));
// Hide or Destroy
@@ -1788,11 +1794,19 @@ void LLFloater::initRectControl()
void LLFloater::closeFrontmostFloater()
{
LLFloater* floater_to_close = gFloaterView->getFrontmostClosableFloater();
- if(floater_to_close)
+ if( floater_to_close )
{
- floater_to_close->closeFloater();
+ if ( floater_to_close->mVerifyUponClose )
+ {
+ floater_to_close->verifyClose();
+ //Closing of the window handle in the subclass - so bug out here.
+ return;
+ }
+ else
+ {
+ floater_to_close->closeFloater();
+ }
}
-
// if nothing took focus after closing focused floater
// give it to next floater (to allow closing multiple windows via keyboard in rapid succession)
if (gFocusMgr.getKeyboardFocus() == NULL)
@@ -2631,7 +2645,14 @@ void LLFloaterView::closeAllChildren(bool app_quitting)
if (floaterp->canClose() && !floaterp->isDead() &&
(app_quitting || floaterp->getVisible()))
{
- floaterp->closeFloater(app_quitting);
+ if ( floaterp->mVerifyUponClose )
+ {
+ floaterp->verifyClose();
+ }
+ else
+ {
+ floaterp->closeFloater(app_quitting);
+ }
}
}
}
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 4dba1e645f..bf71b527b3 100755
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -225,6 +225,7 @@ public:
// If allowed, close the floater cleanly, releasing focus.
virtual void closeFloater(bool app_quitting = false);
+ virtual void verifyClose();
// Close the floater or its host. Use when hidding or toggling a floater instance.
virtual void closeHostedFloater();
@@ -303,7 +304,7 @@ public:
/*virtual*/ void setVisible(BOOL visible); // do not override
/*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override
-
+ void handleCloseConfirmation( );
void setFrontmost(BOOL take_focus = TRUE);
virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp
index 67472ad166..01165a5718 100755
--- a/indra/llui/llpanel.cpp
+++ b/indra/llui/llpanel.cpp
@@ -114,7 +114,9 @@ LLPanel::LLPanel(const LLPanel::Params& p)
mCommitCallbackRegistrar(false),
mEnableCallbackRegistrar(false),
mXMLFilename(p.filename),
- mVisibleSignal(NULL)
+ mVisibleSignal(NULL),
+ mCloseConfirmationSignal(NULL),
+ mVerifyUponClose(false)
// *NOTE: Be sure to also change LLPanel::initFromParams(). We have too
// many classes derived from LLPanel to retrofit them all to pass in params.
{
@@ -127,6 +129,7 @@ LLPanel::LLPanel(const LLPanel::Params& p)
LLPanel::~LLPanel()
{
delete mVisibleSignal;
+ delete mCloseConfirmationSignal;
}
// virtual
@@ -349,6 +352,14 @@ void LLPanel::handleVisibilityChange ( BOOL new_visibility )
(*mVisibleSignal)(this, LLSD(new_visibility) ); // Pass BOOL as LLSD
}
+
+void LLPanel::handleCloseConfirmation( )
+{
+ if (mCloseConfirmationSignal)
+ {
+ (*mCloseConfirmationSignal)(this, LLSD() );
+ }
+}
void LLPanel::setFocus(BOOL b)
{
if( b && !hasFocus())
@@ -959,10 +970,17 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t::
{
mVisibleSignal = new commit_signal_t();
}
-
return mVisibleSignal->connect(cb);
}
+boost::signals2::connection LLPanel::setCloseConfirmationCallback( const commit_signal_t::slot_type& cb )
+{
+ if (!mCloseConfirmationSignal)
+ {
+ mCloseConfirmationSignal = new commit_signal_t();
+ }
+ return mCloseConfirmationSignal->connect(cb);
+}
static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
//-----------------------------------------------------------------------------
diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h
index e63b41f97c..1b0beaa5c8 100755
--- a/indra/llui/llpanel.h
+++ b/indra/llui/llpanel.h
@@ -116,6 +116,8 @@ public:
/*virtual*/ void draw();
/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask );
/*virtual*/ void handleVisibilityChange ( BOOL new_visibility );
+ void handleCloseConfirmation( );
+
// From LLFocusableElement
/*virtual*/ void setFocus( BOOL b );
@@ -251,6 +253,10 @@ public:
std::string getXMLFilename() { return mXMLFilename; };
boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb );
+ boost::signals2::connection setCloseConfirmationCallback( const commit_signal_t::slot_type& cb );
+
+public:
+ const BOOL confirmClose() const { return mVerifyUponClose; }
protected:
// Override to set not found list
@@ -260,6 +266,7 @@ protected:
EnableCallbackRegistry::ScopedRegistrar mEnableCallbackRegistrar;
commit_signal_t* mVisibleSignal; // Called when visibility changes, passes new visibility as LLSD()
+ commit_signal_t* mCloseConfirmationSignal;
std::string mHelpTopic; // the name of this panel's help topic to display in the Help Viewer
typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
@@ -267,7 +274,8 @@ protected:
// for setting the xml filename when building panel in context dependent cases
std::string mXMLFilename;
-
+ //Specific close-down logic in subclass
+ BOOL mVerifyUponClose;
private:
BOOL mBgVisible; // any background at all?
BOOL mBgOpaque; // use opaque color or image
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 6e0bb161af..4560951900 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -303,6 +303,7 @@ set(viewer_SOURCE_FILES
llhasheduniqueid.cpp
llhints.cpp
llhomelocationresponder.cpp
+ llhttpretrypolicy.cpp
llhudeffect.cpp
llhudeffectbeam.cpp
llhudeffectlookat.cpp
@@ -882,6 +883,7 @@ set(viewer_HEADER_FILES
llgroupmgr.h
llhasheduniqueid.h
llhints.h
+ llhttpretrypolicy.h
llhomelocationresponder.h
llhudeffect.h
llhudeffectbeam.h
@@ -2126,10 +2128,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(
@@ -2176,6 +2189,7 @@ if (LL_TESTS)
set(test_libs
${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${WINDOWS_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
@@ -2221,6 +2235,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 31c730e0bc..13bc571259 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11141,6 +11141,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..b4c3e33e0e 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);
}
}
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 652f199e28..cfe9055aab 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
@@ -420,93 +421,25 @@ public:
}
};
-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;
- }
-
- LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name);
- }
- return request_sent;
- }
-};
-
-LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering):
+LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering,
+ bool enforce_item_restrictions):
mFireCount(0),
- mUpdateBaseOrder(update_base_outfit_ordering)
+ mUpdateBaseOrder(update_base_outfit_ordering),
+ mEnforceItemRestrictions(enforce_item_restrictions)
{
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 +449,39 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
selfStopPhase("update_appearance_on_destroy");
- LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder);
+ LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder, mEnforceItemRestrictions);
}
}
-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() :
@@ -1203,8 +1155,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 +1221,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 +1265,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 +1289,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 +1547,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 +1564,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 +1583,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,18 +1598,16 @@ 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)
{
- LLViewerInventoryCategory* catp = item->getLinkedCategory();
- if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
- {
- gInventory.purgeObject(item->getUUID());
- }
+ remove_inventory_item(item->getUUID(), cb);
}
}
}
-void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items)
+void LLAppearanceMgr::removeCategoryContents(const LLUUID& category, bool keep_outfit_links,
+ LLPointer<LLInventoryCallback> cb)
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
@@ -1673,19 +1620,8 @@ void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_lin
continue;
if (item->getIsLinkType())
{
-#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,6 +1673,18 @@ 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);
@@ -1748,7 +1696,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 +1713,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 +1724,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 +1733,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.
@@ -1817,9 +1765,11 @@ 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;
+ removeCategoryContents(cof, keep_outfit_links, link_waiter);
LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;
}
@@ -1840,7 +1790,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)
{
@@ -1937,7 +1887,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 +1906,20 @@ 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);
-
- 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();
- }
+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::updateAppearanceFromCOF(bool update_base_outfit_ordering)
+void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering,
+ bool enforce_item_restrictions)
{
if (mIsInUpdateAppearanceFromCOF)
{
@@ -1996,14 +1932,31 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
+ if (enforce_item_restrictions)
+ {
+ LLInventoryModel::item_array_t items_to_kill;
+ findAllExcessOrDuplicateItems(getCOF(), items_to_kill);
+ if (items_to_kill.size()>0)
+ {
+ // 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));
+
+ // 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;
+ }
+ }
+
//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);
- // 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();
@@ -2019,7 +1972,6 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
//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 +1979,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 +2075,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 +2083,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 +2097,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 +2105,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 +2114,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)
@@ -2287,6 +2233,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 +2287,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 +2304,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 +2318,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 +2377,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 +2402,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 +2441,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 +2485,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 +2500,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 +2518,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);
}
}
}
@@ -2823,7 +2739,7 @@ bool LLAppearanceMgr::updateBaseOutfit()
updateClothingOrderingInfo();
// in a Base Outfit we do not remove items, only links
- purgeCategory(base_outfit_id, false);
+ removeCategoryContents(base_outfit_id, false, NULL);
LLPointer<LLInventoryCallback> dirty_state_updater =
new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state);
@@ -2920,7 +2836,7 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
// 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);
@@ -2957,79 +2873,33 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
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);
@@ -3037,33 +2907,36 @@ public:
}
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"))
{
+ const LLSD& content = getContent();
dumpContents(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
{
@@ -3082,7 +2955,8 @@ public:
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 +2968,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 +3002,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 +3141,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 +3152,7 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond
class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLIncrementCofVersionResponder);
public:
LLIncrementCofVersionResponder() : LLHTTPClient::Responder()
{
@@ -3276,22 +3163,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 +3201,7 @@ public:
}
}
+private:
LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
};
@@ -3373,6 +3270,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 +3297,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 +3316,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 +3490,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 +3514,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 +3545,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..2cc76c4b4c 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -49,7 +49,8 @@ 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 needToSaveCOF();
void updateCOF(const LLUUID& category, bool append = false);
void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
@@ -65,7 +66,8 @@ 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);
// Copy all items and the src category itself.
void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
@@ -105,12 +107,13 @@ 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);
@@ -129,16 +132,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();
@@ -213,16 +220,15 @@ 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);
+ void removeCategoryContents(const LLUUID& category, bool keep_outfit_links,
+ LLPointer<LLInventoryCallback> cb);
static void onOutfitRename(const LLSD& notification, const LLSD& response);
void setOutfitLocked(bool locked);
@@ -256,15 +262,31 @@ 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);
virtual ~LLUpdateAppearanceOnDestroy();
/* virtual */ void fire(const LLUUID& inv_item);
private:
U32 mFireCount;
bool mUpdateBaseOrder;
+ bool mEnforceItemRestrictions;
+};
+
+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/llfloatersidepanelcontainer.cpp b/indra/newview/llfloatersidepanelcontainer.cpp
index 5f9556a870..d5bb8157cf 100755
--- a/indra/newview/llfloatersidepanelcontainer.cpp
+++ b/indra/newview/llfloatersidepanelcontainer.cpp
@@ -45,8 +45,22 @@ LLFloaterSidePanelContainer::LLFloaterSidePanelContainer(const LLSD& key, const
// Prevent transient floaters (e.g. IM windows) from hiding
// when this floater is clicked.
LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::GLOBAL, this);
+ //We want this container to handle the shutdown logic of the sidepanelappearance.
+ mVerifyUponClose = TRUE;
}
+BOOL LLFloaterSidePanelContainer::postBuild()
+{
+ setCloseConfirmationCallback( boost::bind(&LLFloaterSidePanelContainer::onConfirmationClose,this,_2));
+ return TRUE;
+}
+
+void LLFloaterSidePanelContainer::onConfirmationClose( const LLSD &confirm )
+{
+ onClickCloseBtn();
+}
+
+
LLFloaterSidePanelContainer::~LLFloaterSidePanelContainer()
{
LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::GLOBAL, this);
@@ -59,22 +73,18 @@ void LLFloaterSidePanelContainer::onOpen(const LLSD& key)
void LLFloaterSidePanelContainer::onClickCloseBtn()
{
- LLPanelOutfitEdit* panel_outfit_edit =
- dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit"));
- if (panel_outfit_edit)
+ LLSidepanelAppearance* panel = getSidePanelAppearance();
+ if ( panel )
{
- LLFloater *parent = gFloaterView->getParentFloater(panel_outfit_edit);
- if (parent == this )
- {
- LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance*>(getPanel("appearance"));
- if ( panel_appearance )
- {
- panel_appearance->getWearable()->onClose();
- panel_appearance->showOutfitsInventoryPanel();
- }
- }
+ panel->onClose( this );
}
-
+ else
+ {
+ LLFloater::onClickCloseBtn();
+ }
+}
+void LLFloaterSidePanelContainer::close()
+{
LLFloater::onClickCloseBtn();
}
@@ -85,7 +95,7 @@ LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_na
if (!getVisible())
{
- openFloater();
+ openFloater();
}
LLPanel* panel = NULL;
@@ -106,10 +116,30 @@ LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_na
void LLFloaterSidePanelContainer::showPanel(const std::string& floater_name, const LLSD& key)
{
- LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name);
+ //If we're already open then check whether anything is dirty
+ LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>(floater_name);
if (floaterp)
{
- floaterp->openChildPanel(sMainPanelName, key);
+ if ( floaterp->getVisible() )
+ {
+ LLSidepanelAppearance* panel = floaterp->getSidePanelAppearance();
+ if ( panel )
+ {
+ if ( panel->checkForDirtyEdits() )
+ {
+ panel->onClickConfirmExitWithoutSaveIntoAppearance();
+ }
+ else
+ {
+ //or a call into some new f() that just shows inv panel?
+ floaterp->openChildPanel(sMainPanelName, key);
+ }
+ }
+ }
+ else
+ {
+ floaterp->openChildPanel(sMainPanelName, key);
+ }
}
}
@@ -133,3 +163,19 @@ LLPanel* LLFloaterSidePanelContainer::getPanel(const std::string& floater_name,
return NULL;
}
+
+LLSidepanelAppearance* LLFloaterSidePanelContainer::getSidePanelAppearance()
+{
+ LLSidepanelAppearance* panel_appearance = NULL;
+ LLPanelOutfitEdit* panel_outfit_edit = dynamic_cast<LLPanelOutfitEdit*>(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit"));
+ if (panel_outfit_edit)
+ {
+ LLFloater *parent = gFloaterView->getParentFloater(panel_outfit_edit);
+ if (parent == this )
+ {
+ panel_appearance = dynamic_cast<LLSidepanelAppearance*>(getPanel("appearance"));
+ }
+ }
+ return panel_appearance;
+
+}
diff --git a/indra/newview/llfloatersidepanelcontainer.h b/indra/newview/llfloatersidepanelcontainer.h
index 491723471f..974934b48f 100755
--- a/indra/newview/llfloatersidepanelcontainer.h
+++ b/indra/newview/llfloatersidepanelcontainer.h
@@ -30,6 +30,8 @@
#include "llfloater.h"
+class LLSidepanelAppearance;
+
/**
* Class LLFloaterSidePanelContainer
*
@@ -50,11 +52,14 @@ public:
~LLFloaterSidePanelContainer();
/*virtual*/ void onOpen(const LLSD& key);
-
/*virtual*/ void onClickCloseBtn();
+ /*virtual*/ BOOL postBuild();
+ void onConfirmationClose( const LLSD &confirm );
LLPanel* openChildPanel(const std::string& panel_name, const LLSD& params);
+ void close();
+
static void showPanel(const std::string& floater_name, const LLSD& key);
static void showPanel(const std::string& floater_name, const std::string& panel_name, const LLSD& key);
@@ -78,6 +83,9 @@ public:
}
return panel;
}
+
+private:
+ LLSidepanelAppearance* getSidePanelAppearance();
};
#endif // LL_LLFLOATERSIDEPANELCONTAINER_H
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/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..9c0af79923 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -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..c32abe507e 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
{
@@ -1901,49 +1895,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 +3027,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 +3557,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/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 935fe2b4d0..73ef3e60da 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -48,6 +48,7 @@
#include "llcallbacklist.h"
#include "llvoavatarself.h"
#include "llgesturemgr.h"
+#include "llsdutil.h"
#include <typeinfo>
//#define DIFF_INVENTORY_FILES
@@ -252,6 +253,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 +468,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 +479,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 +611,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 +676,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 +703,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 +775,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 +1154,174 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
notifyObservers();
}
+void parse_llsd_uuid_array(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 LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
+{
+ LL_DEBUGS("Inventory") << "ais update " << context << ":" << ll_pretty_print_sd(update) << llendl;
+
+ uuid_vec_t cat_ids;
+ parse_llsd_uuid_array(update,"_categories_removed",cat_ids);
+ for (uuid_vec_t::const_iterator it = cat_ids.begin();
+ it != cat_ids.end(); ++it)
+ {
+ onObjectDeletedFromServer(*it, false);
+ }
+
+ uuid_vec_t item_ids;
+ parse_llsd_uuid_array(update,"_category_items_removed",item_ids);
+ for (uuid_vec_t::const_iterator it = item_ids.begin();
+ it != item_ids.end(); ++it)
+ {
+ onObjectDeletedFromServer(*it, false);
+ }
+
+ uuid_vec_t broken_link_ids;
+ parse_llsd_uuid_array(update,"_broken_links_removed",broken_link_ids);
+ for (uuid_vec_t::const_iterator it = broken_link_ids.begin();
+ it != broken_link_ids.end(); ++it)
+ {
+ onObjectDeletedFromServer(*it, false);
+ }
+
+ // 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.
+#if 0
+ 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();
+ }
+ }
+#endif
+
+
+}
+
+// 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)
+{
+ 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()
+ LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1);
+ accountForUpdate(up);
+
+ // From purgeObject()
+ LLPreview::hide(object_id);
+ deleteObject(object_id, fix_broken_links);
+ }
+}
+
+
// Delete a particular inventory object by ID.
-void LLInventoryModel::deleteObject(const LLUUID& id)
+void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links)
{
lldebugs << "LLInventoryModel::deleteObject()" << llendl;
LLPointer<LLInventoryObject> obj = getObject(id);
@@ -1155,32 +1352,35 @@ 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)
{
- obj->removeFromServer();
- LLPreview::hide(id);
- deleteObject(id);
+ updateLinkedObjectsFromPurge(id);
}
+ notifyObservers();
}
void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)
@@ -1189,129 +1389,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++)
+ if (item_array.size() > 0)
{
- 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 (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode())
- {
- // 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
+ gInventory.notifyObservers();
+ for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
{
- // 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 +1486,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 +1552,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();
}
@@ -2091,11 +2187,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 +2208,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 +2219,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 +2383,11 @@ void LLInventoryModel::buildParentChildMap()
notifyObservers();
}
}
+
+ if (!gInventory.validate())
+ {
+ llwarns << "model failed validity check!" << llendl;
+ }
}
struct LLUUIDAndName
@@ -2809,7 +2926,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 +2938,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 +2980,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 +3058,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 +3119,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 +3206,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 +3221,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 +3508,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..696d0a9163 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,22 @@ 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);
+
+ // Update model after all descendents removed from server.
+ void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);
+
// 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);
/// move Item item_id to Trash
void removeItem(const LLUUID& item_id);
/// move Category category_id to Trash
@@ -334,17 +351,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 +557,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 17311dd75e..524467a37e 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..858ed06544 100755
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -48,6 +48,8 @@
#include "llviewerregion.h"
#include "llvoavatarself.h"
#include "llviewerwearable.h"
+#include "llnotificationsutil.h"
+#include "llfloatersidepanelcontainer.h"
static LLRegisterPanelClassWrapper<LLSidepanelAppearance> t_appearance("sidepanel_appearance");
@@ -70,13 +72,118 @@ private:
LLSidepanelAppearance *mPanel;
};
+bool LLSidepanelAppearance::callBackExitWithoutSaveViaBack(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if ( option == 0 )
+ {
+ LLAppearanceMgr::instance().setOutfitDirty( true );
+ showOutfitsInventoryPanel();
+ LLAppearanceMgr::getInstance()->wearBaseOutfit();
+ return true;
+ }
+ return false;
+}
+
+bool LLSidepanelAppearance::callBackExitWithoutSaveViaClose(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if ( option == 0 )
+ {
+ //revert current edits
+ mEditWearable->revertChanges();
+ //LLAppearanceMgr::getInstance()->wearBaseOutfit();
+ toggleWearableEditPanel(FALSE);
+ LLVOAvatarSelf::onCustomizeEnd( FALSE );
+ mLLFloaterSidePanelContainer->close();
+ return true;
+ }
+ return false;
+}
+
+void LLSidepanelAppearance::onClickConfirmExitWithoutSaveViaClose()
+{
+ if ( LLAppearanceMgr::getInstance()->isOutfitDirty() && !LLAppearanceMgr::getInstance()->isOutfitLocked() )
+ {
+ LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this;
+ LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveViaClose,pSelf,_1,_2) );
+ }
+ else
+ {
+ showOutfitsInventoryPanel();
+ }
+}
+
+
+bool LLSidepanelAppearance::callBackExitWithoutSaveIntoAppearance(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if ( option == 0 )
+ {
+ //revert current edits
+ mEditWearable->revertChanges();
+ toggleWearableEditPanel(FALSE);
+ LLVOAvatarSelf::onCustomizeEnd( FALSE );
+ //mLLFloaterSidePanelContainer->close();
+ showOutfitsInventoryPanel();
+ return true;
+ }
+ return false;
+}
+
+void LLSidepanelAppearance::onClickConfirmExitWithoutSaveIntoAppearance()
+{
+ if ( LLAppearanceMgr::getInstance()->isOutfitDirty() && !LLAppearanceMgr::getInstance()->isOutfitLocked() )
+ {
+ LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this;
+ LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveIntoAppearance,pSelf,_1,_2) );
+ }
+ else
+ {
+ showOutfitsInventoryPanel();
+ }
+}
+void LLSidepanelAppearance::onClickConfirmExitWithoutSaveViaBack()
+{
+ /*
+ if ( LLAppearanceMgr::getInstance()->isOutfitDirty() && !mSidePanelJustOpened && !LLAppearanceMgr::getInstance()->isOutfitLocked() )
+ {
+ LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this;
+ LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveViaBack,pSelf,_1,_2) );
+ }
+ else
+ */
+ {
+ showOutfitsInventoryPanel();
+ }
+}
+
+void LLSidepanelAppearance::onClose(LLFloaterSidePanelContainer* obj)
+{
+ mLLFloaterSidePanelContainer = obj;
+ if ( /*LLAppearanceMgr::getInstance()->isOutfitDirty() && */
+ /*!LLAppearanceMgr::getInstance()->isOutfitLocked() ||*/
+ ( mEditWearable->isAvailable() && mEditWearable->isDirty() ) )
+ {
+ LLSidepanelAppearance* pSelf = (LLSidepanelAppearance *)this;
+ LLNotificationsUtil::add("ConfirmExitWithoutSave", LLSD(), LLSD(), boost::bind(&LLSidepanelAppearance::callBackExitWithoutSaveViaClose,pSelf,_1,_2) );
+ }
+ else
+ {
+ LLVOAvatarSelf::onCustomizeEnd(FALSE);
+ toggleWearableEditPanel(FALSE);
+ mLLFloaterSidePanelContainer->close();
+ }
+}
+
LLSidepanelAppearance::LLSidepanelAppearance() :
LLPanel(),
mFilterSubString(LLStringUtil::null),
mFilterEditor(NULL),
mOutfitEdit(NULL),
mCurrOutfitPanel(NULL),
- mOpened(false)
+ mOpened(false),
+ mSidePanelJustOpened(true)
{
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
outfit_observer.addBOFReplacedCallback(boost::bind(&LLSidepanelAppearance::refreshCurrentOutfitName, this, ""));
@@ -85,6 +192,8 @@ LLSidepanelAppearance::LLSidepanelAppearance() :
gAgentWearables.addLoadingStartedCallback(boost::bind(&LLSidepanelAppearance::setWearablesLoading, this, true));
gAgentWearables.addLoadedCallback(boost::bind(&LLSidepanelAppearance::setWearablesLoading, this, false));
+
+
}
LLSidepanelAppearance::~LLSidepanelAppearance()
@@ -119,8 +228,8 @@ BOOL LLSidepanelAppearance::postBuild()
{
LLButton* back_btn = mOutfitEdit->getChild<LLButton>("back_btn");
if (back_btn)
- {
- back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::showOutfitsInventoryPanel, this));
+ {
+ back_btn->setClickedCallback(boost::bind(&LLSidepanelAppearance::onClickConfirmExitWithoutSaveViaBack, this));
}
}
@@ -144,6 +253,7 @@ BOOL LLSidepanelAppearance::postBuild()
setVisibleCallback(boost::bind(&LLSidepanelAppearance::onVisibilityChange,this,_2));
+
return TRUE;
}
@@ -183,6 +293,12 @@ void LLSidepanelAppearance::onOpen(const LLSD& key)
void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility)
{
+ //handle leaving and subsequent user verification of discarding any unsaved data
+ if ( mSidePanelJustOpened )
+ {
+ mSidePanelJustOpened = false;
+ }
+
LLSD visibility;
visibility["visible"] = new_visibility.asBoolean();
visibility["reset_accordion"] = false;
@@ -191,8 +307,9 @@ void LLSidepanelAppearance::onVisibilityChange(const LLSD &new_visibility)
void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
{
- if (new_visibility["visible"].asBoolean())
+ if (new_visibility["visible"].asBoolean() )
{
+
const BOOL is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible();
const BOOL is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible();
@@ -543,3 +660,8 @@ void LLSidepanelAppearance::updateScrollingPanelList()
mEditWearable->updateScrollingPanelList();
}
}
+
+bool LLSidepanelAppearance::checkForDirtyEdits()
+{
+ return ( mEditWearable->isDirty() ) ? true : false;
+}
diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h
index 762f557a80..caf5be62e9 100755
--- a/indra/newview/llsidepanelappearance.h
+++ b/indra/newview/llsidepanelappearance.h
@@ -38,9 +38,11 @@ class LLCurrentlyWornFetchObserver;
class LLPanelEditWearable;
class LLViewerWearable;
class LLPanelOutfitsInventory;
+class LLFloaterSidePanelContainer;
class LLSidepanelAppearance : public LLPanel
-{
+{
+
LOG_CLASS(LLSidepanelAppearance);
public:
LLSidepanelAppearance();
@@ -48,6 +50,8 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
+ void onClose(LLFloaterSidePanelContainer* obj);
+ void onClickCloseBtn();
void refreshCurrentOutfitName(const std::string& name = "");
@@ -65,6 +69,13 @@ public:
void updateScrollingPanelList();
void updateToVisibility( const LLSD& new_visibility );
LLPanelEditWearable* getWearable(){ return mEditWearable; }
+ bool callBackExitWithoutSaveViaBack(const LLSD& notification, const LLSD& response);
+ void onClickConfirmExitWithoutSaveViaBack();
+ bool callBackExitWithoutSaveViaClose(const LLSD& notification, const LLSD& response);
+ void onClickConfirmExitWithoutSaveViaClose();
+ bool checkForDirtyEdits();
+ bool callBackExitWithoutSaveIntoAppearance(const LLSD& notification, const LLSD& response);
+ void onClickConfirmExitWithoutSaveIntoAppearance();
private:
void onFilterEdit(const std::string& search_string);
@@ -85,6 +96,7 @@ private:
LLButton* mOpenOutfitBtn;
LLButton* mEditAppearanceBtn;
LLButton* mNewOutfitBtn;
+
LLPanel* mCurrOutfitPanel;
LLTextBox* mCurrentLookName;
@@ -99,6 +111,10 @@ private:
// Gets set to true when we're opened for the first time.
bool mOpened;
+ // Set to true if sidepanel has just been opened
+ bool mSidePanelJustOpened;
+ LLFloaterSidePanelContainer* mLLFloaterSidePanelContainer;
+
};
#endif //LL_LLSIDEPANELAPPEARANCE_H
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..f7fbb19bdc 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
@@ -1482,12 +1524,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 +1563,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 +1594,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 +1606,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 +1946,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 +1996,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 +2468,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 +2499,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 +2526,12 @@ LLTextureFetch::~LLTextureFetch()
mHttpOptions = NULL;
}
+ if (mHttpOptionsWithHeaders)
+ {
+ mHttpOptionsWithHeaders->release();
+ mHttpOptionsWithHeaders = NULL;
+ }
+
if (mHttpHeaders)
{
mHttpHeaders->release();
@@ -2464,7 +2566,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 +2628,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);
@@ -2728,7 +2835,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 +2858,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 +3329,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 +4139,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..50d67463c7 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -65,6 +65,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&) {}
@@ -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)
@@ -637,30 +621,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 +1139,396 @@ void move_inventory_item(
gAgent.sendReliableMessage();
}
+class AISCommand: public LLHTTPClient::Responder
+{
+public:
+ typedef boost::function<void()> command_func_type;
+
+ AISCommand(LLPointer<LLInventoryCallback> callback):
+ mCallback(callback)
+ {
+ mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
+ }
+
+ virtual ~AISCommand()
+ {
+ }
+
+ void run_command()
+ {
+ mCommandFunc();
+ }
+
+ void setCommandFunc(command_func_type command_func)
+ {
+ mCommandFunc = command_func;
+ }
+
+ // Need to do command-specific parsing to get an id here. May or
+ // may not need to bother, since most LLInventoryCallbacks do
+ // their work in the destructor.
+ virtual bool getResponseUUID(const LLSD& content, LLUUID& id)
+ {
+ return false;
+ }
+
+ /* virtual */ void 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 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 getCap(std::string& cap)
+ {
+ if (gAgent.getRegion())
+ {
+ cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
+ }
+ if (!cap.empty())
+ {
+ return true;
+ }
+ return false;
+ }
+
+private:
+ command_func_type mCommandFunc;
+ LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
+ LLPointer<LLInventoryCallback> mCallback;
+};
+
+class RemoveItemCommand: public AISCommand
+{
+public:
+ 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);
+ }
+};
+
+class RemoveCategoryCommand: public AISCommand
+{
+public:
+ 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);
+ }
+};
+
+class PurgeDescendentsCommand: public AISCommand
+{
+public:
+ 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);
+ }
+};
+
+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;
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 61b1b8d846..4e24dc87d1 100755
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -118,7 +118,6 @@ 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;
@@ -198,7 +197,6 @@ 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;
@@ -274,7 +272,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 +363,22 @@ void move_inventory_item(
const std::string& new_name,
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,
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/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 b8b53aa6e4..e77b29aca4 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;
};
@@ -1593,6 +1641,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("FetchInventory2");
capabilityNames.append("FetchInventoryDescendents2");
capabilityNames.append("IncrementCOFVersion");
+ capabilityNames.append("InventoryAPIv3");
}
capabilityNames.append("GetDisplayNames");
@@ -1655,7 +1704,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();
@@ -1728,31 +1779,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)
@@ -1762,7 +1819,7 @@ private:
LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
}
}
-
+
std::string mRetryURL;
U64 mRegionHandle;
S32 mAttempt;
@@ -1799,7 +1856,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)
@@ -1850,16 +1916,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)
@@ -1943,3 +2000,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..b73411080a 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;
}
};
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..45b402f0f6 100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1758,7 +1758,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 +1824,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 +2011,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..bf6aadd218 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) ;
@@ -338,8 +339,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 +447,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..8e7bed39c4 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1884,6 +1884,10 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
LL_DEBUGS("Avatar") << avString() << "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
{
@@ -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,36 @@ 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 0.1 meters.
+ // Camera positioning and other things start to break down when your avatar is "walking" while being fully underground
+ if (isSelf() && getWearableData() && isFullyLoaded() && !LLApp::isQuitting())
+ {
+ LLViewerWearable* shape = (LLViewerWearable*)getWearableData()->getWearable(LLWearableType::WT_SHAPE, 0);
+ if (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.
+
+ mAvatarOffset.mV[VZ] = hover_value;
+ shape->setVisualParamWeight(AVATAR_HOVER,hover_value, FALSE);
+
+ }
+ }
+ }
+}
+
+
//-----------------------------------------------------------------------------
// isActive()
//-----------------------------------------------------------------------------
@@ -7301,7 +7337,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;
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 85f6f25009..19ad49d3a1 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,7 +994,7 @@ 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);
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d54eb5f040..52c44e6e1b 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2241,6 +2241,7 @@ LLSD LLVOAvatarSelf::metricsData()
class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder
{
+ LOG_CLASS(ViewerAppearanceChangeMetricsResponder);
public:
ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,
volatile const S32 & live_sequence,
@@ -2251,32 +2252,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;
@@ -2425,6 +2419,7 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder
{
+ LOG_CLASS(CheckAgentAppearanceServiceResponder);
public:
CheckAgentAppearanceServiceResponder()
{
@@ -2434,22 +2429,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 +2587,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/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/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..07c8ecc4dd 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -10112,5 +10112,19 @@ Cannot create large prims that intersect other players. Please re-try when othe
name="okignore"
yestext="OK"/>
</notification>
-
+
+
+ <notification
+ icon="alertmodal.tga"
+ name="ConfirmExitWithoutSave"
+ type="alertmodal">
+ Closing this window will discard any changes you have made.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="OK"
+ ignoretext="Don't show me this again."/>
+ </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..891a53d011 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -134,12 +134,12 @@ 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();
if(status != 200)
{
std::string server_error;
@@ -195,8 +195,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;