summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xautobuild.xml8
-rwxr-xr-xbuild.sh8
-rwxr-xr-xindra/cmake/BuildVersion.cmake5
-rwxr-xr-xindra/edit-me-to-trigger-new-build.txt7
-rw-r--r--indra/llappearance/llavatarappearance.cpp19
-rw-r--r--indra/llappearance/llavatarappearance.h2
-rw-r--r--indra/llappearance/llpolyskeletaldistortion.cpp12
-rwxr-xr-xindra/llcharacter/lljoint.cpp42
-rwxr-xr-xindra/llcharacter/lljoint.h8
-rwxr-xr-xindra/llcharacter/llvisualparam.h1
-rwxr-xr-xindra/llcommon/CMakeLists.txt1
-rwxr-xr-xindra/llcommon/llhttpstatuscodes.h89
-rwxr-xr-xindra/llcommon/llpointer.h126
-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/llcommon/llsdutil.cpp2
-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.cpp35
-rwxr-xr-xindra/llinventory/llinventory.h9
-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.cpp189
-rwxr-xr-xindra/llmessage/llhttpclient.h26
-rwxr-xr-xindra/llmessage/llhttpclientadapter.cpp25
-rwxr-xr-xindra/llmessage/llhttpclientadapter.h8
-rwxr-xr-xindra/llmessage/llhttpconstants.cpp228
-rwxr-xr-xindra/llmessage/llhttpconstants.h225
-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.cpp69
-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.cpp2
-rwxr-xr-xindra/llui/llfloater.h2
-rwxr-xr-xindra/newview/CMakeLists.txt20
-rwxr-xr-xindra/newview/app_settings/logcontrol.xml1
-rwxr-xr-xindra/newview/app_settings/settings.xml11
-rwxr-xr-xindra/newview/character/avatar_lad.xml8
-rwxr-xr-xindra/newview/llaccountingcostmanager.cpp14
-rwxr-xr-xindra/newview/llaccountingcostmanager.h2
-rwxr-xr-xindra/newview/llagent.cpp57
-rwxr-xr-xindra/newview/llagentwearables.cpp228
-rwxr-xr-xindra/newview/llagentwearables.h14
-rwxr-xr-xindra/newview/llagentwearablesfetch.cpp409
-rwxr-xr-xindra/newview/llagentwearablesfetch.h41
-rwxr-xr-xindra/newview/llaisapi.cpp842
-rwxr-xr-xindra/newview/llaisapi.h181
-rwxr-xr-xindra/newview/llappearancemgr.cpp1747
-rwxr-xr-xindra/newview/llappearancemgr.h96
-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.cpp47
-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/llfloateropenobject.cpp20
-rwxr-xr-xindra/newview/llfloateropenobject.h11
-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/llfloatertos.cpp68
-rwxr-xr-xindra/newview/llfloaterurlentry.cpp47
-rwxr-xr-xindra/newview/llfloaterurlentry.h2
-rwxr-xr-xindra/newview/llfloaterwebcontent.cpp7
-rwxr-xr-xindra/newview/llfriendcard.cpp2
-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.cpp142
-rwxr-xr-xindra/newview/llhttpretrypolicy.h98
-rwxr-xr-xindra/newview/llimpanel.cpp7
-rwxr-xr-xindra/newview/llimview.cpp50
-rwxr-xr-xindra/newview/llinspectavatar.cpp6
-rwxr-xr-xindra/newview/llinventorybridge.cpp184
-rwxr-xr-xindra/newview/llinventorybridge.h4
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp16
-rwxr-xr-xindra/newview/llinventoryfunctions.h7
-rwxr-xr-xindra/newview/llinventorymodel.cpp1022
-rwxr-xr-xindra/newview/llinventorymodel.h62
-rwxr-xr-xindra/newview/llinventorymodelbackgroundfetch.cpp120
-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.cpp26
-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.cpp5
-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.cpp2
-rwxr-xr-xindra/newview/llspeakers.cpp13
-rwxr-xr-xindra/newview/llstartup.cpp6
-rw-r--r--indra/newview/lltexturefetch.cpp188
-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/llviewerfoldertype.cpp6
-rwxr-xr-xindra/newview/llviewerinventory.cpp694
-rwxr-xr-xindra/newview/llviewerinventory.h82
-rwxr-xr-xindra/newview/llviewermedia.cpp120
-rwxr-xr-xindra/newview/llviewermessage.cpp5
-rwxr-xr-xindra/newview/llviewerobject.cpp22
-rwxr-xr-xindra/newview/llviewerobject.h1
-rwxr-xr-xindra/newview/llviewerobjectlist.cpp24
-rwxr-xr-xindra/newview/llviewerparcelmedia.cpp2
-rwxr-xr-xindra/newview/llviewerregion.cpp227
-rwxr-xr-xindra/newview/llviewerregion.h3
-rwxr-xr-xindra/newview/llviewerstats.cpp59
-rwxr-xr-xindra/newview/llviewerstats.h5
-rw-r--r--[-rwxr-xr-x]indra/newview/llviewertexlayer.cpp0
-rwxr-xr-xindra/newview/llviewertexture.cpp83
-rwxr-xr-xindra/newview/llviewertexture.h27
-rw-r--r--indra/newview/llviewerwearable.cpp6
-rw-r--r--indra/newview/llviewerwearable.h4
-rwxr-xr-xindra/newview/llviewerwindow.cpp4
-rwxr-xr-xindra/newview/llvoavatar.cpp420
-rwxr-xr-xindra/newview/llvoavatar.h7
-rwxr-xr-xindra/newview/llvoavatarself.cpp174
-rwxr-xr-xindra/newview/llvoavatarself.h3
-rwxr-xr-xindra/newview/llvoicechannel.cpp21
-rwxr-xr-xindra/newview/llvoicevivox.cpp46
-rwxr-xr-xindra/newview/llvovolume.cpp51
-rwxr-xr-xindra/newview/llwearablelist.cpp1
-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.xml4
-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.cpp12
-rwxr-xr-xindra/viewer_components/updater/llupdatechecker.h7
219 files changed, 8995 insertions, 6178 deletions
diff --git a/autobuild.xml b/autobuild.xml
index e047d4d686..93de5d3d66 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -834,9 +834,9 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>d2542614df9dd99cbb5ff67e76d4a6c1</string>
+ <string>98994d5b0b4b3d43be22aa6a5c36e6fa</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock/rev/274899/arch/CYGWIN/installer/gmock-1.6.0-windows-20130426.tar.bz2</string>
+ <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock-graham/rev/272961/arch/CYGWIN/installer/gmock-1.6.0-windows-20130327.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@@ -1290,9 +1290,9 @@
<key>archive</key>
<map>
<key>hash</key>
- <string>5bc44db15eb3cca021382e40e04a9a38</string>
+ <string>fa7b79adc95946028580a609e33d885e</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/279662/arch/Linux/installer/llappearanceutility_source-0.1-linux-20130808.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
diff --git a/build.sh b/build.sh
index a78f368e47..9694131a67 100755
--- a/build.sh
+++ b/build.sh
@@ -275,11 +275,15 @@ then
if $build_viewer_deb && [ "$last_built_variant" == "Release" ]
then
begin_section "Build Viewer Debian Package"
- local have_private_repo=false
+ have_private_repo=false
+
+ # Get the current version.
+ current_version=`dpkg-parsechangelog | grep ^Version | awk '{ print $2 }'`
+
# mangle the changelog
dch --force-bad-version \
--distribution unstable \
- --newversion "${VIEWER_VERSION}" \
+ --newversion "${current_version}"+"${revision}" \
"Automated build #$build_id, repository $branch revision $revision." \
>> "$build_log" 2>&1
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index af2063ce6d..969670b1b9 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 774e8c0676..48e8b566a6 100755
--- a/indra/edit-me-to-trigger-new-build.txt
+++ b/indra/edit-me-to-trigger-new-build.txt
@@ -1,6 +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..bf13680496 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();
+ void computeBodySize();
protected:
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index 4ba16691c2..eb86f77d97 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -192,7 +192,7 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
- F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+ F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
LLJoint* joint;
joint_vec_map_t::iterator iter;
@@ -204,8 +204,10 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
joint = iter->first;
LLVector3 newScale = joint->getScale();
LLVector3 scaleDelta = iter->second;
- newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
- joint->setScale(newScale);
+ newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
+ //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
+ joint->storeScaleForReset( newScale );
+ joint->setScale(newScale);
}
for (iter = mJointOffsets.begin();
@@ -214,8 +216,8 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
joint = iter->first;
LLVector3 newPosition = joint->getPosition();
- LLVector3 positionDelta = iter->second;
- newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
+ LLVector3 positionDelta = iter->second;
+ newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
joint->setPosition(newPosition);
}
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index 09a7c11a22..5cd33fe709 100755
--- a/indra/llcharacter/lljoint.cpp
+++ b/indra/llcharacter/lljoint.cpp
@@ -48,8 +48,11 @@ void LLJoint::init()
mParent = NULL;
mXform.setScaleChildOffset(TRUE);
mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
+ mOldXform.setScaleChildOffset(TRUE);
+ mOldXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));
mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;
mUpdateXform = TRUE;
+ mResetAfterRestoreOldXform = false;
}
LLJoint::LLJoint() :
@@ -57,7 +60,6 @@ LLJoint::LLJoint() :
{
init();
touch();
- mResetAfterRestoreOldXform = false;
}
LLJoint::LLJoint(S32 joint_num) :
@@ -65,7 +67,6 @@ LLJoint::LLJoint(S32 joint_num) :
{
init();
touch();
- mResetAfterRestoreOldXform = false;
}
@@ -78,7 +79,6 @@ LLJoint::LLJoint(const std::string &name, LLJoint *parent) :
{
init();
mUpdateXform = FALSE;
- // *TODO: mResetAfterRestoreOldXform is not initialized!!!
setName(name);
if (parent)
@@ -239,11 +239,8 @@ const LLVector3& LLJoint::getPosition()
//--------------------------------------------------------------------
void LLJoint::setPosition( const LLVector3& pos )
{
-// if (mXform.getPosition() != pos)
- {
- mXform.setPosition(pos);
- touch(MATRIX_DIRTY | POSITION_DIRTY);
- }
+ mXform.setPosition(pos);
+ touch(MATRIX_DIRTY | POSITION_DIRTY);
}
@@ -251,38 +248,37 @@ void LLJoint::setPosition( const LLVector3& pos )
// setPosition()
//--------------------------------------------------------------------
void LLJoint::setDefaultFromCurrentXform( void )
-{
+{
mDefaultXform = mXform;
- touch(MATRIX_DIRTY | POSITION_DIRTY);
-
}
//--------------------------------------------------------------------
// storeCurrentXform()
//--------------------------------------------------------------------
void LLJoint::storeCurrentXform( const LLVector3& pos )
-{
+{
mOldXform = mXform;
- mResetAfterRestoreOldXform = true;
+ mResetAfterRestoreOldXform = true;
setPosition( pos );
+ touch(ALL_DIRTY);
}
+
//--------------------------------------------------------------------
-// restoreOldXform()
+// storeScaleForReset()
//--------------------------------------------------------------------
-void LLJoint::restoreOldXform( void )
+void LLJoint::storeScaleForReset( const LLVector3& scale )
{
- mResetAfterRestoreOldXform = false;
- mXform = mOldXform;
+ mOldXform.setScale( scale );
}
//--------------------------------------------------------------------
// restoreOldXform()
//--------------------------------------------------------------------
-void LLJoint::restoreToDefaultXform( void )
+void LLJoint::restoreOldXform( void )
{
mXform = mDefaultXform;
- setPosition( mXform.getPosition() );
+ mResetAfterRestoreOldXform = false;
+ mDirtyFlags = ALL_DIRTY;
}
-
//--------------------------------------------------------------------
// getWorldPosition()
//--------------------------------------------------------------------
@@ -299,8 +295,6 @@ LLVector3 LLJoint::getLastWorldPosition()
{
return mXform.getWorldPosition();
}
-
-
//--------------------------------------------------------------------
// setWorldPosition()
//--------------------------------------------------------------------
@@ -404,7 +398,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot )
//--------------------------------------------------------------------
const LLVector3& LLJoint::getScale()
{
- return mXform.getScale();
+ return mXform.getScale();
}
//--------------------------------------------------------------------
@@ -413,7 +407,7 @@ const LLVector3& LLJoint::getScale()
void LLJoint::setScale( const LLVector3& scale )
{
// if (mXform.getScale() != scale)
- {
+ {
mXform.setScale(scale);
touch();
}
diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h
index 2b1e2005c6..a6a439a965 100755
--- a/indra/llcharacter/lljoint.h
+++ b/indra/llcharacter/lljoint.h
@@ -84,6 +84,7 @@ protected:
LLXformMatrix mDefaultXform;
LLUUID mId;
+
public:
U32 mDirtyFlags;
BOOL mUpdateXform;
@@ -160,7 +161,7 @@ public:
// get/set local scale
const LLVector3& getScale();
void setScale( const LLVector3& scale );
-
+ void storeScaleForReset( const LLVector3& scale );
// get/set world matrix
const LLMatrix4 &getWorldMatrix();
void setWorldMatrix( const LLMatrix4& mat );
@@ -185,7 +186,6 @@ public:
S32 getJointNum() const { return mJointNum; }
void restoreOldXform( void );
- void restoreToDefaultXform( void );
void setDefaultFromCurrentXform( void );
void storeCurrentXform( const LLVector3& pos );
@@ -196,8 +196,8 @@ public:
//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
- //Setter for joint reset flag
- void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
+ void setJointResetFlag( bool val ) { mResetAfterRestoreOldXform = val; }
+
};
#endif // LL_LLJOINT_H
diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h
index 60ea7a369a..a4d9f93e56 100755
--- a/indra/llcharacter/llvisualparam.h
+++ b/indra/llcharacter/llvisualparam.h
@@ -47,6 +47,7 @@ enum EVisualParamGroup
VISUAL_PARAM_GROUP_TWEAKABLE,
VISUAL_PARAM_GROUP_ANIMATABLE,
VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT,
+ VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE, // deprecated params that used to be tweakable.
NUM_VISUAL_PARAM_GROUPS
};
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 3a4a8facc2..72a997cd89 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -177,7 +177,6 @@ set(llcommon_HEADER_FILES
llhandle.h
llhash.h
llheartbeat.h
- llhttpstatuscodes.h
llindexedqueue.h
llinitparam.h
llinstancetracker.h
diff --git a/indra/llcommon/llhttpstatuscodes.h b/indra/llcommon/llhttpstatuscodes.h
deleted file mode 100755
index 0173461dad..0000000000
--- a/indra/llcommon/llhttpstatuscodes.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * @file llhttpstatuscodes.h
- * @brief Constants for HTTP status codes
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_HTTP_STATUS_CODES_H
-#define LL_HTTP_STATUS_CODES_H
-
-#include "stdtypes.h"
-
-// Standard errors from HTTP spec:
-// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
-const S32 HTTP_CONTINUE = 100;
-const S32 HTTP_SWITCHING_PROTOCOLS = 101;
-
-// Success
-const S32 HTTP_OK = 200;
-const S32 HTTP_CREATED = 201;
-const S32 HTTP_ACCEPTED = 202;
-const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
-const S32 HTTP_NO_CONTENT = 204;
-const S32 HTTP_RESET_CONTENT = 205;
-const S32 HTTP_PARTIAL_CONTENT = 206;
-
-// Redirection
-const S32 HTTP_MULTIPLE_CHOICES = 300;
-const S32 HTTP_MOVED_PERMANENTLY = 301;
-const S32 HTTP_FOUND = 302;
-const S32 HTTP_SEE_OTHER = 303;
-const S32 HTTP_NOT_MODIFIED = 304;
-const S32 HTTP_USE_PROXY = 305;
-const S32 HTTP_TEMPORARY_REDIRECT = 307;
-
-// Client Error
-const S32 HTTP_BAD_REQUEST = 400;
-const S32 HTTP_UNAUTHORIZED = 401;
-const S32 HTTP_PAYMENT_REQUIRED = 402;
-const S32 HTTP_FORBIDDEN = 403;
-const S32 HTTP_NOT_FOUND = 404;
-const S32 HTTP_METHOD_NOT_ALLOWED = 405;
-const S32 HTTP_NOT_ACCEPTABLE = 406;
-const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
-const S32 HTTP_REQUEST_TIME_OUT = 408;
-const S32 HTTP_CONFLICT = 409;
-const S32 HTTP_GONE = 410;
-const S32 HTTP_LENGTH_REQUIRED = 411;
-const S32 HTTP_PRECONDITION_FAILED = 412;
-const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
-const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
-const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
-const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
-const S32 HTTP_EXPECTATION_FAILED = 417;
-
-// Server Error
-const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
-const S32 HTTP_NOT_IMPLEMENTED = 501;
-const S32 HTTP_BAD_GATEWAY = 502;
-const S32 HTTP_SERVICE_UNAVAILABLE = 503;
-const S32 HTTP_GATEWAY_TIME_OUT = 504;
-const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
-
-// We combine internal process errors with status codes
-// These status codes should not be sent over the wire
-// and indicate something went wrong internally.
-// If you get these they are not normal.
-const S32 HTTP_INTERNAL_ERROR = 499;
-
-#endif
diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h
index 88c09c8dca..dd43e3aaa2 100755
--- a/indra/llcommon/llpointer.h
+++ b/indra/llcommon/llpointer.h
@@ -171,4 +171,130 @@ protected:
Type* mPointer;
};
+template <class Type> class LLConstPointer
+{
+public:
+ LLConstPointer() :
+ mPointer(NULL)
+ {
+ }
+
+ LLConstPointer(const Type* ptr) :
+ mPointer(ptr)
+ {
+ ref();
+ }
+
+ LLConstPointer(const LLConstPointer<Type>& ptr) :
+ mPointer(ptr.mPointer)
+ {
+ ref();
+ }
+
+ // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
+ template<typename Subclass>
+ LLConstPointer(const LLConstPointer<Subclass>& ptr) :
+ mPointer(ptr.get())
+ {
+ ref();
+ }
+
+ ~LLConstPointer()
+ {
+ unref();
+ }
+
+ const Type* get() const { return mPointer; }
+ const Type* operator->() const { return mPointer; }
+ const Type& operator*() const { return *mPointer; }
+
+ operator BOOL() const { return (mPointer != NULL); }
+ operator bool() const { return (mPointer != NULL); }
+ bool operator!() const { return (mPointer == NULL); }
+ bool isNull() const { return (mPointer == NULL); }
+ bool notNull() const { return (mPointer != NULL); }
+
+ operator const Type*() const { return mPointer; }
+ bool operator !=(const Type* ptr) const { return (mPointer != ptr); }
+ bool operator ==(const Type* ptr) const { return (mPointer == ptr); }
+ bool operator ==(const LLConstPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
+ bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
+ bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
+
+ LLConstPointer<Type>& operator =(const Type* ptr)
+ {
+ if( mPointer != ptr )
+ {
+ unref();
+ mPointer = ptr;
+ ref();
+ }
+
+ return *this;
+ }
+
+ LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr)
+ {
+ if( mPointer != ptr.mPointer )
+ {
+ unref();
+ mPointer = ptr.mPointer;
+ ref();
+ }
+ return *this;
+ }
+
+ // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
+ template<typename Subclass>
+ LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)
+ {
+ if( mPointer != ptr.get() )
+ {
+ unref();
+ mPointer = ptr.get();
+ ref();
+ }
+ return *this;
+ }
+
+ // Just exchange the pointers, which will not change the reference counts.
+ static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b)
+ {
+ const Type* temp = a.mPointer;
+ a.mPointer = b.mPointer;
+ b.mPointer = temp;
+ }
+
+protected:
+#ifdef LL_LIBRARY_INCLUDE
+ void ref();
+ void unref();
+#else
+ void ref()
+ {
+ if (mPointer)
+ {
+ mPointer->ref();
+ }
+ }
+
+ void unref()
+ {
+ if (mPointer)
+ {
+ const Type *tempp = mPointer;
+ mPointer = NULL;
+ tempp->unref();
+ if (mPointer != NULL)
+ {
+ llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
+ unref();
+ }
+ }
+ }
+#endif
+protected:
+ const Type* mPointer;
+};
+
#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 614a2d5636..2f8ea1f3d8 100755
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -168,8 +168,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
break;
case LLSD::TypeString:
- if(data.asString().empty()) ostr << pre << "<string />" << post;
- else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post;
+ if(data.asStringRef().empty()) ostr << pre << "<string />" << post;
+ else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post;
break;
case LLSD::TypeDate:
@@ -182,7 +182,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
case LLSD::TypeBinary:
{
- LLSD::Binary buffer = data.asBinary();
+ const LLSD::Binary& buffer = data.asBinary();
if(buffer.empty())
{
ostr << pre << "<binary />" << post;
@@ -375,13 +375,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
{
break;
}
+ count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
+ if (!count)
{
-
- count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
- if (!count)
- {
- break;
- }
+ break;
}
status = XML_ParseBuffer(mParser, count, false);
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 803417d368..562fd26658 100755
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -182,7 +182,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd)
char* ll_pretty_print_sd(const LLSD& sd)
{
- const U32 bufferSize = 10 * 1024;
+ const U32 bufferSize = 100 * 1024;
static char buffer[bufferSize];
std::ostringstream stream;
//stream.rdbuf()->pubsetbuf(buffer, bufferSize);
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp
index 6fe0bfc7d1..d49f615ac4 100755
--- a/indra/llcorehttp/_httplibcurl.cpp
+++ b/indra/llcorehttp/_httplibcurl.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,7 +31,7 @@
#include "_httpoprequest.h"
#include "_httppolicy.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
namespace LLCore
@@ -359,12 +359,17 @@ int HttpLibcurl::getActiveCountInClass(int policy_class) const
struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist)
{
- for (HttpHeaders::container_t::const_iterator it(headers->mHeaders.begin());
-
- headers->mHeaders.end() != it;
- ++it)
+ const HttpHeaders::const_iterator end(headers->end());
+ for (HttpHeaders::const_iterator it(headers->begin()); end != it; ++it)
{
- slist = curl_slist_append(slist, (*it).c_str());
+ static const char sep[] = ": ";
+ std::string header;
+ header.reserve((*it).first.size() + (*it).second.size() + sizeof(sep));
+ header.append((*it).first);
+ header.append(sep);
+ header.append((*it).second);
+
+ slist = curl_slist_append(slist, header.c_str());
}
return slist;
}
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index 51a8eaf998..95e0f72c0b 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -44,7 +44,7 @@
#include "_httplibcurl.h"
#include "_httpinternal.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
#include "llproxy.h"
namespace
@@ -479,6 +479,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
+ // *TODO: Should this be 'Keep-Alive' ?
mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
}
@@ -609,7 +610,8 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
const size_t hdr_size(size * nmemb);
const char * hdr_data(static_cast<const char *>(data)); // Not null terminated
-
+ bool is_header(true);
+
if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len))
{
// One of possibly several status lines. Reset what we know and start over
@@ -620,8 +622,9 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
op->mStatus = HttpStatus();
if (op->mReplyHeaders)
{
- op->mReplyHeaders->mHeaders.clear();
+ op->mReplyHeaders->clear();
}
+ is_header = false;
}
// Nothing in here wants a final CR/LF combination. Remove
@@ -636,18 +639,18 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
}
// Save header if caller wants them in the response
- if (op->mProcFlags & PF_SAVE_HEADERS)
+ if (is_header && op->mProcFlags & PF_SAVE_HEADERS)
{
// Save headers in response
if (! op->mReplyHeaders)
{
op->mReplyHeaders = new HttpHeaders;
}
- op->mReplyHeaders->mHeaders.push_back(std::string(hdr_data, wanted_hdr_size));
+ op->mReplyHeaders->appendNormal(hdr_data, wanted_hdr_size);
}
// Detect and parse 'Content-Range' headers
- if (op->mProcFlags & PF_SCAN_RANGE_HEADER)
+ if (is_header && op->mProcFlags & PF_SCAN_RANGE_HEADER)
{
char hdr_buffer[128]; // Enough for a reasonable header
size_t frag_size((std::min)(wanted_hdr_size, sizeof(hdr_buffer) - 1));
diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp
index 40ad4f047d..909dc5b0cb 100755
--- a/indra/llcorehttp/examples/http_texture_load.cpp
+++ b/indra/llcorehttp/examples/http_texture_load.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -328,7 +328,7 @@ WorkingSet::WorkingSet()
mTextures.reserve(30000);
mHeaders = new LLCore::HttpHeaders;
- mHeaders->mHeaders.push_back("Accept: image/x-j2c");
+ mHeaders->append("Accept", "image/x-j2c");
}
diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp
index 2832696271..23ebea361c 100755
--- a/indra/llcorehttp/httpheaders.cpp
+++ b/indra/llcorehttp/httpheaders.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,6 +26,8 @@
#include "httpheaders.h"
+#include "llstring.h"
+
namespace LLCore
{
@@ -40,5 +42,142 @@ HttpHeaders::~HttpHeaders()
{}
+void
+HttpHeaders::clear()
+{
+ mHeaders.clear();
+}
+
+
+void HttpHeaders::append(const std::string & name, const std::string & value)
+{
+ mHeaders.push_back(value_type(name, value));
+}
+
+
+void HttpHeaders::append(const char * name, const char * value)
+{
+ mHeaders.push_back(value_type(name, value));
+}
+
+
+void HttpHeaders::appendNormal(const char * header, size_t size)
+{
+ std::string name;
+ std::string value;
+
+ int col_pos(0);
+ for (; col_pos < size; ++col_pos)
+ {
+ if (':' == header[col_pos])
+ break;
+ }
+
+ if (col_pos < size)
+ {
+ // Looks like a header, split it and normalize.
+ // Name is everything before the colon, may be zero-length.
+ name.assign(header, col_pos);
+
+ // Value is everything after the colon, may also be zero-length.
+ const size_t val_len(size - col_pos - 1);
+ if (val_len)
+ {
+ value.assign(header + col_pos + 1, val_len);
+ }
+
+ // Clean the strings
+ LLStringUtil::toLower(name);
+ LLStringUtil::trim(name);
+ LLStringUtil::trimHead(value);
+ }
+ else
+ {
+ // Uncertain what this is, we'll pack it as
+ // a name without a value. Won't clean as we don't
+ // know what it is...
+ name.assign(header, size);
+ }
+
+ mHeaders.push_back(value_type(name, value));
+}
+
+
+// Find from end to simulate a tradition of using single-valued
+// std::map for this in the past.
+const std::string * HttpHeaders::find(const char * name) const
+{
+ const_reverse_iterator iend(rend());
+ for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter)
+ {
+ if ((*iter).first == name)
+ {
+ return &(*iter).second;
+ }
+ }
+ return NULL;
+}
+
+
+// Standard Iterators
+HttpHeaders::iterator HttpHeaders::begin()
+{
+ return mHeaders.begin();
+}
+
+
+HttpHeaders::const_iterator HttpHeaders::begin() const
+{
+ return mHeaders.begin();
+}
+
+
+HttpHeaders::iterator HttpHeaders::end()
+{
+ return mHeaders.end();
+}
+
+
+HttpHeaders::const_iterator HttpHeaders::end() const
+{
+ return mHeaders.end();
+}
+
+
+// Standard Reverse Iterators
+HttpHeaders::reverse_iterator HttpHeaders::rbegin()
+{
+ return mHeaders.rbegin();
+}
+
+
+HttpHeaders::const_reverse_iterator HttpHeaders::rbegin() const
+{
+ return mHeaders.rbegin();
+}
+
+
+HttpHeaders::reverse_iterator HttpHeaders::rend()
+{
+ return mHeaders.rend();
+}
+
+
+HttpHeaders::const_reverse_iterator HttpHeaders::rend() const
+{
+ return mHeaders.rend();
+}
+
+
+// Return the raw container to the caller.
+//
+// To be used FOR UNIT TESTS ONLY.
+//
+HttpHeaders::container_t & HttpHeaders::getContainerTESTONLY()
+{
+ return mHeaders;
+}
+
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h
index 3449daa3a1..f70cd898f3 100755
--- a/indra/llcorehttp/httpheaders.h
+++ b/indra/llcorehttp/httpheaders.h
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -43,13 +43,26 @@ namespace LLCore
/// caller has asked that headers be returned (not the default
/// option).
///
-/// @note
-/// This is a minimally-functional placeholder at the moment
-/// to fill out the class hierarchy. The final class will be
-/// something else, probably more pair-oriented. It's also
-/// an area where shared values are desirable so refcounting is
-/// already specced and a copy-on-write scheme imagined.
-/// Expect changes here.
+/// Class is mostly a thin wrapper around a vector of pairs
+/// of strings. Methods provided are few and intended to
+/// reflect actual use patterns. These include:
+/// - Clearing the list
+/// - Appending a name/value pair to the vector
+/// - Processing a raw byte string into a normalized name/value
+/// pair and appending the result.
+/// - Simple case-sensitive find-last-by-name search
+/// - Forward and reverse iterators over all pairs
+///
+/// Container is ordered and multi-valued. Headers are
+/// written in the order in which they are appended and
+/// are stored in the order in which they're received from
+/// the wire. The same header may appear two or more times
+/// in any container. Searches using the simple find()
+/// interface will find only the last occurrence (somewhat
+/// simulates the use of std::map). Fuller searches require
+/// the use of an iterator. Headers received from the wire
+/// are only returned from the last request when redirections
+/// are involved.
///
/// Threading: Not intrinsically thread-safe. It *is* expected
/// that callers will build these objects and then share them
@@ -64,6 +77,16 @@ namespace LLCore
class HttpHeaders : public LLCoreInt::RefCounted
{
public:
+ typedef std::pair<std::string, std::string> header_t;
+ typedef std::vector<header_t> container_t;
+ typedef container_t::iterator iterator;
+ typedef container_t::const_iterator const_iterator;
+ typedef container_t::reverse_iterator reverse_iterator;
+ typedef container_t::const_reverse_iterator const_reverse_iterator;
+ typedef container_t::value_type value_type;
+ typedef container_t::size_type size_type;
+
+public:
/// @post In addition to the instance, caller has a refcount
/// to the instance. A call to @see release() will destroy
/// the instance.
@@ -76,7 +99,78 @@ protected:
void operator=(const HttpHeaders &); // Not defined
public:
- typedef std::vector<std::string> container_t;
+ // Empty the list of headers.
+ void clear();
+
+ // Append a name/value pair supplied as either std::strings
+ // or NUL-terminated char * to the header list. No normalization
+ // is performed on the strings. No conformance test is
+ // performed (names may contain spaces, colons, etc.).
+ //
+ void append(const std::string & name, const std::string & value);
+ void append(const char * name, const char * value);
+
+ // Extract a name/value pair from a raw byte array using
+ // the first colon character as a separator. Input string
+ // does not need to be NUL-terminated. Resulting name/value
+ // pair is appended to the header list.
+ //
+ // Normalization is performed on the name/value pair as
+ // follows:
+ // - name is lower-cased according to mostly ASCII rules
+ // - name is left- and right-trimmed of spaces and tabs
+ // - value is left-trimmed of spaces and tabs
+ // - either or both of name and value may be zero-length
+ //
+ // By convention, headers read from the wire will be normalized
+ // in this fashion prior to delivery to any HttpHandler code.
+ // Headers to be written to the wire are left as appended to
+ // the list.
+ void appendNormal(const char * header, size_t size);
+
+ // Perform a simple, case-sensitive search of the header list
+ // returning a pointer to the value of the last matching header
+ // in the header list. If none is found, a NULL pointer is returned.
+ //
+ // Any pointer returned references objects in the container itself
+ // and will have the same lifetime as this class. If you want
+ // the value beyond the lifetime of this instance, make a copy.
+ //
+ // @arg name C-style string giving the name of a header
+ // to search. The comparison is case-sensitive
+ // though list entries may have been normalized
+ // to lower-case.
+ //
+ // @return NULL if the header wasn't found otherwise
+ // a pointer to a std::string in the container.
+ // Pointer is valid only for the lifetime of
+ // the container or until container is modifed.
+ //
+ const std::string * find(const char * name) const;
+
+ // Count of headers currently in the list.
+ size_type size() const
+ {
+ return mHeaders.size();
+ }
+
+ // Standard std::vector-based forward iterators.
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ // Standard std::vector-based reverse iterators.
+ reverse_iterator rbegin();
+ const_reverse_iterator rbegin() const;
+ reverse_iterator rend();
+ const_reverse_iterator rend() const;
+
+public:
+ // For unit tests only - not a public API
+ container_t & getContainerTESTONLY();
+
+protected:
container_t mHeaders;
}; // end class HttpHeaders
diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp
index ce0d19b058..668c36dc66 100755
--- a/indra/llcorehttp/tests/test_httpheaders.hpp
+++ b/indra/llcorehttp/tests/test_httpheaders.hpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,7 +36,6 @@
using namespace LLCoreInt;
-
namespace tut
{
@@ -63,7 +62,7 @@ void HttpHeadersTestObjectType::test<1>()
HttpHeaders * headers = new HttpHeaders();
ensure("One ref on construction of HttpHeaders", headers->getRefCount() == 1);
ensure("Memory being used", mMemTotal < GetMemTotal());
- ensure("Nothing in headers", 0 == headers->mHeaders.size());
+ ensure("Nothing in headers", 0 == headers->size());
// release the implicit reference, causing the object to be released
headers->release();
@@ -85,14 +84,340 @@ void HttpHeadersTestObjectType::test<2>()
{
// Append a few strings
- std::string str1("Pragma:");
- headers->mHeaders.push_back(str1);
- std::string str2("Accept: application/json");
- headers->mHeaders.push_back(str2);
+ std::string str1n("Pragma");
+ std::string str1v("");
+ headers->append(str1n, str1v);
+ std::string str2n("Accept");
+ std::string str2v("application/json");
+ headers->append(str2n, str2v);
+
+ ensure("Headers retained", 2 == headers->size());
+ HttpHeaders::container_t & c(headers->getContainerTESTONLY());
+
+ ensure("First name is first name", c[0].first == str1n);
+ ensure("First value is first value", c[0].second == str1v);
+ ensure("Second name is second name", c[1].first == str2n);
+ ensure("Second value is second value", c[1].second == str2v);
+ }
+
+ // release the implicit reference, causing the object to be released
+ headers->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpHeadersTestObjectType::test<3>()
+{
+ set_test_name("HttpHeaders basic find");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpHeaders * headers = new HttpHeaders();
+
+ {
+ // Append a few strings
+ std::string str1n("Uno");
+ std::string str1v("1");
+ headers->append(str1n, str1v);
+ std::string str2n("doS");
+ std::string str2v("2-2-2-2");
+ headers->append(str2n, str2v);
+ std::string str3n("TRES");
+ std::string str3v("trois gymnopedie");
+ headers->append(str3n, str3v);
+
+ ensure("Headers retained", 3 == headers->size());
+
+ const std::string * result(NULL);
+
+ // Find a header
+ result = headers->find("TRES");
+ ensure("Found the last item", result != NULL);
+ ensure("Last item is a nice", result != NULL && str3v == *result);
+
+ // appends above are raw and find is case sensitive
+ result = headers->find("TReS");
+ ensure("Last item not found due to case", result == NULL);
+
+ result = headers->find("TRE");
+ ensure("Last item not found due to prefixing (1)", result == NULL);
+
+ result = headers->find("TRESS");
+ ensure("Last item not found due to prefixing (2)", result == NULL);
+ }
+
+ // release the implicit reference, causing the object to be released
+ headers->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpHeadersTestObjectType::test<4>()
+{
+ set_test_name("HttpHeaders normalized header entry");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpHeaders * headers = new HttpHeaders();
+
+ {
+ static char line1[] = " AcCePT : image/yourfacehere";
+ static char line1v[] = "image/yourfacehere";
+ headers->appendNormal(line1, sizeof(line1) - 1);
+
+ ensure("First append worked in some fashion", 1 == headers->size());
+
+ const std::string * result(NULL);
+
+ // Find a header
+ result = headers->find("accept");
+ ensure("Found 'accept'", result != NULL);
+ ensure("accept value has face", result != NULL && *result == line1v);
+
+ // Left-clean on value
+ static char line2[] = " next : \t\tlinejunk \t";
+ headers->appendNormal(line2, sizeof(line2) - 1);
+ ensure("Second append worked", 2 == headers->size());
+ result = headers->find("next");
+ ensure("Found 'next'", result != NULL);
+ ensure("next value is left-clean", result != NULL &&
+ *result == "linejunk \t");
+
+ // First value unmolested
+ result = headers->find("accept");
+ ensure("Found 'accept' again", result != NULL);
+ ensure("accept value has face", result != NULL && *result == line1v);
+
+ // Colons in value are okay
+ static char line3[] = "FancY-PANTs::plop:-neuf-=vleem=";
+ static char line3v[] = ":plop:-neuf-=vleem=";
+ headers->appendNormal(line3, sizeof(line3) - 1);
+ ensure("Third append worked", 3 == headers->size());
+ result = headers->find("fancy-pants");
+ ensure("Found 'fancy-pants'", result != NULL);
+ ensure("fancy-pants value has colons", result != NULL && *result == line3v);
+
+ // Zero-length value
+ static char line4[] = "all-talk-no-walk:";
+ headers->appendNormal(line4, sizeof(line4) - 1);
+ ensure("Fourth append worked", 4 == headers->size());
+ result = headers->find("all-talk-no-walk");
+ ensure("Found 'all-talk'", result != NULL);
+ ensure("al-talk value is zero-length", result != NULL && result->size() == 0);
+
+ // Zero-length name
+ static char line5[] = ":all-talk-no-walk";
+ static char line5v[] = "all-talk-no-walk";
+ headers->appendNormal(line5, sizeof(line5) - 1);
+ ensure("Fifth append worked", 5 == headers->size());
+ result = headers->find("");
+ ensure("Found no-name", result != NULL);
+ ensure("no-name value is something", result != NULL && *result == line5v);
+
+ // Lone colon is still something
+ headers->clear();
+ static char line6[] = " :";
+ headers->appendNormal(line6, sizeof(line6) - 1);
+ ensure("Sixth append worked", 1 == headers->size());
+ result = headers->find("");
+ ensure("Found 2nd no-name", result != NULL);
+ ensure("2nd no-name value is nothing", result != NULL && result->size() == 0);
+
+ // Line without colons is taken as-is and unstripped in name
+ static char line7[] = " \toskdgioasdghaosdghoowg28342908tg8902hg0hwedfhqew890v7qh0wdebv78q0wdevbhq>?M>BNM<ZV>?NZ? \t";
+ headers->appendNormal(line7, sizeof(line7) - 1);
+ ensure("Seventh append worked", 2 == headers->size());
+ result = headers->find(line7);
+ ensure("Found whatsit line", result != NULL);
+ ensure("Whatsit line has no value", result != NULL && result->size() == 0);
+
+ // Normaling interface heeds the byte count, doesn't look for NUL-terminator
+ static char line8[] = "binary:ignorestuffontheendofthis";
+ headers->appendNormal(line8, 13);
+ ensure("Eighth append worked", 3 == headers->size());
+ result = headers->find("binary");
+ ensure("Found 'binary'", result != NULL);
+ ensure("binary value was limited to 'ignore'", result != NULL &&
+ *result == "ignore");
+
+ }
- ensure("Headers retained", 2 == headers->mHeaders.size());
- ensure("First is first", headers->mHeaders[0] == str1);
- ensure("Second is second", headers->mHeaders[1] == str2);
+ // release the implicit reference, causing the object to be released
+ headers->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+// Verify forward iterator finds everything as expected
+template <> template <>
+void HttpHeadersTestObjectType::test<5>()
+{
+ set_test_name("HttpHeaders iterator tests");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpHeaders * headers = new HttpHeaders();
+
+ HttpHeaders::iterator end(headers->end()), begin(headers->begin());
+ ensure("Empty container has equal begin/end const iterators", end == begin);
+ HttpHeaders::const_iterator cend(headers->end()), cbegin(headers->begin());
+ ensure("Empty container has equal rbegin/rend const iterators", cend == cbegin);
+
+ ensure("Empty container has equal begin/end iterators", headers->end() == headers->begin());
+
+ {
+ static char line1[] = " AcCePT : image/yourfacehere";
+ static char line1v[] = "image/yourfacehere";
+ headers->appendNormal(line1, sizeof(line1) - 1);
+
+ static char line2[] = " next : \t\tlinejunk \t";
+ static char line2v[] = "linejunk \t";
+ headers->appendNormal(line2, sizeof(line2) - 1);
+
+ static char line3[] = "FancY-PANTs::plop:-neuf-=vleem=";
+ static char line3v[] = ":plop:-neuf-=vleem=";
+ headers->appendNormal(line3, sizeof(line3) - 1);
+
+ static char line4[] = "all-talk-no-walk:";
+ static char line4v[] = "";
+ headers->appendNormal(line4, sizeof(line4) - 1);
+
+ static char line5[] = ":all-talk-no-walk";
+ static char line5v[] = "all-talk-no-walk";
+ headers->appendNormal(line5, sizeof(line5) - 1);
+
+ static char line6[] = " :";
+ static char line6v[] = "";
+ headers->appendNormal(line6, sizeof(line6) - 1);
+
+ ensure("All entries accounted for", 6 == headers->size());
+
+ static char * values[] = {
+ line1v,
+ line2v,
+ line3v,
+ line4v,
+ line5v,
+ line6v
+ };
+
+ int i(0);
+ HttpHeaders::const_iterator cend(headers->end());
+ for (HttpHeaders::const_iterator it(headers->begin());
+ cend != it;
+ ++it, ++i)
+ {
+ std::ostringstream str;
+ str << "Const Iterator value # " << i << " was " << values[i];
+ ensure(str.str(), (*it).second == values[i]);
+ }
+
+ // Rewind, do non-consts
+ i = 0;
+ HttpHeaders::iterator end(headers->end());
+ for (HttpHeaders::iterator it(headers->begin());
+ end != it;
+ ++it, ++i)
+ {
+ std::ostringstream str;
+ str << "Const Iterator value # " << i << " was " << values[i];
+ ensure(str.str(), (*it).second == values[i]);
+ }
+ }
+
+ // release the implicit reference, causing the object to be released
+ headers->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+// Reverse iterators find everything as expected
+template <> template <>
+void HttpHeadersTestObjectType::test<6>()
+{
+ set_test_name("HttpHeaders reverse iterator tests");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpHeaders * headers = new HttpHeaders();
+
+ HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin());
+ ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin);
+ HttpHeaders::const_reverse_iterator crend(headers->rend()), crbegin(headers->rbegin());
+ ensure("Empty container has equal rbegin/rend const iterators", crend == crbegin);
+
+ {
+ static char line1[] = " AcCePT : image/yourfacehere";
+ static char line1v[] = "image/yourfacehere";
+ headers->appendNormal(line1, sizeof(line1) - 1);
+
+ static char line2[] = " next : \t\tlinejunk \t";
+ static char line2v[] = "linejunk \t";
+ headers->appendNormal(line2, sizeof(line2) - 1);
+
+ static char line3[] = "FancY-PANTs::plop:-neuf-=vleem=";
+ static char line3v[] = ":plop:-neuf-=vleem=";
+ headers->appendNormal(line3, sizeof(line3) - 1);
+
+ static char line4[] = "all-talk-no-walk:";
+ static char line4v[] = "";
+ headers->appendNormal(line4, sizeof(line4) - 1);
+
+ static char line5[] = ":all-talk-no-walk";
+ static char line5v[] = "all-talk-no-walk";
+ headers->appendNormal(line5, sizeof(line5) - 1);
+
+ static char line6[] = " :";
+ static char line6v[] = "";
+ headers->appendNormal(line6, sizeof(line6) - 1);
+
+ ensure("All entries accounted for", 6 == headers->size());
+
+ static char * values[] = {
+ line6v,
+ line5v,
+ line4v,
+ line3v,
+ line2v,
+ line1v
+ };
+
+ int i(0);
+ HttpHeaders::const_reverse_iterator cend(headers->rend());
+ for (HttpHeaders::const_reverse_iterator it(headers->rbegin());
+ cend != it;
+ ++it, ++i)
+ {
+ std::ostringstream str;
+ str << "Const Iterator value # " << i << " was " << values[i];
+ ensure(str.str(), (*it).second == values[i]);
+ }
+
+ // Rewind, do non-consts
+ i = 0;
+ HttpHeaders::reverse_iterator end(headers->rend());
+ for (HttpHeaders::reverse_iterator it(headers->rbegin());
+ end != it;
+ ++it, ++i)
+ {
+ std::ostringstream str;
+ str << "Iterator value # " << i << " was " << values[i];
+ ensure(str.str(), (*it).second == values[i]);
+ }
}
// release the implicit reference, causing the object to be released
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index e5488cf941..27d65f171e 100755
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -60,6 +60,8 @@ void usleep(unsigned long usec);
namespace tut
{
+typedef std::vector<std::pair<boost::regex, boost::regex> > regex_container_t;
+
struct HttpRequestTestData
{
// the test objects inherit from this so the member functions and variables
@@ -109,11 +111,17 @@ public:
for (int i(0); i < mHeadersRequired.size(); ++i)
{
bool found = false;
- for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin());
- header->mHeaders.end() != iter;
+ for (HttpHeaders::const_iterator iter(header->begin());
+ header->end() != iter;
++iter)
{
- if (boost::regex_match(*iter, mHeadersRequired[i]))
+ // std::cerr << "Header: " << (*iter).first
+ // << ": " << (*iter).second << std::endl;
+
+ if (boost::regex_match((*iter).first,
+ mHeadersRequired[i].first) &&
+ boost::regex_match((*iter).second,
+ mHeadersRequired[i].second))
{
found = true;
break;
@@ -129,11 +137,14 @@ public:
{
for (int i(0); i < mHeadersDisallowed.size(); ++i)
{
- for (HttpHeaders::container_t::const_iterator iter(header->mHeaders.begin());
- header->mHeaders.end() != iter;
+ for (HttpHeaders::const_iterator iter(header->begin());
+ header->end() != iter;
++iter)
{
- if (boost::regex_match(*iter, mHeadersDisallowed[i]))
+ if (boost::regex_match((*iter).first,
+ mHeadersDisallowed[i].first) &&
+ boost::regex_match((*iter).second,
+ mHeadersDisallowed[i].second))
{
std::ostringstream str;
str << "Disallowed header # " << i << " not found in response";
@@ -159,8 +170,8 @@ public:
std::string mName;
HttpHandle mExpectHandle;
std::string mCheckContentType;
- std::vector<boost::regex> mHeadersRequired;
- std::vector<boost::regex> mHeadersDisallowed;
+ regex_container_t mHeadersRequired;
+ regex_container_t mHeadersDisallowed;
};
typedef test_group<HttpRequestTestData> HttpRequestTestGroupType;
@@ -1335,7 +1346,9 @@ void HttpRequestTestObjectType::test<13>()
// Issue a GET that succeeds
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("\\W*X-LL-Special:.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(boost::regex("X-LL-Special", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base,
@@ -1702,18 +1715,54 @@ void HttpRequestTestObjectType::test<16>()
// Issue a GET that *can* connect
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("\\*/\\*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
@@ -1735,23 +1784,60 @@ void HttpRequestTestObjectType::test<16>()
// Do a texture-style fetch
headers = new HttpHeaders;
- headers->mHeaders.push_back("Accept: image/x-j2c");
+ headers->append("Accept", "image/x-j2c");
mStatus = HttpStatus(200);
handler.mHeadersRequired.clear();
handler.mHeadersDisallowed.clear();
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*image/x-j2c", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("\\W*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("image/x-j2c", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("\\W*X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
@@ -1892,20 +1978,63 @@ void HttpRequestTestObjectType::test<17>()
// Issue a default POST
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("\\*/\\*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-length", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex("application/x-www-form-urlencoded", boost::regex::icase)));
+
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-expect", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer_encoding", boost::regex::icase),
+ boost::regex(".*chunked.*", boost::regex::icase)));
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
@@ -2052,20 +2181,64 @@ void HttpRequestTestObjectType::test<18>()
// Issue a default PUT
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("\\*/\\*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-length", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-expect", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer-encoding", boost::regex::icase),
+ boost::regex(".*chunked.*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
@@ -2206,27 +2379,73 @@ void HttpRequestTestObjectType::test<19>()
// headers
headers = new HttpHeaders;
- headers->mHeaders.push_back("Keep-Alive: 120");
- headers->mHeaders.push_back("Accept-encoding: deflate");
- headers->mHeaders.push_back("Accept: text/plain");
+ headers->append("Keep-Alive", "120");
+ headers->append("Accept-encoding", "deflate");
+ headers->append("Accept", "text/plain");
// Issue a GET with modified headers
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/plain", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*deflate", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-type:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("text/plain", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("deflate", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("120", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("300", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("\\*/\\*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
@@ -2359,10 +2578,10 @@ void HttpRequestTestObjectType::test<20>()
// headers
headers = new HttpHeaders();
- headers->mHeaders.push_back("keep-Alive: 120");
- headers->mHeaders.push_back("Accept: text/html");
- headers->mHeaders.push_back("content-type: application/llsd+xml");
- headers->mHeaders.push_back("cache-control: no-store");
+ headers->append("keep-Alive", "120");
+ headers->append("Accept", "text/html");
+ headers->append("content-type", "application/llsd+xml");
+ headers->append("cache-control", "no-store");
// And a buffer array
const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>");
@@ -2371,23 +2590,76 @@ void HttpRequestTestObjectType::test<20>()
// Issue a default POST
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*text/html", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*120", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("\\s*X-Reflect-cache-control:\\s*no-store", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*application/x-www-form-urlencoded", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-keep-alive:\\s*300", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("text/html", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("120", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-length", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex("application/llsd\\+xml", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex("no-store", boost::regex::icase)));
+
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex("application/x-www-form-urlencoded", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("\\*/\\*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("300", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-expect", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+
HttpHandle handle = req->requestPost(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
@@ -2529,9 +2801,9 @@ void HttpRequestTestObjectType::test<21>()
// headers
headers = new HttpHeaders;
- headers->mHeaders.push_back("content-type: text/plain");
- headers->mHeaders.push_back("content-type: text/html");
- headers->mHeaders.push_back("content-type: application/llsd+xml");
+ headers->append("content-type", "text/plain");
+ headers->append("content-type", "text/html");
+ headers->append("content-type", "application/llsd+xml");
// And a buffer array
const char * msg("<xml><llsd><string>It was the best of times, it was the worst of times.</string></llsd></xml>");
@@ -2540,22 +2812,71 @@ void HttpRequestTestObjectType::test<21>()
// Issue a default PUT
mStatus = HttpStatus(200);
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-connection:\\s*keep-alive", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept:\\s*\\*/\\*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-accept-encoding:\\s*((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase)); // close enough
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-keep-alive:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-host:\\s*.*", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-length:\\s*\\d+", boost::regex::icase));
- handler.mHeadersRequired.push_back(boost::regex("X-Reflect-content-type:\\s*application/llsd\\+xml", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-cache-control:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-pragma:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-range:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-referer:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-content-encoding:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-expect:.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("\\s*X-Reflect-transfer-encoding:\\s*.*chunked.*", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/plain", boost::regex::icase));
- handler.mHeadersDisallowed.push_back(boost::regex("X-Reflect-content-type:\\s*text/html", boost::regex::icase));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-connection", boost::regex::icase),
+ boost::regex("keep-alive", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept", boost::regex::icase),
+ boost::regex("\\*/\\*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-accept-encoding", boost::regex::icase),
+ boost::regex("((gzip|deflate),\\s*)+(gzip|deflate)", boost::regex::icase))); // close enough
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-keep-alive", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-host", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-length", boost::regex::icase),
+ boost::regex("\\d+", boost::regex::icase)));
+ handler.mHeadersRequired.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex("application/llsd\\+xml", boost::regex::icase)));
+
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-cache-control", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-pragma", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-range", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-referer", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-expect", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-transfer-encoding", boost::regex::icase),
+ boost::regex(".*", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex("text/plain", boost::regex::icase)));
+ handler.mHeadersDisallowed.push_back(
+ regex_container_t::value_type(
+ boost::regex("X-Reflect-content-type", boost::regex::icase),
+ boost::regex("text/html", boost::regex::icase)));
HttpHandle handle = req->requestPut(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base + "reflect/",
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index fb2d43e3b0..b86e73c690 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -50,18 +50,21 @@ BOOL gSent = false;
class LLCrashLoggerResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLCrashLoggerResponder);
public:
LLCrashLoggerResponder()
{
}
- virtual void error(U32 status, const std::string& reason)
+protected:
+ virtual void httpFailure()
{
+ llwarns << dumpResponse() << llendl;
gBreak = true;
}
- virtual void result(const LLSD& content)
- {
+ virtual void httpSuccess()
+ {
gBreak = true;
gSent = true;
}
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index 41d58c6deb..6336d02f22 100755
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -50,6 +50,7 @@ static const std::string INV_DESC_LABEL("desc");
static const std::string INV_PERMISSIONS_LABEL("permissions");
static const std::string INV_SHADOW_ID_LABEL("shadow_id");
static const std::string INV_ASSET_ID_LABEL("asset_id");
+static const std::string INV_LINKED_ID_LABEL("linked_id");
static const std::string INV_SALE_INFO_LABEL("sale_info");
static const std::string INV_FLAGS_LABEL("flags");
static const std::string INV_CREATION_DATE_LABEL("created_at");
@@ -249,13 +250,6 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co
return TRUE;
}
-
-void LLInventoryObject::removeFromServer()
-{
- // don't do nothin'
- llwarns << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << llendl;
-}
-
void LLInventoryObject::updateParentOnServer(BOOL) const
{
// don't do nothin'
@@ -268,7 +262,7 @@ void LLInventoryObject::updateServer(BOOL) const
llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
}
-inline
+// static
void LLInventoryObject::correctInventoryName(std::string& name)
{
LLStringUtil::replaceNonstandardASCII(name, ' ');
@@ -423,12 +417,17 @@ U32 LLInventoryItem::getCRC32() const
return crc;
}
+// static
+void LLInventoryItem::correctInventoryDescription(std::string& desc)
+{
+ LLStringUtil::replaceNonstandardASCII(desc, ' ');
+ LLStringUtil::replaceChar(desc, '|', ' ');
+}
void LLInventoryItem::setDescription(const std::string& d)
{
std::string new_desc(d);
- LLStringUtil::replaceNonstandardASCII(new_desc, ' ');
- LLStringUtil::replaceChar(new_desc, '|', ' ');
+ LLInventoryItem::correctInventoryDescription(new_desc);
if( new_desc != mDescription )
{
mDescription = new_desc;
@@ -1050,11 +1049,16 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const
LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize");
-bool LLInventoryItem::fromLLSD(const LLSD& sd)
+bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
{
LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE);
- mInventoryType = LLInventoryType::IT_NONE;
- mAssetUUID.setNull();
+ if (is_new)
+ {
+ // If we're adding LLSD to an existing object, need avoid
+ // clobbering these fields.
+ mInventoryType = LLInventoryType::IT_NONE;
+ mAssetUUID.setNull();
+ }
std::string w;
w = INV_ITEM_ID_LABEL;
@@ -1111,6 +1115,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
{
mAssetUUID = sd[w];
}
+ w = INV_LINKED_ID_LABEL;
+ if (sd.has(w))
+ {
+ mAssetUUID = sd[w];
+ }
w = INV_ASSET_TYPE_LABEL;
if (sd.has(w))
{
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 99716ed7be..dd504fb155 100755
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -48,6 +48,7 @@ class LLInventoryObject : public LLRefCount
{
public:
typedef std::list<LLPointer<LLInventoryObject> > object_list_t;
+ typedef std::list<LLConstPointer<LLInventoryObject> > const_object_list_t;
//--------------------------------------------------------------------
// Initialization
@@ -86,22 +87,19 @@ public:
void setType(LLAssetType::EType type);
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
-private:
// in place correction for inventory name string
- void correctInventoryName(std::string& name);
+ static void correctInventoryName(std::string& name);
//--------------------------------------------------------------------
// File Support
// Implemented here so that a minimal information set can be transmitted
// between simulator and viewer.
//--------------------------------------------------------------------
-public:
// virtual BOOL importFile(LLFILE* fp);
virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const;
virtual BOOL importLegacyStream(std::istream& input_stream);
virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const;
- virtual void removeFromServer();
virtual void updateParentOnServer(BOOL) const;
virtual void updateServer(BOOL) const;
@@ -174,6 +172,7 @@ public:
//--------------------------------------------------------------------
public:
void setAssetUUID(const LLUUID& asset_id);
+ static void correctInventoryDescription(std::string& name);
void setDescription(const std::string& new_desc);
void setSaleInfo(const LLSaleInfo& sale_info);
void setPermissions(const LLPermissions& perm);
@@ -212,7 +211,7 @@ public:
void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
LLSD asLLSD() const;
void asLLSD( LLSD& sd ) const;
- bool fromLLSD(const LLSD& sd);
+ bool fromLLSD(const LLSD& sd, bool is_new = true);
//--------------------------------------------------------------------
// Member Variables
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index d193e367eb..d43ea5b2cb 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 f2a3e059ef..5cf935ca9f 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"
@@ -99,7 +100,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;
}
}
@@ -109,7 +110,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;
}
}
@@ -134,6 +135,7 @@ std::string LLCurl::getVersionString()
//////////////////////////////////////////////////////////////////////////////
LLCurl::Responder::Responder()
+ : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)
{
}
@@ -143,22 +145,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()
{
}
@@ -167,44 +177,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;
@@ -288,7 +363,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;
}
@@ -313,10 +389,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;
@@ -380,9 +460,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)
@@ -392,14 +472,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;
}
@@ -436,9 +517,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)
@@ -526,8 +629,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)
@@ -806,7 +910,7 @@ S32 LLCurl::Multi::process()
++processed;
if (msg->msg == CURLMSG_DONE)
{
- U32 response = 0;
+ S32 response = 0;
Easy* easy = NULL ;
{
@@ -825,7 +929,7 @@ S32 LLCurl::Multi::process()
}
else
{
- response = 499;
+ response = HTTP_INTERNAL_ERROR;
//*TODO: change to llwarns
llerrs << "cleaned up curl request completed!" << llendl;
}
@@ -1124,13 +1228,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);
@@ -1157,7 +1261,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;
@@ -1185,7 +1289,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;
@@ -1557,6 +1661,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 6110b035dc..70c890a8de 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,90 +239,83 @@ 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 req;
delete body_injector;
- return ;
+ return;
}
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
-
- lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
- << headers << llendl;
+
+ LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL;
// Insert custom headers if the caller sent any
if (headers.isMap())
{
- if (headers.has("Cookie"))
+ if (headers.has(HTTP_OUT_HEADER_COOKIE))
{
req->allowCookies();
}
- LLSD::map_const_iterator iter = headers.beginMap();
- LLSD::map_const_iterator end = headers.endMap();
-
- for (; iter != end; ++iter)
- {
- std::ostringstream header;
- //if the header is "Pragma" with no value
- //the caller intends to force libcurl to drop
- //the Pragma header it so gratuitously inserts
- //Before inserting the header, force libcurl
- //to not use the proxy (read: llurlrequest.cpp)
- static const std::string PRAGMA("Pragma");
- if ((iter->first == PRAGMA) && (iter->second.asString().empty()))
- {
- req->useProxy(false);
- }
- header << iter->first << ": " << iter->second.asString() ;
- lldebugs << "header = " << header.str() << llendl;
- req->addHeader(header.str().c_str());
- }
- }
+ LLSD::map_const_iterator iter = headers.beginMap();
+ LLSD::map_const_iterator end = headers.endMap();
+
+ for (; iter != end; ++iter)
+ {
+ //if the header is "Pragma" with no value
+ //the caller intends to force libcurl to drop
+ //the Pragma header it so gratuitously inserts
+ //Before inserting the header, force libcurl
+ //to not use the proxy (read: llurlrequest.cpp)
+ if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty()))
+ {
+ req->useProxy(false);
+ }
+ LL_DEBUGS("LLHTTPClient") << "header = " << iter->first
+ << ": " << iter->second.asString() << LL_ENDL;
+ req->addHeader(iter->first, iter->second.asString());
+ }
+ }
// Check to see if we have already set Accept or not. If no one
// set it, set it to application/llsd+xml since that's what we
// almost always want.
- if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST )
+ if( method != HTTP_PUT && method != HTTP_POST )
{
- static const std::string ACCEPT("Accept");
- if(!headers.has(ACCEPT))
+ if(!headers.has(HTTP_OUT_HEADER_ACCEPT))
{
- req->addHeader("Accept: application/llsd+xml");
+ req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
}
}
if (responder)
{
responder->setURL(url);
+ responder->setHTTPMethod(method);
}
req->setCallback(new LLHTTPClientURLAdaptor(responder));
- if (method == LLURLRequest::HTTP_POST && gMessageSystem)
+ if (method == HTTP_POST && gMessageSystem)
{
- req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d",
- gMessageSystem->mPort).c_str());
- }
+ req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d",
+ gMessageSystem->mPort));
+ }
- if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST)
+ if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)
{
- static const std::string CONTENT_TYPE("Content-Type");
- if(!headers.has(CONTENT_TYPE))
+ if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE))
{
// If the Content-Type header was passed in, it has
// already been added as a header through req->addHeader
// in the loop above. We defer to the caller's wisdom, but
// if they did not specify a Content-Type, then ask the
// injector.
- req->addHeader(
- llformat(
- "Content-Type: %s",
- body_injector->contentType()).c_str());
+ req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType());
}
- chain.push_back(LLIOPipe::ptr_t(body_injector));
+ chain.push_back(LLIOPipe::ptr_t(body_injector));
}
chain.push_back(LLIOPipe::ptr_t(req));
@@ -340,9 +336,9 @@ void LLHTTPClient::getByteRange(
if(offset > 0 || bytes > 0)
{
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
- headers["Range"] = range;
+ headers[HTTP_OUT_HEADER_RANGE] = range;
}
- request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
+ request(url,HTTP_GET, NULL, responder, timeout, headers);
}
void LLHTTPClient::head(
@@ -351,16 +347,16 @@ void LLHTTPClient::head(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
+ request(url, HTTP_HEAD, NULL, responder, timeout, headers);
}
void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
{
- request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
+ request(url, HTTP_GET, NULL, responder, timeout, headers);
}
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout)
{
- request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers);
+ request(url, HTTP_HEAD, NULL, responder, timeout, headers);
}
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout)
{
@@ -401,7 +397,7 @@ public:
return content;
}
- std::string asString()
+ const std::string& asString()
{
return mBuffer;
}
@@ -430,7 +426,7 @@ private:
*/
static LLSD blocking_request(
const std::string& url,
- LLURLRequest::ERequestAction method,
+ EHTTPMethod method,
const LLSD& body,
const LLSD& headers = LLSD(),
const F32 timeout = 5
@@ -473,11 +469,11 @@ static LLSD blocking_request(
}
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
- if (method == LLURLRequest::HTTP_GET)
+ if (method == HTTP_GET)
{
curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
}
- else if (method == LLURLRequest::HTTP_POST)
+ else if (method == HTTP_POST)
{
curl_easy_setopt(curlp, CURLOPT_POST, 1);
//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
@@ -486,18 +482,20 @@ static LLSD blocking_request(
body_str = ostr.str();
curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());
//copied from PHP libs, correct?
- headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml");
+ headers_list = curl_slist_append(headers_list,
+ llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
// copied from llurlrequest.cpp
// it appears that apache2.2.3 or django in etch is busted. If
// we do not clear the expect header, we get a 500. May be
// limited to django/mod_wsgi.
- headers_list = curl_slist_append(headers_list, "Expect:");
+ headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str());
}
// * Do the action using curl, handle results
lldebugs << "HTTP body: " << body_str << llendl;
- headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml");
+ headers_list = curl_slist_append(headers_list,
+ llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());
CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);
if ( curl_result != CURLE_OK )
{
@@ -506,11 +504,11 @@ static LLSD blocking_request(
LLSD response = LLSD::emptyMap();
S32 curl_success = curl_easy_perform(curlp);
- S32 http_status = 499;
+ S32 http_status = HTTP_INTERNAL_ERROR;
curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);
response["status"] = http_status;
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
- if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
+ if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) )
{
// We expect 404s, don't spam for them.
llwarns << "CURL REQ URL: " << url << llendl;
@@ -540,12 +538,12 @@ static LLSD blocking_request(
LLSD LLHTTPClient::blockingGet(const std::string& url)
{
- return blocking_request(url, LLURLRequest::HTTP_GET, LLSD());
+ return blocking_request(url, HTTP_GET, LLSD());
}
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
{
- return blocking_request(url, LLURLRequest::HTTP_POST, body);
+ return blocking_request(url, HTTP_POST, body);
}
void LLHTTPClient::put(
@@ -555,7 +553,17 @@ void LLHTTPClient::put(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
+ request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
+}
+
+void LLHTTPClient::patch(
+ const std::string& url,
+ const LLSD& body,
+ ResponderPtr responder,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers);
}
void LLHTTPClient::post(
@@ -565,7 +573,7 @@ void LLHTTPClient::post(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
+ request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
}
void LLHTTPClient::postRaw(
@@ -576,7 +584,7 @@ void LLHTTPClient::postRaw(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
+ request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
}
void LLHTTPClient::postFile(
@@ -586,7 +594,7 @@ void LLHTTPClient::postFile(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers);
+ request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers);
}
void LLHTTPClient::postFile(
@@ -597,7 +605,7 @@ void LLHTTPClient::postFile(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
+ request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
}
// static
@@ -607,7 +615,7 @@ void LLHTTPClient::del(
const LLSD& headers,
const F32 timeout)
{
- request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers);
+ request(url, HTTP_DELETE, NULL, responder, timeout, headers);
}
// static
@@ -619,8 +627,21 @@ 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);
+}
+
+// static
+void LLHTTPClient::copy(
+ const std::string& url,
+ const std::string& destination,
+ ResponderPtr responder,
+ const LLSD& hdrs,
+ const F32 timeout)
+{
+ LLSD headers = hdrs;
+ headers[HTTP_OUT_HEADER_DESTINATION] = destination;
+ request(url, HTTP_COPY, NULL, responder, timeout, headers);
}
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
index a7236ba169..5ace2d74c9 100755
--- a/indra/llmessage/llhttpclient.h
+++ b/indra/llmessage/llhttpclient.h
@@ -74,6 +74,14 @@ public:
ResponderPtr,
const LLSD& headers = LLSD(),
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
+ static void patch(
+ const std::string& url,
+ const LLSD& body,
+ ResponderPtr,
+ const LLSD& headers = LLSD(),
+ const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
@@ -111,7 +119,7 @@ public:
const LLSD& headers = LLSD(),
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
///< sends a DELETE method, but we can't call it delete in c++
-
+
/**
* @brief Send a MOVE webdav method
*
@@ -128,6 +136,22 @@ public:
const LLSD& headers = LLSD(),
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+ /**
+ * @brief Send a COPY webdav method
+ *
+ * @param url The complete serialized (and escaped) url to get.
+ * @param destination The complete serialized destination url.
+ * @param responder The responder that will handle the result.
+ * @param headers A map of key:value headers to pass to the request
+ * @param timeout The number of seconds to give the server to respond.
+ */
+ static void copy(
+ const std::string& url,
+ const std::string& destination,
+ ResponderPtr responder,
+ const LLSD& headers = LLSD(),
+ const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
//@}
/**
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
index dcd2d79d67..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"] = " ";
+ // as above
+ 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..01f4a080b0
--- /dev/null
+++ b/indra/llmessage/llhttpconstants.cpp
@@ -0,0 +1,228 @@
+/**
+ * @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 HTTP_VERB_PATCH("PATCH");
+const std::string HTTP_VERB_COPY("COPY");
+
+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,
+ HTTP_VERB_PATCH,
+ HTTP_VERB_COPY
+ };
+ if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))
+ {
+ return VERBS[0];
+ }
+ return VERBS[method];
+}
+
+bool isHttpInformationalStatus(S32 status)
+{
+ // Check for status 1xx.
+ return((100 <= status) && (status < 200));
+}
+
+bool isHttpGoodStatus(S32 status)
+{
+ // Check for status 2xx.
+ return((200 <= status) && (status < 300));
+}
+
+bool isHttpRedirectStatus(S32 status)
+{
+ // Check for status 3xx.
+ return((300 <= status) && (status < 400));
+}
+
+bool isHttpClientErrorStatus(S32 status)
+{
+ // Status 499 is sometimes used for re-interpreted status 2xx errors
+ // based on body content. Treat these as potentially retryable 'server' status errors,
+ // since we do not have enough context to know if this will always fail.
+ if (HTTP_INTERNAL_ERROR == status) return false;
+
+ // Check for status 5xx.
+ return((400 <= status) && (status < 500));
+}
+
+bool isHttpServerErrorStatus(S32 status)
+{
+ // Status 499 is sometimes used for re-interpreted status 2xx errors.
+ // Allow retry of these, since we don't have enough information in this
+ // context to know if this will always fail.
+ if (HTTP_INTERNAL_ERROR == status) return true;
+
+ // Check for status 5xx.
+ return((500 <= status) && (status < 600));
+}
+
+// Parses 'Retry-After' header contents and returns seconds until retry should occur.
+bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait)
+{
+ // *TODO: This needs testing! Not in use yet.
+ // Examples of Retry-After headers:
+ // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+ // Retry-After: 120
+
+ // Check for number of seconds version, first:
+ char* end = 0;
+ // Parse as double
+ double seconds = std::strtod(retry_after.c_str(), &end);
+ if ( end != 0 && *end == 0 )
+ {
+ // Successful parse
+ seconds_to_wait = (F32) seconds;
+ return true;
+ }
+
+ // Parse rfc1123 date.
+ time_t date = curl_getdate(retry_after.c_str(), NULL );
+ if (-1 == date) return false;
+
+ seconds_to_wait = (F64)date - LLTimer::getTotalSeconds();
+
+ return true;
+}
+
diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h
new file mode 100755
index 0000000000..4aa3cc6394
--- /dev/null
+++ b/indra/llmessage/llhttpconstants.h
@@ -0,0 +1,225 @@
+/**
+ * @file llhttpconstants.h
+ * @brief Constants for HTTP requests and responses
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2001-2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_HTTP_CONSTANTS_H
+#define LL_HTTP_CONSTANTS_H
+
+#include "stdtypes.h"
+
+/////// HTTP STATUS CODES ///////
+
+// Standard errors from HTTP spec:
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
+const S32 HTTP_CONTINUE = 100;
+const S32 HTTP_SWITCHING_PROTOCOLS = 101;
+
+// Success
+const S32 HTTP_OK = 200;
+const S32 HTTP_CREATED = 201;
+const S32 HTTP_ACCEPTED = 202;
+const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
+const S32 HTTP_NO_CONTENT = 204;
+const S32 HTTP_RESET_CONTENT = 205;
+const S32 HTTP_PARTIAL_CONTENT = 206;
+
+// Redirection
+const S32 HTTP_MULTIPLE_CHOICES = 300;
+const S32 HTTP_MOVED_PERMANENTLY = 301;
+const S32 HTTP_FOUND = 302;
+const S32 HTTP_SEE_OTHER = 303;
+const S32 HTTP_NOT_MODIFIED = 304;
+const S32 HTTP_USE_PROXY = 305;
+const S32 HTTP_TEMPORARY_REDIRECT = 307;
+
+// Client Error
+const S32 HTTP_BAD_REQUEST = 400;
+const S32 HTTP_UNAUTHORIZED = 401;
+const S32 HTTP_PAYMENT_REQUIRED = 402;
+const S32 HTTP_FORBIDDEN = 403;
+const S32 HTTP_NOT_FOUND = 404;
+const S32 HTTP_METHOD_NOT_ALLOWED = 405;
+const S32 HTTP_NOT_ACCEPTABLE = 406;
+const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
+const S32 HTTP_REQUEST_TIME_OUT = 408;
+const S32 HTTP_CONFLICT = 409;
+const S32 HTTP_GONE = 410;
+const S32 HTTP_LENGTH_REQUIRED = 411;
+const S32 HTTP_PRECONDITION_FAILED = 412;
+const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
+const S32 HTTP_REQUEST_URI_TOO_LARGE = 414;
+const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
+const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+const S32 HTTP_EXPECTATION_FAILED = 417;
+
+// Server Error
+const S32 HTTP_INTERNAL_SERVER_ERROR = 500;
+const S32 HTTP_NOT_IMPLEMENTED = 501;
+const S32 HTTP_BAD_GATEWAY = 502;
+const S32 HTTP_SERVICE_UNAVAILABLE = 503;
+const S32 HTTP_GATEWAY_TIME_OUT = 504;
+const S32 HTTP_VERSION_NOT_SUPPORTED = 505;
+
+// We combine internal process errors with status codes
+// These status codes should not be sent over the wire
+// and indicate something went wrong internally.
+// If you get these they are not normal.
+const S32 HTTP_INTERNAL_CURL_ERROR = 498;
+const S32 HTTP_INTERNAL_ERROR = 499;
+
+
+////// HTTP Methods //////
+
+extern const std::string HTTP_VERB_INVALID;
+extern const std::string HTTP_VERB_HEAD;
+extern const std::string HTTP_VERB_GET;
+extern const std::string HTTP_VERB_PUT;
+extern const std::string HTTP_VERB_POST;
+extern const std::string HTTP_VERB_DELETE;
+extern const std::string HTTP_VERB_MOVE;
+extern const std::string HTTP_VERB_OPTIONS;
+
+enum EHTTPMethod
+{
+ HTTP_INVALID = 0,
+ HTTP_HEAD,
+ HTTP_GET,
+ HTTP_PUT,
+ HTTP_POST,
+ HTTP_DELETE,
+ HTTP_MOVE, // Caller will need to set 'Destination' header
+ HTTP_OPTIONS,
+ HTTP_PATCH,
+ HTTP_COPY,
+ 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 de9e2fe294..d6448e83fe 100755
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -40,7 +40,6 @@
#include "llstring.h"
#include "apr_env.h"
#include "llapr.h"
-static const U32 HTTP_STATUS_PIPE_ERROR = 499;
/**
* String constants
@@ -48,11 +47,12 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
+// These are defined in llhttpnode.h/llhttpnode.cpp
+extern const std::string CONTEXT_REQUEST;
+extern const std::string CONTEXT_RESPONSE;
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
-
-
/**
* class LLURLRequestDetail
*/
@@ -130,34 +130,15 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
* class LLURLRequest
*/
-// static
-std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
-{
- static const std::string VERBS[] =
- {
- "(invalid)",
- "HEAD",
- "GET",
- "PUT",
- "POST",
- "DELETE",
- "MOVE"
- };
- if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT))
- {
- return VERBS[0];
- }
- return VERBS[action];
-}
-LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
+LLURLRequest::LLURLRequest(EHTTPMethod action) :
mAction(action)
{
initialize();
}
LLURLRequest::LLURLRequest(
- LLURLRequest::ERequestAction action,
+ EHTTPMethod action,
const std::string& url) :
mAction(action)
{
@@ -180,12 +161,17 @@ void LLURLRequest::setURL(const std::string& url)
}
}
-std::string LLURLRequest::getURL() const
+const std::string& LLURLRequest::getURL() const
{
return mDetail->mURL;
}
-void LLURLRequest::addHeader(const char* header)
+void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */)
+{
+ mDetail->mCurlRequest->slist_append(header, value);
+}
+
+void LLURLRequest::addHeaderRaw(const char* header)
{
mDetail->mCurlRequest->slist_append(header);
}
@@ -272,7 +258,7 @@ LLIOPipe::EStatus LLURLRequest::handleError(
LLURLRequestComplete* complete = NULL;
complete = (LLURLRequestComplete*)mCompletionCallback.get();
complete->httpStatus(
- HTTP_STATUS_PIPE_ERROR,
+ HTTP_INTERNAL_ERROR,
LLIOPipe::lookupStatusString(status));
complete->responseStatus(status);
pump->respond(complete);
@@ -494,21 +480,32 @@ bool LLURLRequest::configure()
case HTTP_PUT:
// Disable the expect http 1.1 extension. POST and PUT default
// to turning this on, and I am not too sure what it means.
- addHeader("Expect:");
+ addHeader(HTTP_OUT_HEADER_EXPECT);
+
+ mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
+ mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
+ rv = true;
+ break;
+
+ case HTTP_PATCH:
+ // Disable the expect http 1.1 extension. POST and PUT default
+ // to turning this on, and I am not too sure what it means.
+ addHeader(HTTP_OUT_HEADER_EXPECT);
mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
+ mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH");
rv = true;
break;
case HTTP_POST:
// Disable the expect http 1.1 extension. POST and PUT default
// to turning this on, and I am not too sure what it means.
- addHeader("Expect:");
+ addHeader(HTTP_OUT_HEADER_EXPECT);
// Disable the content type http header.
// *FIX: what should it be?
- addHeader("Content-Type:");
+ addHeader(HTTP_OUT_HEADER_CONTENT_TYPE);
// Set the handle for an http post
mDetail->mCurlRequest->setPost(NULL, bytes);
@@ -519,13 +516,19 @@ bool LLURLRequest::configure()
break;
case HTTP_DELETE:
- // Set the handle for an http post
+ // Set the handle for an http delete
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
rv = true;
break;
+ case HTTP_COPY:
+ // Set the handle for an http copy
+ mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY");
+ rv = true;
+ break;
+
case HTTP_MOVE:
- // Set the handle for an http post
+ // Set the handle for an http move
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
// *NOTE: should we check for the Destination header?
rv = true;
@@ -638,7 +641,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 559001d079..a32bfa59ce 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 c3005f1722..5bee3735eb 100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -605,6 +605,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 273ceb4038..8919af32ec 100755
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1611,7 +1611,7 @@ void LLFloater::bringToFront( S32 x, S32 y )
// virtual
-void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key)
+void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key)
{
LLMultiFloater* hostp = getHost();
if (hostp)
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 3482314698..71979bd95a 100755
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -306,7 +306,7 @@ public:
/*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override
void setFrontmost(BOOL take_focus = TRUE);
- virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
+ virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
// Defaults to false.
virtual BOOL canSaveAs() const { return FALSE; }
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 3a09bc530c..7e50e761ae 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -99,6 +99,7 @@ include_directories(SYSTEM
set(viewer_SOURCE_FILES
groupchatlistener.cpp
llaccountingcostmanager.cpp
+ llaisapi.cpp
llagent.cpp
llagentaccess.cpp
llagentcamera.cpp
@@ -306,6 +307,7 @@ set(viewer_SOURCE_FILES
llhasheduniqueid.cpp
llhints.cpp
llhomelocationresponder.cpp
+ llhttpretrypolicy.cpp
llhudeffect.cpp
llhudeffectbeam.cpp
llhudeffectlookat.cpp
@@ -682,6 +684,7 @@ set(viewer_HEADER_FILES
ViewerInstall.cmake
groupchatlistener.h
llaccountingcostmanager.h
+ llaisapi.h
llagent.h
llagentaccess.h
llagentcamera.h
@@ -888,6 +891,7 @@ set(viewer_HEADER_FILES
llgroupmgr.h
llhasheduniqueid.h
llhints.h
+ llhttpretrypolicy.h
llhomelocationresponder.h
llhudeffect.h
llhudeffectbeam.h
@@ -2148,10 +2152,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(
@@ -2232,6 +2247,7 @@ if (LL_TESTS)
set(test_libs
${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${WINDOWS_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
@@ -2277,6 +2293,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 72fe21cf14..501552664a 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11422,6 +11422,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/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index e5b385f4aa..e28bb6969a 100755
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -7563,7 +7563,7 @@ render_pass="bump">
<param
id="868"
- group="0"
+ group="3"
wearable="shirt"
edit_group="shirt"
edit_group_order="8"
@@ -8686,7 +8686,7 @@ render_pass="bump">
<param
id="869"
- group="0"
+ group="3"
wearable="pants"
edit_group="pants"
edit_group_order="6"
@@ -9607,7 +9607,7 @@ render_pass="bump">
<param
id="163"
- group="0"
+ group="3"
wearable="skin"
edit_group="skin_facedetail"
edit_group_order="3"
@@ -11666,7 +11666,7 @@ render_pass="bump">
<param
id="877"
- group="0"
+ group="3"
name="Jacket Wrinkles"
label="Jacket Wrinkles"
wearable="jacket"
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 f4ce3c9118..5f87d73c40 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -2537,17 +2537,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;
@@ -2566,39 +2568,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())
{
@@ -2744,7 +2750,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
{
@@ -2754,7 +2760,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
@@ -3253,8 +3259,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"];
@@ -3323,8 +3328,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"));
}
}
};
@@ -4303,7 +4307,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
@@ -4344,7 +4348,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"
@@ -4424,7 +4430,8 @@ void LLAgent::sendAgentSetAppearance()
param;
param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam())
{
- if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ||
+ param->getGroup() == VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
{
msg->nextBlockFast(_PREHASH_VisualParam );
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 1edbbe2a2e..8501436b5b 100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -62,15 +62,15 @@ using namespace LLAvatarAppearanceDefines;
// Callback to wear and start editing an item that has just been created.
void wear_and_edit_cb(const LLUUID& inv_item)
- {
- if (inv_item.isNull()) return;
-
- // Request editing the item after it gets worn.
- gAgentWearables.requestEditingWearable(inv_item);
-
- // Wear it.
- LLAppearanceMgr::instance().wearItemOnAvatar(inv_item);
- }
+{
+ if (inv_item.isNull()) return;
+
+ // Request editing the item after it gets worn.
+ gAgentWearables.requestEditingWearable(inv_item);
+
+ // Wear it.
+ LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true);
+}
///////////////////////////////////////////////////////////////////////////////
@@ -180,10 +180,10 @@ void LLAgentWearables::initClass()
}
void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
-{
+{
llassert(avatar);
- avatar->outputRezTiming("Sending wearables request");
- sendAgentWearablesRequest();
+ avatar->outputRezTiming("Sending wearables request");
+ sendAgentWearablesRequest();
setAvatarAppearance(avatar);
}
@@ -209,7 +209,7 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal
* @param wearable The wearable data.
* @param todo Bitmask of actions to take on completion.
*/
-LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
+LLAgentWearables::AddWearableToAgentInventoryCallback::AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) :
mType(type),
mIndex(index),
@@ -221,7 +221,7 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento
llinfos << "constructor" << llendl;
}
-void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
+void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
{
if (mTodo & CALL_CREATESTANDARDDONE)
{
@@ -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);
}
}
@@ -316,12 +317,12 @@ void LLAgentWearables::sendAgentWearablesUpdate()
if (wearable->getItemID().isNull())
{
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
(LLWearableType::EType)type,
index,
wearable,
- addWearableToAgentInventoryCallback::CALL_NONE);
+ AddWearableToAgentInventoryCallback::CALL_NONE);
addWearableToAgentInventory(cb, wearable);
}
else
@@ -418,23 +419,18 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32
item->getFlags(),
item->getCreationDate());
template_item->setTransactionID(new_wearable->getTransactionID());
- template_item->updateServer(FALSE);
- gInventory.updateItem(template_item);
- if (name_changed)
- {
- gInventory.notifyObservers();
- }
+ update_inventory_item(template_item, gAgentAvatarp->mEndCustomizeCallback);
}
else
{
// Add a new inventory item (shouldn't ever happen here)
- U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
+ U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;
if (send_update)
{
- todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
+ todo |= AddWearableToAgentInventoryCallback::CALL_UPDATE;
}
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
type,
index,
@@ -483,12 +479,12 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type,
old_wearable,
trunc_name);
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
type,
index,
new_wearable,
- addWearableToAgentInventoryCallback::CALL_WEARITEM,
+ AddWearableToAgentInventoryCallback::CALL_WEARITEM,
description
);
LLUUID category_id;
@@ -706,7 +702,7 @@ LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::ETyp
}
const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) const
- {
+{
return dynamic_cast<const LLViewerWearable*> (getWearable(type, index));
}
@@ -714,39 +710,39 @@ const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType
BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type)
{
return (gAgentWearables.getWearableCount(type) > 0);
- }
-
+}
+
// virtual
void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
- {
+{
if (isAgentAvatarValid())
{
const BOOL upload_result = removed;
gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result);
-}
+ }
LLWearableData::wearableUpdated(wearable, removed);
if (!removed)
-{
+ {
LLViewerWearable* viewer_wearable = dynamic_cast<LLViewerWearable*>(wearable);
viewer_wearable->refreshName();
- // Hack pt 2. If the wearable we just loaded has definition version 24,
- // then force a re-save of this wearable after slamming the version number to 22.
- // This number was incorrectly incremented for internal builds before release, and
- // this fix will ensure that the affected wearables are re-saved with the right version number.
- // the versions themselves are compatible. This code can be removed before release.
- if( wearable->getDefinitionVersion() == 24 )
- {
- wearable->setDefinitionVersion(22);
- U32 index = getWearableIndex(wearable);
+ // Hack pt 2. If the wearable we just loaded has definition version 24,
+ // then force a re-save of this wearable after slamming the version number to 22.
+ // This number was incorrectly incremented for internal builds before release, and
+ // this fix will ensure that the affected wearables are re-saved with the right version number.
+ // the versions themselves are compatible. This code can be removed before release.
+ if( wearable->getDefinitionVersion() == 24 )
+ {
+ wearable->setDefinitionVersion(22);
+ U32 index = getWearableIndex(wearable);
llinfos << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << llendl;
- saveWearable(wearable->getType(),index,TRUE);
- }
+ saveWearable(wearable->getType(),index,TRUE);
+ }
checkWearableAgainstInventory(viewer_wearable);
-}
+ }
}
BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const
@@ -908,12 +904,12 @@ void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type,
// destory content.) JC
const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
type,
index,
new_wearable,
- addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
+ AddWearableToAgentInventoryCallback::CALL_RECOVERDONE);
addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE);
}
@@ -956,17 +952,17 @@ public:
/* virtual */ void fire(const LLUUID& inv_item)
{
llinfos << "One item created " << inv_item.asString() << llendl;
- LLViewerInventoryItem *item = gInventory.getItem(inv_item);
- mItemsToLink.put(item);
+ LLConstPointer<LLInventoryObject> item = gInventory.getItem(inv_item);
+ mItemsToLink.push_back(item);
updatePendingWearable(inv_item);
}
~OnWearableItemCreatedCB()
{
llinfos << "All items created" << llendl;
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
- LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(),
- mItemsToLink,
- link_waiter);
+ link_inventory_array(LLAppearanceMgr::instance().getCOF(),
+ mItemsToLink,
+ link_waiter);
}
void addPendingWearable(LLViewerWearable *wearable)
{
@@ -1015,7 +1011,7 @@ public:
}
private:
- LLInventoryModel::item_array_t mItemsToLink;
+ LLInventoryObject::const_object_list_t mItemsToLink;
std::vector<LLViewerWearable*> mWearablesAwaitingItems;
};
@@ -1234,30 +1230,86 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
// Assumes existing wearables are not dirty.
void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items,
- const LLDynamicArray< LLViewerWearable* >& wearables,
- BOOL remove)
+ const LLDynamicArray< LLViewerWearable* >& wearables)
{
llinfos << "setWearableOutfit() start" << llendl;
+ S32 count = wearables.count();
+ llassert(items.count() == count);
+
+ // Check for whether outfit already matches the one requested
+ S32 matched = 0, mismatched = 0;
+ const S32 arr_size = LLWearableType::WT_COUNT;
+ S32 type_counts[arr_size];
+ std::fill(type_counts,type_counts+arr_size,0);
+ for (S32 i = 0; i < count; i++)
+ {
+ LLViewerWearable* new_wearable = wearables[i];
+ LLPointer<LLInventoryItem> new_item = items[i];
+
+ const LLWearableType::EType type = new_wearable->getType();
+ if (type < 0 || type>=LLWearableType::WT_COUNT)
+ {
+ llwarns << "invalid type " << type << llendl;
+ mismatched++;
+ continue;
+ }
+ S32 index = type_counts[type];
+ type_counts[type]++;
+
+ LLViewerWearable *curr_wearable = dynamic_cast<LLViewerWearable*>(getWearable(type,index));
+ if (!new_wearable || !curr_wearable ||
+ new_wearable->getAssetID() != curr_wearable->getAssetID())
+ {
+ LL_DEBUGS("Avatar") << "mismatch, type " << type << " index " << index
+ << " names " << (curr_wearable ? curr_wearable->getName() : "NONE") << ","
+ << " names " << (new_wearable ? new_wearable->getName() : "NONE") << llendl;
+ mismatched++;
+ continue;
+ }
+
+ if (curr_wearable->getName() != new_item->getName() ||
+ curr_wearable->getItemID() != new_item->getUUID())
+ {
+ LL_DEBUGS("Avatar") << "mismatch on name or inventory id, names "
+ << curr_wearable->getName() << " vs " << new_item->getName()
+ << " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID()
+ << llendl;
+ mismatched++;
+ continue;
+ }
+ // If we got here, everything matches.
+ matched++;
+ }
+ LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << llendl;
+ for (S32 j=0; j<LLWearableType::WT_COUNT; j++)
+ {
+ LLWearableType::EType type = (LLWearableType::EType) j;
+ if (getWearableCount(type) != type_counts[j])
+ {
+ LL_DEBUGS("Avatar") << "count mismatch for type " << j << " current " << getWearableCount(j) << " requested " << type_counts[j] << llendl;
+ mismatched++;
+ }
+ }
+ if (mismatched == 0)
+ {
+ LL_DEBUGS("Avatar") << "no changes, bailing out" << llendl;
+ return;
+ }
+
+
// TODO: Removed check for ensuring that teens don't remove undershirt and underwear. Handle later
- if (remove)
+ // note: shirt is the first non-body part wearable item. Update if wearable order changes.
+ // This loop should remove all clothing, but not any body parts
+ for (S32 j = 0; j < (S32)LLWearableType::WT_COUNT; j++)
{
- // note: shirt is the first non-body part wearable item. Update if wearable order changes.
- // This loop should remove all clothing, but not any body parts
- for (S32 type = 0; type < (S32)LLWearableType::WT_COUNT; type++)
+ if (LLWearableType::getAssetType((LLWearableType::EType)j) == LLAssetType::AT_CLOTHING)
{
- if (LLWearableType::getAssetType((LLWearableType::EType)type) == LLAssetType::AT_CLOTHING)
- {
- removeWearable((LLWearableType::EType)type, true, 0);
- }
+ removeWearable((LLWearableType::EType)j, true, 0);
}
}
- S32 count = wearables.count();
- llassert(items.count() == count);
-
- S32 i;
- for (i = 0; i < count; i++)
+ for (S32 i = 0; i < count; i++)
{
LLViewerWearable* new_wearable = wearables[i];
LLPointer<LLInventoryItem> new_item = items[i];
@@ -1311,7 +1363,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
gAgentAvatarp->dumpAvatarTEs("setWearableOutfit");
- lldebugs << "setWearableOutfit() end" << llendl;
+ LL_DEBUGS("Avatar") << "setWearableOutfit() end" << llendl;
}
@@ -1442,6 +1494,7 @@ void LLAgentWearables::queryWearableCache()
{
return;
}
+ gAgentAvatarp->setIsUsingServerBakes(false);
// Look up affected baked textures.
// If they exist:
@@ -1496,12 +1549,12 @@ void LLAgentWearables::queryWearableCache()
// virtual
void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const
{
- // Add some garbage into the hash so that it becomes invalid.
- if (isAgentAvatarValid())
- {
- hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
- }
- }
+ // Add some garbage into the hash so that it becomes invalid.
+ if (isAgentAvatarValid())
+ {
+ hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
+ }
+}
// User has picked "remove from avatar" from a menu.
// static
@@ -1860,24 +1913,6 @@ void LLAgentWearables::updateServer()
gAgent.sendAgentSetAppearance();
}
-void LLAgentWearables::populateMyOutfitsFolder(void)
-{
- llinfos << "starting outfit population" << llendl;
-
- const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(my_outfits_id);
- outfits->mMyOutfitsID = my_outfits_id;
-
- // Get the complete information on the items in the inventory and
- // setup an observer that will wait for that to happen.
- gInventory.addObserver(outfits);
- outfits->startFetch();
- if (outfits->isFinished())
- {
- outfits->done();
- }
-}
-
boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb)
{
return mLoadingStartedSignal.connect(cb);
@@ -1896,6 +1931,7 @@ bool LLAgentWearables::changeInProgress() const
void LLAgentWearables::notifyLoadingStarted()
{
mCOFChangeInProgress = true;
+ mCOFChangeTimer.reset();
mLoadingStartedSignal();
}
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 5be4648636..96fe4b80c0 100755
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -77,6 +77,7 @@ public:
BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const;
BOOL areWearablesLoaded() const;
bool isCOFChangeInProgress() const { return mCOFChangeInProgress; }
+ F32 getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); }
void updateWearablesLoaded();
void checkWearablesLoaded() const;
bool canMoveWearable(const LLUUID& item_id, bool closer_to_body) const;
@@ -107,7 +108,7 @@ private:
/*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed);
public:
void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false);
- void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLViewerWearable* >& wearables, BOOL remove);
+ void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLViewerWearable* >& wearables);
void setWearableName(const LLUUID& item_id, const std::string& new_name);
// *TODO: Move this into llappearance/LLWearableData ?
void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index);
@@ -170,12 +171,6 @@ protected:
//--------------------------------------------------------------------
// Outfits
//--------------------------------------------------------------------
-public:
-
- // Should only be called if we *know* we've never done so before, since users may
- // not want the Library outfits to stay in their quick outfit selector and can delete them.
- void populateMyOutfitsFolder();
-
private:
void makeNewOutfitDone(S32 type, U32 index);
@@ -237,6 +232,7 @@ private:
* True if agent's outfit is being changed now.
*/
BOOL mCOFChangeInProgress;
+ LLTimer mCOFChangeTimer;
//--------------------------------------------------------------------------------
// Support classes
@@ -253,7 +249,7 @@ private:
~sendAgentWearablesUpdateCallback();
};
- class addWearableToAgentInventoryCallback : public LLInventoryCallback
+ class AddWearableToAgentInventoryCallback : public LLInventoryCallback
{
public:
enum ETodo
@@ -266,7 +262,7 @@ private:
CALL_WEARITEM = 16
};
- addWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb,
+ AddWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb,
LLWearableType::EType type,
U32 index,
LLViewerWearable* wearable,
diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp
index 8b6b6db525..a2a667e660 100755
--- a/indra/newview/llagentwearablesfetch.cpp
+++ b/indra/newview/llagentwearablesfetch.cpp
@@ -35,46 +35,6 @@
#include "llvoavatarself.h"
-void order_my_outfits_cb()
- {
- if (!LLApp::isRunning())
- {
- llwarns << "called during shutdown, skipping" << llendl;
- return;
- }
-
- const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- if (my_outfits_id.isNull()) return;
-
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(my_outfits_id, cats, items);
- if (!cats) return;
-
- //My Outfits should at least contain saved initial outfit and one another outfit
- if (cats->size() < 2)
- {
- llwarning("My Outfits category was not populated properly", 0);
- return;
- }
-
- llinfos << "Starting updating My Outfits with wearables ordering information" << llendl;
-
- for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin();
- outfit_iter != cats->end(); ++outfit_iter)
- {
- const LLUUID& cat_id = (*outfit_iter)->getUUID();
- if (cat_id.isNull()) continue;
-
- // saved initial outfit already contains wearables ordering information
- if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue;
-
- LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id);
- }
-
- llinfos << "Finished updating My Outfits with wearables ordering information" << llendl;
- }
-
LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :
LLInventoryFetchDescendentsObserver(cof_id)
{
@@ -157,26 +117,21 @@ public:
// Link to all fetched items in COF.
LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+ LLInventoryObject::const_object_list_t item_array;
for (uuid_vec_t::iterator it = mIDs.begin();
it != mIDs.end();
++it)
{
LLUUID id = *it;
- LLViewerInventoryItem *item = gInventory.getItem(*it);
+ LLConstPointer<LLInventoryObject> item = gInventory.getItem(*it);
if (!item)
{
- llwarns << "fetch failed!" << llendl;
+ llwarns << "fetch failed for item " << (*it) << "!" << llendl;
continue;
}
-
- link_inventory_item(gAgent.getID(),
- item->getLinkedUUID(),
- LLAppearanceMgr::instance().getCOF(),
- item->getName(),
- item->getDescription(),
- LLAssetType::AT_LINK,
- link_waiter);
+ item_array.push_back(item);
}
+ link_inventory_array(LLAppearanceMgr::instance().getCOF(), item_array, link_waiter);
}
};
@@ -244,357 +199,3 @@ void LLInitialWearablesFetch::processWearablesMessage()
}
}
-LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) :
- LLInventoryFetchDescendentsObserver(my_outfits_id),
- mCurrFetchStep(LOFS_FOLDER),
- mOutfitsPopulated(false)
-{
- llinfos << "created" << llendl;
-
- mMyOutfitsID = LLUUID::null;
- mClothingID = LLUUID::null;
- mLibraryClothingID = LLUUID::null;
- mImportedClothingID = LLUUID::null;
- mImportedClothingName = "Imported Library Clothing";
-}
-
-LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch()
-{
- llinfos << "destroyed" << llendl;
-}
-
-void LLLibraryOutfitsFetch::done()
-{
- llinfos << "start" << llendl;
-
- // Delay this until idle() routine, since it's a heavy operation and
- // we also can't have it run within notifyObservers.
- doOnIdleOneTime(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this));
- gInventory.removeObserver(this); // Prevent doOnIdleOneTime from being added twice.
-}
-
-void LLLibraryOutfitsFetch::doneIdle()
-{
- llinfos << "start" << llendl;
-
- gInventory.addObserver(this); // Add this back in since it was taken out during ::done()
-
- switch (mCurrFetchStep)
- {
- case LOFS_FOLDER:
- folderDone();
- mCurrFetchStep = LOFS_OUTFITS;
- break;
- case LOFS_OUTFITS:
- outfitsDone();
- mCurrFetchStep = LOFS_LIBRARY;
- break;
- case LOFS_LIBRARY:
- libraryDone();
- mCurrFetchStep = LOFS_IMPORTED;
- break;
- case LOFS_IMPORTED:
- importedFolderDone();
- mCurrFetchStep = LOFS_CONTENTS;
- break;
- case LOFS_CONTENTS:
- contentsDone();
- break;
- default:
- llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl;
- mOutfitsPopulated = TRUE;
- break;
- }
-
- // We're completely done. Cleanup.
- if (mOutfitsPopulated)
- {
- gInventory.removeObserver(this);
- delete this;
- return;
- }
-}
-
-void LLLibraryOutfitsFetch::folderDone()
-{
- llinfos << "start" << llendl;
-
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
- gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH);
-
- // Early out if we already have items in My Outfits
- // except the case when My Outfits contains just initial outfit
- if (cat_array.count() > 1)
- {
- mOutfitsPopulated = true;
- return;
- }
-
- mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
- mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false);
-
- // If Library->Clothing->Initial Outfits exists, use that.
- LLNameCategoryCollector matchFolderFunctor("Initial Outfits");
- cat_array.clear();
- gInventory.collectDescendentsIf(mLibraryClothingID,
- cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH,
- matchFolderFunctor);
- if (cat_array.count() > 0)
- {
- const LLViewerInventoryCategory *cat = cat_array.get(0);
- mLibraryClothingID = cat->getUUID();
- }
-
- mComplete.clear();
-
- // Get the complete information on the items in the inventory.
- uuid_vec_t folders;
- folders.push_back(mClothingID);
- folders.push_back(mLibraryClothingID);
- setFetchIDs(folders);
- startFetch();
- if (isFinished())
- {
- done();
- }
-}
-
-void LLLibraryOutfitsFetch::outfitsDone()
-{
- llinfos << "start" << llendl;
-
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
- uuid_vec_t folders;
-
- // Collect the contents of the Library's Clothing folder
- gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH);
-
- llassert(cat_array.count() > 0);
- for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
- iter != cat_array.end();
- ++iter)
- {
- const LLViewerInventoryCategory *cat = iter->get();
-
- // Get the names and id's of every outfit in the library, skip "Ruth"
- // because it's a low quality legacy outfit
- if (cat->getName() != "Ruth")
- {
- // Get the name of every outfit in the library
- folders.push_back(cat->getUUID());
- mLibraryClothingFolders.push_back(cat->getUUID());
- }
- }
- cat_array.clear();
- wearable_array.clear();
-
- // Check if you already have an "Imported Library Clothing" folder
- LLNameCategoryCollector matchFolderFunctor(mImportedClothingName);
- gInventory.collectDescendentsIf(mClothingID,
- cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH,
- matchFolderFunctor);
- if (cat_array.size() > 0)
- {
- const LLViewerInventoryCategory *cat = cat_array.get(0);
- mImportedClothingID = cat->getUUID();
- }
-
- mComplete.clear();
- setFetchIDs(folders);
- startFetch();
- if (isFinished())
- {
- done();
- }
-}
-
-class LLLibraryOutfitsCopyDone: public LLInventoryCallback
-{
-public:
- LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher):
- mFireCount(0), mLibraryOutfitsFetcher(fetcher)
- {
- }
-
- virtual ~LLLibraryOutfitsCopyDone()
- {
- if (!LLApp::isExiting() && mLibraryOutfitsFetcher)
- {
- gInventory.addObserver(mLibraryOutfitsFetcher);
- mLibraryOutfitsFetcher->done();
- }
- }
-
- /* virtual */ void fire(const LLUUID& inv_item)
- {
- mFireCount++;
- }
-private:
- U32 mFireCount;
- LLLibraryOutfitsFetch * mLibraryOutfitsFetcher;
-};
-
-// Copy the clothing folders from the library into the imported clothing folder
-void LLLibraryOutfitsFetch::libraryDone()
-{
- llinfos << "start" << llendl;
-
- if (mImportedClothingID != LLUUID::null)
- {
- // Skip straight to fetching the contents of the imported folder
- importedFolderFetch();
- return;
- }
-
- // Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone.
- gInventory.removeObserver(this);
-
- LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this);
- mImportedClothingID = gInventory.createNewCategory(mClothingID,
- LLFolderType::FT_NONE,
- mImportedClothingName);
- // Copy each folder from library into clothing unless it already exists.
- for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin();
- iter != mLibraryClothingFolders.end();
- ++iter)
- {
- const LLUUID& src_folder_id = (*iter); // Library clothing folder ID
- const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id);
- if (!cat)
- {
- llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl;
- continue;
- }
-
- if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id))
- {
- llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl;
- continue;
- }
-
- // Don't copy the category if it already exists.
- LLNameCategoryCollector matchFolderFunctor(cat->getName());
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
- gInventory.collectDescendentsIf(mImportedClothingID,
- cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH,
- matchFolderFunctor);
- if (cat_array.size() > 0)
- {
- continue;
- }
-
- LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID,
- LLFolderType::FT_NONE,
- cat->getName());
- LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter);
- }
-}
-
-void LLLibraryOutfitsFetch::importedFolderFetch()
-{
- llinfos << "start" << llendl;
-
- // Fetch the contents of the Imported Clothing Folder
- uuid_vec_t folders;
- folders.push_back(mImportedClothingID);
-
- mComplete.clear();
- setFetchIDs(folders);
- startFetch();
- if (isFinished())
- {
- done();
- }
-}
-
-void LLLibraryOutfitsFetch::importedFolderDone()
-{
- llinfos << "start" << llendl;
-
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
- uuid_vec_t folders;
-
- // Collect the contents of the Imported Clothing folder
- gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH);
-
- for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin();
- iter != cat_array.end();
- ++iter)
- {
- const LLViewerInventoryCategory *cat = iter->get();
-
- // Get the name of every imported outfit
- folders.push_back(cat->getUUID());
- mImportedClothingFolders.push_back(cat->getUUID());
- }
-
- mComplete.clear();
- setFetchIDs(folders);
- startFetch();
- if (isFinished())
- {
- done();
- }
-}
-
-void LLLibraryOutfitsFetch::contentsDone()
-{
- llinfos << "start" << llendl;
-
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
-
- LLPointer<LLInventoryCallback> order_myoutfits_on_destroy = new LLBoostFuncInventoryCallback(no_op_inventory_func, order_my_outfits_cb);
-
- for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin();
- folder_iter != mImportedClothingFolders.end();
- ++folder_iter)
- {
- const LLUUID &folder_id = (*folder_iter);
- const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id);
- if (!cat)
- {
- llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl;
- continue;
- }
-
- //initial outfit should be already in My Outfits
- if (cat->getName() == LLStartUp::getInitialOutfitName()) continue;
-
- // First, make a folder in the My Outfits directory.
- LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName());
-
- cat_array.clear();
- wearable_array.clear();
- // Collect the contents of each imported clothing folder, so we can create new outfit links for it
- gInventory.collectDescendents(folder_id, cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH);
-
- for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin();
- wearable_iter != wearable_array.end();
- ++wearable_iter)
- {
- const LLViewerInventoryItem *item = wearable_iter->get();
- link_inventory_item(gAgent.getID(),
- item->getLinkedUUID(),
- new_outfit_folder_id,
- item->getName(),
- item->getDescription(),
- LLAssetType::AT_LINK,
- order_myoutfits_on_destroy);
- }
- }
-
- mOutfitsPopulated = true;
-}
-
diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h
index bedc445c0e..81b03110ae 100755
--- a/indra/newview/llagentwearablesfetch.h
+++ b/indra/newview/llagentwearablesfetch.h
@@ -70,45 +70,4 @@ private:
initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg
};
-//--------------------------------------------------------------------
-// InitialWearablesFetch
-//
-// This grabs outfits from the Library and copies those over to the user's
-// outfits folder, typically during first-ever login.
-//--------------------------------------------------------------------
-class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver
-{
-public:
- enum ELibraryOutfitFetchStep
- {
- LOFS_FOLDER = 0,
- LOFS_OUTFITS,
- LOFS_LIBRARY,
- LOFS_IMPORTED,
- LOFS_CONTENTS
- };
-
- LLLibraryOutfitsFetch(const LLUUID& my_outfits_id);
- ~LLLibraryOutfitsFetch();
-
- virtual void done();
- void doneIdle();
- LLUUID mMyOutfitsID;
- void importedFolderFetch();
-protected:
- void folderDone();
- void outfitsDone();
- void libraryDone();
- void importedFolderDone();
- void contentsDone();
- enum ELibraryOutfitFetchStep mCurrFetchStep;
- uuid_vec_t mLibraryClothingFolders;
- uuid_vec_t mImportedClothingFolders;
- bool mOutfitsPopulated;
- LLUUID mClothingID;
- LLUUID mLibraryClothingID;
- LLUUID mImportedClothingID;
- std::string mImportedClothingName;
-};
-
#endif // LL_AGENTWEARABLESINITIALFETCH_H
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
new file mode 100755
index 0000000000..6f6e6ebb35
--- /dev/null
+++ b/indra/newview/llaisapi.cpp
@@ -0,0 +1,842 @@
+/**
+ * @file llaisapi.cpp
+ * @brief classes and functions for interfacing with the v3+ ais inventory service.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ *
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llaisapi.h"
+
+#include "llagent.h"
+#include "llcallbacklist.h"
+#include "llinventorymodel.h"
+#include "llsdutil.h"
+#include "llviewerregion.h"
+
+///----------------------------------------------------------------------------
+/// Classes for AISv3 support.
+///----------------------------------------------------------------------------
+
+// AISCommand - base class for retry-able HTTP requests using the AISv3 cap.
+AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback):
+ mCommandFunc(NULL),
+ mCallback(callback)
+{
+ mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
+}
+
+bool AISCommand::run_command()
+{
+ if (NULL == mCommandFunc)
+ {
+ // This may happen if a command failed to initiate itself.
+ LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL;
+ return false;
+ }
+ else
+ {
+ mCommandFunc();
+ return true;
+ }
+}
+
+void AISCommand::setCommandFunc(command_func_type command_func)
+{
+ mCommandFunc = command_func;
+}
+
+// virtual
+bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id)
+{
+ return false;
+}
+
+/* virtual */
+void AISCommand::httpSuccess()
+{
+ // Command func holds a reference to self, need to release it
+ // after a success or final failure.
+ setCommandFunc(no_op);
+
+ const LLSD& content = getContent();
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
+ mRetryPolicy->onSuccess();
+
+ gInventory.onAISUpdateReceived("AISCommand", content);
+
+ if (mCallback)
+ {
+ LLUUID id; // will default to null if parse fails.
+ getResponseUUID(content,id);
+ mCallback->fire(id);
+ }
+}
+
+/*virtual*/
+void AISCommand::httpFailure()
+{
+ LL_WARNS("Inventory") << dumpResponse() << LL_ENDL;
+ S32 status = getStatus();
+ const LLSD& headers = getResponseHeaders();
+ 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.
+ // *TODO: Notify user? This seems bad.
+ setCommandFunc(no_op);
+ }
+}
+
+//static
+bool AISCommand::isAPIAvailable()
+{
+ if (gAgent.getRegion())
+ {
+ return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3");
+ }
+ return false;
+}
+
+//static
+bool AISCommand::getInvCap(std::string& cap)
+{
+ if (gAgent.getRegion())
+ {
+ cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
+ }
+ if (!cap.empty())
+ {
+ return true;
+ }
+ return false;
+}
+
+//static
+bool AISCommand::getLibCap(std::string& cap)
+{
+ if (gAgent.getRegion())
+ {
+ cap = gAgent.getRegion()->getCapability("LibraryAPIv3");
+ }
+ if (!cap.empty())
+ {
+ return true;
+ }
+ return false;
+}
+
+//static
+void AISCommand::getCapabilityNames(LLSD& capabilityNames)
+{
+ capabilityNames.append("InventoryAPIv3");
+ capabilityNames.append("LibraryAPIv3");
+}
+
+RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/item/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LLHTTPClient::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LLHTTPClient::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + item_id.asString() + "/children";
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> callback):
+ mUpdates(updates),
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/item/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ headers["Content-Type"] = "application/llsd+xml";
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& cat_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> callback):
+ mUpdates(updates),
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + cat_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ headers["Content-Type"] = "application/llsd+xml";
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+CreateInventoryCommand::CreateInventoryCommand(const LLUUID& parent_id,
+ const LLSD& new_inventory,
+ LLPointer<LLInventoryCallback> callback):
+ mNewInventory(new_inventory),
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ LLUUID tid;
+ tid.generate();
+ std::string url = cap + std::string("/category/") + parent_id.asString() + "?tid=" + tid.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ headers["Content-Type"] = "application/llsd+xml";
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::post, url, mNewInventory, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback):
+ mContents(contents),
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getInvCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ LLUUID tid;
+ tid.generate();
+ std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString();
+ llinfos << url << llendl;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ headers["Content-Type"] = "application/llsd+xml";
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id,
+ const LLUUID& dest_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+{
+ std::string cap;
+ if (!getLibCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL;
+ LLUUID tid;
+ tid.generate();
+ std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString();
+ llinfos << url << llendl;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout);
+ setCommandFunc(cmd);
+}
+
+bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id)
+{
+ if (content.has("category_id"))
+ {
+ id = content["category_id"];
+ return true;
+ }
+ return false;
+}
+
+AISUpdate::AISUpdate(const LLSD& update)
+{
+ parseUpdate(update);
+}
+
+void AISUpdate::clearParseResults()
+{
+ mCatDescendentDeltas.clear();
+ mCatDescendentsKnown.clear();
+ mCatVersionsUpdated.clear();
+ mItemsCreated.clear();
+ mItemsUpdated.clear();
+ mCategoriesCreated.clear();
+ mCategoriesUpdated.clear();
+ mObjectsDeletedIds.clear();
+ mItemIds.clear();
+ mCategoryIds.clear();
+}
+
+void AISUpdate::parseUpdate(const LLSD& update)
+{
+ clearParseResults();
+ parseMeta(update);
+ parseContent(update);
+}
+
+void AISUpdate::parseMeta(const LLSD& update)
+{
+ // parse _categories_removed -> mObjectsDeletedIds
+ uuid_list_t cat_ids;
+ parseUUIDArray(update,"_categories_removed",cat_ids);
+ for (uuid_list_t::const_iterator it = cat_ids.begin();
+ it != cat_ids.end(); ++it)
+ {
+ LLViewerInventoryCategory *cat = gInventory.getCategory(*it);
+ mCatDescendentDeltas[cat->getParentUUID()]--;
+ mObjectsDeletedIds.insert(*it);
+ }
+
+ // parse _categories_items_removed -> mObjectsDeletedIds
+ uuid_list_t item_ids;
+ parseUUIDArray(update,"_category_items_removed",item_ids);
+ parseUUIDArray(update,"_removed_items",item_ids);
+ for (uuid_list_t::const_iterator it = item_ids.begin();
+ it != item_ids.end(); ++it)
+ {
+ LLViewerInventoryItem *item = gInventory.getItem(*it);
+ mCatDescendentDeltas[item->getParentUUID()]--;
+ mObjectsDeletedIds.insert(*it);
+ }
+
+ // parse _broken_links_removed -> mObjectsDeletedIds
+ uuid_list_t broken_link_ids;
+ parseUUIDArray(update,"_broken_links_removed",broken_link_ids);
+ for (uuid_list_t::const_iterator it = broken_link_ids.begin();
+ it != broken_link_ids.end(); ++it)
+ {
+ LLViewerInventoryItem *item = gInventory.getItem(*it);
+ mCatDescendentDeltas[item->getParentUUID()]--;
+ mObjectsDeletedIds.insert(*it);
+ }
+
+ // parse _created_items
+ parseUUIDArray(update,"_created_items",mItemIds);
+
+ // parse _created_categories
+ parseUUIDArray(update,"_created_categories",mCategoryIds);
+
+ // Parse updated category versions.
+ const std::string& ucv = "_updated_category_versions";
+ if (update.has(ucv))
+ {
+ for(LLSD::map_const_iterator it = update[ucv].beginMap(),
+ end = update[ucv].endMap();
+ it != end; ++it)
+ {
+ const LLUUID id((*it).first);
+ S32 version = (*it).second.asInteger();
+ mCatVersionsUpdated[id] = version;
+ }
+ }
+}
+
+void AISUpdate::parseContent(const LLSD& update)
+{
+ if (update.has("linked_id"))
+ {
+ parseLink(update);
+ }
+ else if (update.has("item_id"))
+ {
+ parseItem(update);
+ }
+
+ if (update.has("category_id"))
+ {
+ parseCategory(update);
+ }
+ else
+ {
+ if (update.has("_embedded"))
+ {
+ parseEmbedded(update["_embedded"]);
+ }
+ }
+}
+
+void AISUpdate::parseItem(const LLSD& item_map)
+{
+ LLUUID item_id = item_map["item_id"].asUUID();
+ LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
+ LLViewerInventoryItem *curr_item = gInventory.getItem(item_id);
+ if (curr_item)
+ {
+ // Default to current values where not provided.
+ new_item->copyViewerItem(curr_item);
+ }
+ BOOL rv = new_item->unpackMessage(item_map);
+ if (rv)
+ {
+ if (curr_item)
+ {
+ mItemsUpdated[item_id] = new_item;
+ // This statement is here to cause a new entry with 0
+ // delta to be created if it does not already exist;
+ // otherwise has no effect.
+ mCatDescendentDeltas[new_item->getParentUUID()];
+ }
+ else
+ {
+ mItemsCreated[item_id] = new_item;
+ mCatDescendentDeltas[new_item->getParentUUID()]++;
+ }
+ }
+ else
+ {
+ // *TODO: Wow, harsh. Should we just complain and get out?
+ llerrs << "unpack failed" << llendl;
+ }
+}
+
+void AISUpdate::parseLink(const LLSD& link_map)
+{
+ LLUUID item_id = link_map["item_id"].asUUID();
+ LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem);
+ LLViewerInventoryItem *curr_link = gInventory.getItem(item_id);
+ if (curr_link)
+ {
+ // Default to current values where not provided.
+ new_link->copyViewerItem(curr_link);
+ }
+ BOOL rv = new_link->unpackMessage(link_map);
+ if (rv)
+ {
+ const LLUUID& parent_id = new_link->getParentUUID();
+ if (curr_link)
+ {
+ mItemsUpdated[item_id] = new_link;
+ // This statement is here to cause a new entry with 0
+ // delta to be created if it does not already exist;
+ // otherwise has no effect.
+ mCatDescendentDeltas[parent_id];
+ }
+ else
+ {
+ LLPermissions default_perms;
+ default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null);
+ default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE);
+ new_link->setPermissions(default_perms);
+ LLSaleInfo default_sale_info;
+ new_link->setSaleInfo(default_sale_info);
+ //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
+ mItemsCreated[item_id] = new_link;
+ mCatDescendentDeltas[parent_id]++;
+ }
+ }
+ else
+ {
+ // *TODO: Wow, harsh. Should we just complain and get out?
+ llerrs << "unpack failed" << llendl;
+ }
+}
+
+
+void AISUpdate::parseCategory(const LLSD& category_map)
+{
+ LLUUID category_id = category_map["category_id"].asUUID();
+
+ // Check descendent count first, as it may be needed
+ // to populate newly created categories
+ if (category_map.has("_embedded"))
+ {
+ parseDescendentCount(category_id, category_map["_embedded"]);
+ }
+
+ LLPointer<LLViewerInventoryCategory> new_cat(new LLViewerInventoryCategory(category_id));
+ LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
+ if (curr_cat)
+ {
+ // Default to current values where not provided.
+ new_cat->copyViewerCategory(curr_cat);
+ }
+ BOOL rv = new_cat->unpackMessage(category_map);
+ // *NOTE: unpackMessage does not unpack version or descendent count.
+ //if (category_map.has("version"))
+ //{
+ // mCatVersionsUpdated[category_id] = category_map["version"].asInteger();
+ //}
+ if (rv)
+ {
+ if (curr_cat)
+ {
+ mCategoriesUpdated[category_id] = new_cat;
+ // This statement is here to cause a new entry with 0
+ // delta to be created if it does not already exist;
+ // otherwise has no effect.
+ mCatDescendentDeltas[new_cat->getParentUUID()];
+ // Capture update for the category itself as well.
+ mCatDescendentDeltas[category_id];
+ }
+ else
+ {
+ // Set version/descendents for newly created categories.
+ if (category_map.has("version"))
+ {
+ S32 version = category_map["version"].asInteger();
+ LL_DEBUGS("Inventory") << "Setting version to " << version
+ << " for new category " << category_id << LL_ENDL;
+ new_cat->setVersion(version);
+ }
+ uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
+ if (mCatDescendentsKnown.end() != lookup_it)
+ {
+ S32 descendent_count = lookup_it->second;
+ LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
+ << " for new category " << category_id << LL_ENDL;
+ new_cat->setDescendentCount(descendent_count);
+ }
+ mCategoriesCreated[category_id] = new_cat;
+ mCatDescendentDeltas[new_cat->getParentUUID()]++;
+ }
+ }
+ else
+ {
+ // *TODO: Wow, harsh. Should we just complain and get out?
+ llerrs << "unpack failed" << llendl;
+ }
+
+ // Check for more embedded content.
+ if (category_map.has("_embedded"))
+ {
+ parseEmbedded(category_map["_embedded"]);
+ }
+}
+
+void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded)
+{
+ // We can only determine true descendent count if this contains all descendent types.
+ if (embedded.has("category") &&
+ embedded.has("link") &&
+ embedded.has("item"))
+ {
+ mCatDescendentsKnown[category_id] = embedded["category"].size();
+ mCatDescendentsKnown[category_id] += embedded["link"].size();
+ mCatDescendentsKnown[category_id] += embedded["item"].size();
+ }
+}
+
+void AISUpdate::parseEmbedded(const LLSD& embedded)
+{
+ if (embedded.has("link"))
+ {
+ parseEmbeddedLinks(embedded["link"]);
+ }
+ if (embedded.has("item"))
+ {
+ parseEmbeddedItems(embedded["item"]);
+ }
+ if (embedded.has("category"))
+ {
+ parseEmbeddedCategories(embedded["category"]);
+ }
+}
+
+void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids)
+{
+ if (content.has(name))
+ {
+ for(LLSD::array_const_iterator it = content[name].beginArray(),
+ end = content[name].endArray();
+ it != end; ++it)
+ {
+ ids.insert((*it).asUUID());
+ }
+ }
+}
+
+void AISUpdate::parseEmbeddedLinks(const LLSD& links)
+{
+ for(LLSD::map_const_iterator linkit = links.beginMap(),
+ linkend = links.endMap();
+ linkit != linkend; ++linkit)
+ {
+ const LLUUID link_id((*linkit).first);
+ const LLSD& link_map = (*linkit).second;
+ if (mItemIds.end() == mItemIds.find(link_id))
+ {
+ LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
+ }
+ else
+ {
+ parseLink(link_map);
+ }
+ }
+}
+
+void AISUpdate::parseEmbeddedItems(const LLSD& items)
+{
+ // Special case: this may be a single item (_embedded in a link)
+ if (items.has("item_id"))
+ {
+ if (mItemIds.end() != mItemIds.find(items["item_id"].asUUID()))
+ {
+ parseContent(items);
+ }
+ return;
+ }
+
+ for(LLSD::map_const_iterator itemit = items.beginMap(),
+ itemend = items.endMap();
+ itemit != itemend; ++itemit)
+ {
+ const LLUUID item_id((*itemit).first);
+ const LLSD& item_map = (*itemit).second;
+ if (mItemIds.end() == mItemIds.find(item_id))
+ {
+ LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
+ }
+ else
+ {
+ parseItem(item_map);
+ }
+ }
+}
+
+void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
+{
+ for(LLSD::map_const_iterator categoryit = categories.beginMap(),
+ categoryend = categories.endMap();
+ categoryit != categoryend; ++categoryit)
+ {
+ const LLUUID category_id((*categoryit).first);
+ const LLSD& category_map = (*categoryit).second;
+ if (mCategoryIds.end() == mCategoryIds.find(category_id))
+ {
+ LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
+ }
+ else
+ {
+ parseCategory(category_map);
+ }
+ }
+}
+
+void AISUpdate::doUpdate()
+{
+ // Do version/descendent accounting.
+ for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin();
+ catit != mCatDescendentDeltas.end(); ++catit)
+ {
+ LL_DEBUGS("Inventory") << "descendent accounting for " << catit->first << llendl;
+
+ const LLUUID cat_id(catit->first);
+ // Don't account for update if we just created this category.
+ if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end())
+ {
+ LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL;
+ continue;
+ }
+
+ // Don't account for update unless AIS told us it updated that category.
+ if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end())
+ {
+ LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL;
+ continue;
+ }
+
+ // If we have a known descendent count, set that now.
+ LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
+ if (cat)
+ {
+ S32 descendent_delta = catit->second;
+ S32 old_count = cat->getDescendentCount();
+ LL_DEBUGS("Inventory") << "Updating descendent count for "
+ << cat->getName() << " " << cat_id
+ << " with delta " << descendent_delta << " from "
+ << old_count << " to " << (old_count+descendent_delta) << LL_ENDL;
+ LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta);
+ gInventory.accountForUpdate(up);
+ }
+ else
+ {
+ LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL;
+ }
+ }
+
+ // CREATE CATEGORIES
+ for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin();
+ create_it != mCategoriesCreated.end(); ++create_it)
+ {
+ LLUUID category_id(create_it->first);
+ LLPointer<LLViewerInventoryCategory> new_category = create_it->second;
+
+ gInventory.updateCategory(new_category);
+ LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL;
+ }
+
+ // UPDATE CATEGORIES
+ for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin();
+ update_it != mCategoriesUpdated.end(); ++update_it)
+ {
+ LLUUID category_id(update_it->first);
+ LLPointer<LLViewerInventoryCategory> new_category = update_it->second;
+ // Since this is a copy of the category *before* the accounting update, above,
+ // we need to transfer back the updated version/descendent count.
+ LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID());
+ if (NULL == curr_cat)
+ {
+ LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL;
+ }
+ else
+ {
+ new_category->setVersion(curr_cat->getVersion());
+ new_category->setDescendentCount(curr_cat->getDescendentCount());
+ gInventory.updateCategory(new_category);
+ LL_DEBUGS("Inventory") << "updated category " << new_category->getName() << " " << category_id << LL_ENDL;
+ }
+ }
+
+ // CREATE ITEMS
+ for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin();
+ create_it != mItemsCreated.end(); ++create_it)
+ {
+ LLUUID item_id(create_it->first);
+ LLPointer<LLViewerInventoryItem> new_item = create_it->second;
+
+ // FIXME risky function since it calls updateServer() in some
+ // cases. Maybe break out the update/create cases, in which
+ // case this is create.
+ LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL;
+ gInventory.updateItem(new_item);
+ }
+
+ // UPDATE ITEMS
+ for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin();
+ update_it != mItemsUpdated.end(); ++update_it)
+ {
+ LLUUID item_id(update_it->first);
+ LLPointer<LLViewerInventoryItem> new_item = update_it->second;
+ // FIXME risky function since it calls updateServer() in some
+ // cases. Maybe break out the update/create cases, in which
+ // case this is update.
+ LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL;
+ //LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL;
+ gInventory.updateItem(new_item);
+ }
+
+ // DELETE OBJECTS
+ for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin();
+ del_it != mObjectsDeletedIds.end(); ++del_it)
+ {
+ LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL;
+ gInventory.onObjectDeletedFromServer(*del_it, false, false, 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.
+ for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin();
+ ucv_it != mCatVersionsUpdated.end(); ++ucv_it)
+ {
+ const LLUUID id = ucv_it->first;
+ S32 version = ucv_it->second;
+ LLViewerInventoryCategory *cat = gInventory.getCategory(id);
+ LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << llendl;
+ if (cat->getVersion() != version)
+ {
+ llwarns << "Possible version mismatch for category " << cat->getName()
+ << ", viewer version " << cat->getVersion()
+ << " server version " << version << llendl;
+ }
+ }
+
+ gInventory.notifyObservers();
+}
+
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
new file mode 100755
index 0000000000..f3a662c280
--- /dev/null
+++ b/indra/newview/llaisapi.h
@@ -0,0 +1,181 @@
+/**
+ * @file llaisapi.h
+ * @brief classes and functions for interfacing with the v3+ ais inventory service.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAISAPI_H
+#define LL_LLAISAPI_H
+
+#include "lluuid.h"
+#include <map>
+#include <set>
+#include <string>
+#include "llcurl.h"
+#include "llhttpclient.h"
+#include "llhttpretrypolicy.h"
+#include "llviewerinventory.h"
+
+class AISCommand: public LLHTTPClient::Responder
+{
+public:
+ typedef boost::function<void()> command_func_type;
+
+ AISCommand(LLPointer<LLInventoryCallback> callback);
+
+ virtual ~AISCommand() {}
+
+ bool run_command();
+
+ void setCommandFunc(command_func_type command_func);
+
+ // Need to do command-specific parsing to get an id here, for
+ // LLInventoryCallback::fire(). May or may not need to bother,
+ // since most LLInventoryCallbacks do their work in the
+ // destructor.
+
+ /* virtual */ void httpSuccess();
+ /* virtual */ void httpFailure();
+
+ static bool isAPIAvailable();
+ static bool getInvCap(std::string& cap);
+ static bool getLibCap(std::string& cap);
+ static void getCapabilityNames(LLSD& capabilityNames);
+
+protected:
+ virtual bool getResponseUUID(const LLSD& content, LLUUID& id);
+
+private:
+ command_func_type mCommandFunc;
+ LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
+ LLPointer<LLInventoryCallback> mCallback;
+};
+
+class RemoveItemCommand: public AISCommand
+{
+public:
+ RemoveItemCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback);
+};
+
+class RemoveCategoryCommand: public AISCommand
+{
+public:
+ RemoveCategoryCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback);
+};
+
+class PurgeDescendentsCommand: public AISCommand
+{
+public:
+ PurgeDescendentsCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback);
+};
+
+class UpdateItemCommand: public AISCommand
+{
+public:
+ UpdateItemCommand(const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> callback);
+private:
+ LLSD mUpdates;
+};
+
+class UpdateCategoryCommand: public AISCommand
+{
+public:
+ UpdateCategoryCommand(const LLUUID& cat_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> callback);
+private:
+ LLSD mUpdates;
+};
+
+class SlamFolderCommand: public AISCommand
+{
+public:
+ SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback);
+
+private:
+ LLSD mContents;
+};
+
+class CopyLibraryCategoryCommand: public AISCommand
+{
+public:
+ CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback);
+
+protected:
+ /* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id);
+};
+
+class CreateInventoryCommand: public AISCommand
+{
+public:
+ CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback);
+
+private:
+ LLSD mNewInventory;
+};
+
+class AISUpdate
+{
+public:
+ AISUpdate(const LLSD& update);
+ void parseUpdate(const LLSD& update);
+ void parseMeta(const LLSD& update);
+ void parseContent(const LLSD& update);
+ void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
+ void parseLink(const LLSD& link_map);
+ void parseItem(const LLSD& link_map);
+ void parseCategory(const LLSD& link_map);
+ void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
+ void parseEmbedded(const LLSD& embedded);
+ void parseEmbeddedLinks(const LLSD& links);
+ void parseEmbeddedItems(const LLSD& links);
+ void parseEmbeddedCategories(const LLSD& links);
+ void doUpdate();
+private:
+ void clearParseResults();
+
+ typedef std::map<LLUUID,S32> uuid_int_map_t;
+ uuid_int_map_t mCatDescendentDeltas;
+ uuid_int_map_t mCatDescendentsKnown;
+ uuid_int_map_t mCatVersionsUpdated;
+
+ typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t;
+ deferred_item_map_t mItemsCreated;
+ deferred_item_map_t mItemsUpdated;
+ typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t;
+ deferred_category_map_t mCategoriesCreated;
+ deferred_category_map_t mCategoriesUpdated;
+
+ // These keep track of uuid's mentioned in meta values.
+ // Useful for filtering out which content we are interested in.
+ uuid_list_t mObjectsDeletedIds;
+ uuid_list_t mItemIds;
+ uuid_list_t mCategoryIds;
+};
+
+#endif
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index fd9236c8b3..7fbe84312e 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -52,6 +52,8 @@
#include "llwearablelist.h"
#include "llsdutil.h"
#include "llsdserialize.h"
+#include "llhttpretrypolicy.h"
+#include "llaisapi.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -196,7 +198,7 @@ public:
LLEventTimer(5.0)
{
if (!mTrackingPhase.empty())
- {
+ {
selfStartPhase(mTrackingPhase);
}
}
@@ -212,23 +214,23 @@ public:
addItem(item->getUUID());
}
}
-
+
// Request or re-request operation for specified item.
void addItem(const LLUUID& item_id)
{
LL_DEBUGS("Avatar") << "item_id " << item_id << llendl;
-
+
if (!requestOperation(item_id))
{
LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << llendl;
return;
- }
+ }
mPendingRequests++;
// On a re-request, this will reset the timer.
mWaitTimes[item_id] = LLTimer();
if (mRetryCounts.find(item_id) == mRetryCounts.end())
- {
+ {
mRetryCounts[item_id] = 0;
}
else
@@ -242,7 +244,7 @@ public:
void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)
{
if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate"))
- {
+ {
llwarns << "Simulating late operation by punting handling to later" << llendl;
doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),
mRetryAfter);
@@ -265,12 +267,12 @@ public:
onCompletionOrFailure();
}
}
-
+
void onCompletionOrFailure()
{
assert (!mCompletionOrFailureCalled);
mCompletionOrFailureCalled = true;
-
+
// Will never call onCompletion() if any item has been flagged as
// a failure - otherwise could wind up with corrupted
// outfit, involuntary nudity, etc.
@@ -288,7 +290,7 @@ public:
onFailure();
}
}
-
+
void onFailure()
{
llinfos << "failed" << llendl;
@@ -300,7 +302,7 @@ public:
llinfos << "done" << llendl;
mOnCompletionFunc();
}
-
+
// virtual
// Will be deleted after returning true - only safe to do this if all callbacks have fired.
BOOL tick()
@@ -313,7 +315,7 @@ public:
// been serviced, since it will result in this object being
// deleted.
bool all_done = (mPendingRequests==0);
-
+
if (!mWaitTimes.empty())
{
llwarns << "still waiting on " << mWaitTimes.size() << " items" << llendl;
@@ -323,20 +325,20 @@ public:
// Use a copy of iterator because it may be erased/invalidated.
std::map<LLUUID,LLTimer>::iterator curr_it = it;
++it;
-
+
F32 time_waited = curr_it->second.getElapsedTimeF32();
S32 retries = mRetryCounts[curr_it->first];
if (time_waited > mRetryAfter)
{
if (retries < mMaxRetries)
- {
+ {
LL_DEBUGS("Avatar") << "Waited " << time_waited <<
" for " << curr_it->first << ", retrying" << llendl;
mRetryCount++;
addItem(curr_it->first);
- }
- else
- {
+ }
+ else
+ {
llwarns << "Giving up on " << curr_it->first << " after too many retries" << llendl;
mWaitTimes.erase(curr_it);
mFailCount++;
@@ -347,8 +349,8 @@ public:
onCompletionOrFailure();
}
+ }
}
- }
return all_done;
}
@@ -360,7 +362,7 @@ public:
LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << llendl;
LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << llendl;
}
-
+
virtual ~LLCallAfterInventoryBatchMgr()
{
LL_DEBUGS("Avatar") << "deleting" << llendl;
@@ -396,10 +398,16 @@ public:
LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries)
{
addItems(src_items);
+ sInstanceCount++;
}
+ ~LLCallAfterInventoryCopyMgr()
+ {
+ sInstanceCount--;
+ }
+
virtual bool requestOperation(const LLUUID& item_id)
- {
+ {
LLViewerInventoryItem *item = gInventory.getItem(item_id);
llassert(item);
LL_DEBUGS("Avatar") << "copying item " << item_id << llendl;
@@ -418,95 +426,86 @@ public:
);
return true;
}
+
+ static S32 getInstanceCount() { return sInstanceCount; }
+
+private:
+ static S32 sInstanceCount;
};
-class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr
+S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0;
+
+class LLWearCategoryAfterCopy: public LLInventoryCallback
{
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)
+ LLWearCategoryAfterCopy(bool append):
+ mAppend(append)
+ {}
+
+ // virtual
+ void fire(const LLUUID& id)
{
- addItems(src_items);
+ // Wear the inventory category.
+ LLInventoryCategory* cat = gInventory.getCategory(id);
+ LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend);
}
-
- 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);
+private:
+ bool mAppend;
+};
- if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
+class LLTrackPhaseWrapper : public LLInventoryCallback
+{
+public:
+ LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL):
+ mTrackingPhase(phase_name),
+ mCB(cb)
{
- if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
+ selfStartPhase(mTrackingPhase);
+ }
+
+ // virtual
+ void fire(const LLUUID& id)
+ {
+ if (mCB)
{
- 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);
+ mCB->fire(id);
}
- return request_sent;
}
+
+ // virtual
+ ~LLTrackPhaseWrapper()
+ {
+ selfStopPhase(mTrackingPhase);
+ }
+
+protected:
+ std::string mTrackingPhase;
+ LLPointer<LLInventoryCallback> mCB;
};
-LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering):
+LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions,
+ bool enforce_ordering,
+ nullary_func_t post_update_func
+ ):
mFireCount(0),
- mUpdateBaseOrder(update_base_outfit_ordering)
+ mEnforceItemRestrictions(enforce_item_restrictions),
+ mEnforceOrdering(enforce_ordering),
+ mPostUpdateFunc(post_update_func)
{
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 +515,46 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy()
selfStopPhase("update_appearance_on_destroy");
- LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder);
+ LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions,
+ mEnforceOrdering,
+ mPostUpdateFunc);
}
}
-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++;
}
+void edit_wearable_and_customize_avatar(LLUUID item_id)
+{
+ // Start editing the item if previously requested.
+ gAgentWearables.editWearableIfRequested(item_id);
+
+ // 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();
+ }
+ }
+}
+
+LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy()
+{
+ if (!LLApp::isExiting())
+ {
+ LLAppearanceMgr::instance().updateAppearanceFromCOF(
+ true,true,
+ boost::bind(edit_wearable_and_customize_avatar, mItemID));
+ }
+}
+
+
struct LLFoundData
{
LLFoundData() :
@@ -593,6 +618,8 @@ public:
bool isMostRecent();
void handleLateArrivals();
void resetTime(F32 timeout);
+ static S32 countActive() { return sActiveHoldingPatterns.size(); }
+ S32 index() { return mIndex; }
private:
found_list_t mFoundList;
@@ -606,12 +633,15 @@ private:
bool mFired;
typedef std::set<LLWearableHoldingPattern*> type_set_hp;
static type_set_hp sActiveHoldingPatterns;
+ static S32 sNextIndex;
+ S32 mIndex;
bool mIsMostRecent;
std::set<LLViewerWearable*> mLateArrivals;
bool mIsAllComplete;
};
LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns;
+S32 LLWearableHoldingPattern::sNextIndex = 0;
LLWearableHoldingPattern::LLWearableHoldingPattern():
mResolved(0),
@@ -619,10 +649,10 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():
mIsMostRecent(true),
mIsAllComplete(false)
{
- if (sActiveHoldingPatterns.size()>0)
+ if (countActive()>0)
{
llinfos << "Creating LLWearableHoldingPattern when "
- << sActiveHoldingPatterns.size()
+ << countActive()
<< " other attempts are active."
<< " Flagging others as invalid."
<< llendl;
@@ -634,7 +664,9 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():
}
}
+ mIndex = sNextIndex++;
sActiveHoldingPatterns.insert(this);
+ LL_DEBUGS("Avatar") << "HP " << index() << " created" << llendl;
selfStartPhase("holding_pattern");
}
@@ -645,6 +677,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern()
{
selfStopPhase("holding_pattern");
}
+ LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << llendl;
}
bool LLWearableHoldingPattern::isMostRecent()
@@ -692,7 +725,7 @@ void LLWearableHoldingPattern::checkMissingWearables()
if (!isMostRecent())
{
// runway why don't we actually skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
std::vector<S32> found_by_type(LLWearableType::WT_COUNT,0);
@@ -710,7 +743,7 @@ void LLWearableHoldingPattern::checkMissingWearables()
{
if (requested_by_type[type] > found_by_type[type])
{
- llwarns << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl;
+ llwarns << self_av_string() << "HP " << index() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl;
}
if (found_by_type[type] > 0)
continue;
@@ -727,13 +760,16 @@ void LLWearableHoldingPattern::checkMissingWearables()
mTypesToRecover.insert(type);
mTypesToLink.insert(type);
recoverMissingWearable((LLWearableType::EType)type);
- llwarns << self_av_string() << "need to replace " << type << llendl;
+ llwarns << self_av_string() << "HP " << index() << " need to replace wearable of type " << type << llendl;
}
}
resetTime(60.0F);
- selfStartPhase("get_missing_wearables");
+ if (isMostRecent())
+ {
+ selfStartPhase("get_missing_wearables_2");
+ }
if (!pollMissingWearables())
{
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this));
@@ -750,13 +786,13 @@ void LLWearableHoldingPattern::onAllComplete()
if (!isMostRecent())
{
// runway need to skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
// Activate all gestures in this folder
if (mGestItems.count() > 0)
{
- LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.count() << " gestures" << LL_ENDL;
+ LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " activating " << mGestItems.count() << " gestures" << LL_ENDL;
LLGestureMgr::instance().activateGestures(mGestItems);
@@ -773,13 +809,13 @@ void LLWearableHoldingPattern::onAllComplete()
}
// Update wearables.
- LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL;
- LLAppearanceMgr::instance().updateAgentWearables(this, false);
+ LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " << mResolved << " wearable items " << LL_ENDL;
+ LLAppearanceMgr::instance().updateAgentWearables(this);
// Update attachments to match those requested.
if (isAgentAvatarValid())
{
- LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.count() << " attachments" << LL_ENDL;
+ LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " updating " << mObjItems.count() << " attachments" << LL_ENDL;
LLAgentWearables::userUpdateAttachments(mObjItems);
}
@@ -797,12 +833,15 @@ void LLWearableHoldingPattern::onAllComplete()
void LLWearableHoldingPattern::onFetchCompletion()
{
- selfStopPhase("get_wearables");
+ if (isMostRecent())
+ {
+ selfStopPhase("get_wearables_2");
+ }
if (!isMostRecent())
{
// runway skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
checkMissingWearables();
@@ -814,7 +853,7 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
if (!isMostRecent())
{
// runway skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
bool completed = isFetchCompleted();
@@ -823,14 +862,14 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
if (done)
{
- LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out
+ LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out
<< " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL;
mFired = true;
if (timed_out)
{
- llwarns << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl;
}
onFetchCompletion();
@@ -841,82 +880,77 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)
{
if (!holder->isMostRecent())
- {
- llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- // runway skip here?
- }
+ {
+ llwarns << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ // runway skip here?
+ }
- llinfos << "Recovered item link for type " << type << llendl;
+ llinfos << "HP " << holder->index() << " recovered item link for type " << type << llendl;
holder->eraseTypeToLink(type);
- // Add wearable to FoundData for actual wearing
- LLViewerInventoryItem *item = gInventory.getItem(item_id);
- LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
+ // Add wearable to FoundData for actual wearing
+ LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
- if (linked_item)
- {
- gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID());
+ if (linked_item)
+ {
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID());
- if (item)
- {
- LLFoundData found(linked_item->getUUID(),
- linked_item->getAssetUUID(),
- linked_item->getName(),
- linked_item->getType(),
- linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID,
- true // is replacement
- );
+ if (item)
+ {
+ LLFoundData found(linked_item->getUUID(),
+ linked_item->getAssetUUID(),
+ linked_item->getName(),
+ linked_item->getType(),
+ linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID,
+ true // is replacement
+ );
found.mWearable = wearable;
holder->getFoundList().push_front(found);
- }
- else
- {
- llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl;
- }
}
else
{
- llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl;
+ llwarns << self_av_string() << "HP " << holder->index() << " inventory item not found for recovered wearable" << llendl;
}
}
+ else
+ {
+ llwarns << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << llendl;
+ }
+}
void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)
{
if (!holder->isMostRecent())
- {
- // runway skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
- }
+ {
+ // runway skip here?
+ llwarns << self_av_string() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ }
- LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL;
- LLViewerInventoryItem *itemp = gInventory.getItem(item_id);
+ LL_DEBUGS("Avatar") << self_av_string() << "HP " << holder->index() << " recovered item for type " << type << LL_ENDL;
+ LLConstPointer<LLInventoryObject> itemp = gInventory.getItem(item_id);
wearable->setItemID(item_id);
- LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder));
holder->eraseTypeToRecover(type);
- llassert(itemp);
- if (itemp)
- {
- link_inventory_item( gAgent.getID(),
- item_id,
- LLAppearanceMgr::instance().getCOF(),
- itemp->getName(),
- itemp->getDescription(),
- LLAssetType::AT_LINK,
- cb);
- }
+ llassert(itemp);
+ if (itemp)
+ {
+ LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder));
+
+ link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb);
}
+}
void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)
{
if (!isMostRecent())
{
// runway skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
// Try to recover by replacing missing wearable with a new one.
LLNotificationsUtil::add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearableType::getTypeLabel(type)
- << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
+ LL_DEBUGS("Avatar") << "HP " << index() << " wearable " << LLWearableType::getTypeLabel(type)
+ << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
// Add a new one in the lost and found folder.
@@ -949,7 +983,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables()
if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable))
{
// Wearable link that was never resolved; remove links to it from COF
- LL_INFOS("Avatar") << self_av_string() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL;
+ LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL;
LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID);
}
}
@@ -960,7 +994,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()
if (!isMostRecent())
{
// runway skip here?
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
bool timed_out = isTimedOut();
@@ -969,7 +1003,7 @@ bool LLWearableHoldingPattern::pollMissingWearables()
if (!done)
{
- LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size()
+ LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size()
<< " links " << mTypesToLink.size()
<< " wearables, timed out " << timed_out
<< " elapsed " << mWaitTime.getElapsedTimeF32()
@@ -978,7 +1012,10 @@ bool LLWearableHoldingPattern::pollMissingWearables()
if (done)
{
- selfStopPhase("get_missing_wearables");
+ if (isMostRecent())
+ {
+ selfStopPhase("get_missing_wearables_2");
+ }
gAgentAvatarp->debugWearablesLoaded();
@@ -1009,14 +1046,14 @@ void LLWearableHoldingPattern::handleLateArrivals()
}
if (!isMostRecent())
{
- llwarns << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " late arrivals not handled - outfit change no longer valid" << llendl;
}
if (!mIsAllComplete)
{
- llwarns << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " late arrivals not handled - in middle of missing wearables processing" << llendl;
}
- LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL;
+ LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL;
// Update mFoundList using late-arriving wearables.
std::set<LLWearableType::EType> replaced_types;
@@ -1079,7 +1116,7 @@ void LLWearableHoldingPattern::handleLateArrivals()
mLateArrivals.clear();
// Update appearance based on mFoundList
- LLAppearanceMgr::instance().updateAgentWearables(this, false);
+ LLAppearanceMgr::instance().updateAgentWearables(this);
}
void LLWearableHoldingPattern::resetTime(F32 timeout)
@@ -1092,19 +1129,19 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)
{
if (!isMostRecent())
{
- llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
}
mResolved += 1; // just counting callbacks, not successes.
- LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL;
+ LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL;
if (!wearable)
{
- llwarns << self_av_string() << "no wearable found" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " " << "no wearable found" << llendl;
}
if (mFired)
{
- llwarns << self_av_string() << "called after holder fired" << llendl;
+ llwarns << self_av_string() << "HP " << index() << " " << "called after holder fired" << llendl;
if (wearable)
{
mLateArrivals.insert(wearable);
@@ -1130,7 +1167,9 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)
// Failing this means inventory or asset server are corrupted in a way we don't handle.
if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType))
{
- llwarns << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl;
+ llwarns << self_av_string() << "HP " << index() << " "
+ << "recovered wearable but type invalid. inventory wearable type: "
+ << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl;
break;
}
@@ -1203,8 +1242,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 +1308,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:
@@ -1290,7 +1332,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
{
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
- copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb);
+ copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
return false;
}
else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
@@ -1310,15 +1352,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 +1376,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);
@@ -1457,6 +1509,58 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds
gInventory.notifyObservers();
}
+void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
+ bool include_folder_links, LLPointer<LLInventoryCallback> cb)
+{
+ LLInventoryModel::cat_array_t* cats;
+ LLInventoryModel::item_array_t* items;
+ LLSD contents = LLSD::emptyArray();
+ gInventory.getDirectDescendentsOf(src_id, cats, items);
+ llinfos << "copying " << items->count() << " items" << llendl;
+ for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();
+ iter != items->end();
+ ++iter)
+ {
+ const LLViewerInventoryItem* item = (*iter);
+ switch (item->getActualType())
+ {
+ case LLAssetType::AT_LINK:
+ {
+ LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << llendl;
+ //getActualDescription() is used for a new description
+ //to propagate ordering information saved in descriptions of links
+ LLSD item_contents;
+ item_contents["name"] = item->getName();
+ item_contents["desc"] = item->getActualDescription();
+ item_contents["linked_id"] = item->getLinkedUUID();
+ item_contents["type"] = LLAssetType::AT_LINK;
+ contents.append(item_contents);
+ break;
+ }
+ case LLAssetType::AT_LINK_FOLDER:
+ {
+ LLViewerInventoryCategory *catp = item->getLinkedCategory();
+ if (catp && include_folder_links)
+ {
+ LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << llendl;
+ LLSD base_contents;
+ base_contents["name"] = catp->getName();
+ base_contents["desc"] = ""; // categories don't have descriptions.
+ base_contents["linked_id"] = catp->getLinkedUUID();
+ base_contents["type"] = LLAssetType::AT_LINK_FOLDER;
+ contents.append(base_contents);
+ }
+ break;
+ }
+ default:
+ {
+ // Linux refuses to compile unless all possible enums are handled. Really, Linux?
+ break;
+ }
+ }
+ }
+ slam_inventory_folder(dst_id, contents, cb);
+}
// Copy contents of src_id to dst_id.
void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb)
@@ -1465,6 +1569,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(src_id, cats, items);
llinfos << "copying " << items->count() << " items" << llendl;
+ LLInventoryObject::const_object_list_t link_array;
for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();
iter != items->end();
++iter)
@@ -1474,14 +1579,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
{
case LLAssetType::AT_LINK:
{
- //getActualDescription() is used for a new description
- //to propagate ordering information saved in descriptions of links
- link_inventory_item(gAgent.getID(),
- item->getLinkedUUID(),
- dst_id,
- item->getName(),
- item->getActualDescription(),
- LLAssetType::AT_LINK, cb);
+ LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << llendl;
+ link_array.push_back(LLConstPointer<LLInventoryObject>(item));
break;
}
case LLAssetType::AT_LINK_FOLDER:
@@ -1490,12 +1589,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
// Skip copying outfit links.
if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT)
{
- link_inventory_item(gAgent.getID(),
- item->getLinkedUUID(),
- dst_id,
- item->getName(),
- item->getDescription(),
- LLAssetType::AT_LINK_FOLDER, cb);
+ LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << llendl;
+ link_array.push_back(LLConstPointer<LLInventoryObject>(item));
}
break;
}
@@ -1504,7 +1599,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
case LLAssetType::AT_BODYPART:
case LLAssetType::AT_GESTURE:
{
- llinfos << "copying inventory item " << item->getName() << llendl;
+ LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << llendl;
copy_inventory_item(gAgent.getID(),
item->getPermissions().getOwner(),
item->getUUID(),
@@ -1518,6 +1613,10 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL
break;
}
}
+ if (!link_array.empty())
+ {
+ link_inventory_array(dst_id, link_array, cb);
+ }
}
BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id)
@@ -1582,15 +1681,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 +1698,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 +1717,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,46 +1732,14 @@ 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)
-{
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(category, cats, items,
- LLInventoryModel::EXCLUDE_TRASH);
- for (S32 i = 0; i < items.count(); ++i)
- {
- LLViewerInventoryItem *item = items.get(i);
- if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER))
- continue;
- if (item->getIsLinkType())
- {
-#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());
- }
-#endif
- }
-}
-
// Keep the last N wearables of each type. For viewer 2.0, N is 1 for
// both body parts and clothing items.
void LLAppearanceMgr::filterWearableItems(
@@ -1713,33 +1764,14 @@ void LLAppearanceMgr::filterWearableItems(
}
}
-// Create links to all listed items.
-void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
- LLInventoryModel::item_array_t& items,
- LLPointer<LLInventoryCallback> cb)
-{
- for (S32 i=0; i<items.count(); i++)
- {
- const LLInventoryItem* item = items.get(i).get();
- link_inventory_item(gAgent.getID(),
- item->getLinkedUUID(),
- cat_uuid,
- item->getName(),
- item->getActualDescription(),
- LLAssetType::AT_LINK,
- cb);
-
- const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid);
- const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND";
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL;
-#endif
- }
-}
-
void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
{
LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
+ if (!pcat)
+ {
+ llwarns << "no category found for id " << category << llendl;
+ return;
+ }
LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;
const LLUUID cof = getCOF();
@@ -1748,7 +1780,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 +1797,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 +1808,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 +1817,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.
@@ -1803,23 +1835,56 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
all_items += obj_items;
all_items += gest_items;
+ // Find any wearables that need description set to enforce ordering.
+ desc_map_t desc_map;
+ getWearableOrderingDescUpdates(wear_items, desc_map);
+
// Will link all the above items.
- LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
- linkAll(cof,all_items,link_waiter);
+ // link_waiter enforce flags are false because we've already fixed everything up in updateCOF().
+ LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(false,false);
+ LLSD contents = LLSD::emptyArray();
- // Add link to outfit if category is an outfit.
- if (!append)
+ for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin();
+ it != all_items.end(); ++it)
{
- createBaseOutfitLink(category, link_waiter);
- }
+ LLSD item_contents;
+ LLInventoryItem *item = *it;
- // Remove current COF contents. Have to do this after creating
- // 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();
+ std::string desc;
+ desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID());
+ if (desc_iter != desc_map.end())
+ {
+ desc = desc_iter->second;
+ LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc
+ << " (was: " << item->getActualDescription() << ")" << llendl;
+ }
+ else
+ {
+ desc = item->getActualDescription();
+ }
+
+ item_contents["name"] = item->getName();
+ item_contents["desc"] = desc;
+ item_contents["linked_id"] = item->getLinkedUUID();
+ item_contents["type"] = LLAssetType::AT_LINK;
+ contents.append(item_contents);
+ }
+ const LLUUID& base_id = append ? getBaseOutfitUUID() : category;
+ LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id);
+ if (base_cat)
+ {
+ LLSD base_contents;
+ base_contents["name"] = base_cat->getName();
+ base_contents["desc"] = "";
+ base_contents["linked_id"] = base_cat->getLinkedUUID();
+ base_contents["type"] = LLAssetType::AT_LINK_FOLDER;
+ contents.append(base_contents);
+ }
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents);
+ }
+ slam_inventory_folder(getCOF(), contents, link_waiter);
LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;
}
@@ -1840,21 +1905,21 @@ 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)
{
- link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "",
- LLAssetType::AT_LINK_FOLDER, link_waiter);
+ link_inventory_object(cof, catp, link_waiter);
new_outfit_name = catp->getName();
}
updatePanelOutfitName(new_outfit_name);
}
-void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append)
+void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder)
{
- lldebugs << "updateAgentWearables()" << llendl;
+ LL_DEBUGS("Avatar") << "starts" << llendl;
+ LLTimer timer;
LLInventoryItem::item_array_t items;
LLDynamicArray< LLViewerWearable* > wearables;
@@ -1880,8 +1945,14 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
if(wearables.count() > 0)
{
- gAgentWearables.setWearableOutfit(items, wearables, !append);
+ gAgentWearables.setWearableOutfit(items, wearables);
}
+ LL_DEBUGS("Avatar") << "ends, elapsed " << timer.getElapsedTimeF32() << llendl;
+}
+
+S32 LLAppearanceMgr::countActiveHoldingPatterns()
+{
+ return LLWearableHoldingPattern::countActive();
}
static void remove_non_link_items(LLInventoryModel::item_array_t &items)
@@ -1932,12 +2003,12 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list,
S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
LLAssetType::EType type,
S32 max_items,
- LLInventoryModel::item_array_t& items_to_kill)
+ LLInventoryObject::object_list_t& items_to_kill)
{
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)
@@ -1950,40 +2021,39 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id,
it != kill_items.end();
++it)
{
- items_to_kill.push_back(*it);
+ items_to_kill.push_back(LLPointer<LLInventoryObject>(*it));
to_kill_count++;
}
return to_kill_count;
}
-
-void LLAppearanceMgr::enforceItemRestrictions()
-{
- S32 purge_count = 0;
- LLInventoryModel::item_array_t items_to_kill;
- purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART,
- 1, items_to_kill);
- purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING,
- LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
- purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT,
- -1, items_to_kill);
+void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id,
+ LLInventoryObject::object_list_t& items_to_kill)
+{
+ findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART,
+ 1, items_to_kill);
+ findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING,
+ LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill);
+ findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT,
+ -1, items_to_kill);
+}
+void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb)
+{
+ LLInventoryObject::object_list_t items_to_kill;
+ findAllExcessOrDuplicateItems(getCOF(), items_to_kill);
if (items_to_kill.size()>0)
{
- for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin();
- it != items_to_kill.end();
- ++it)
- {
- LLViewerInventoryItem *item = *it;
- LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL;
- gInventory.purgeObject(item->getUUID());
- }
- gInventory.notifyObservers();
+ // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
+ // this should catch anything that gets through.
+ remove_inventory_items(items_to_kill, cb);
}
}
-void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
+void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions,
+ bool enforce_ordering,
+ nullary_func_t post_update_func)
{
if (mIsInUpdateAppearanceFromCOF)
{
@@ -1991,19 +2061,43 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
return;
}
- BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
- selfStartPhase("update_appearance_from_cof");
-
LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL;
- //checking integrity of the COF in terms of ordering of wearables,
- //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
- updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering);
+ if (enforce_item_restrictions)
+ {
+ // The point here is just to call
+ // updateAppearanceFromCOF() again after excess items
+ // have been removed. That time we will set
+ // enforce_item_restrictions to false so we don't get
+ // caught in a perpetual loop.
+ LLPointer<LLInventoryCallback> cb(
+ new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func));
+ enforceCOFItemRestrictions(cb);
+ return;
+ }
+
+ if (enforce_ordering)
+ {
+ //checking integrity of the COF in terms of ordering of wearables,
+ //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state)
+
+ // As with enforce_item_restrictions handling above, we want
+ // to wait for the update callbacks, then (finally!) call
+ // updateAppearanceFromCOF() with no additional COF munging needed.
+ LLPointer<LLInventoryCallback> cb(
+ new LLUpdateAppearanceOnDestroy(false, false, post_update_func));
+ updateClothingOrderingInfo(LLUUID::null, cb);
+ return;
+ }
+
+ if (!validateClothingOrderingInfo())
+ {
+ llwarns << "Clothing ordering error" << llendl;
+ }
+
+ BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF);
+ selfStartPhase("update_appearance_from_cof");
- // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but
- // this should catch anything that gets through.
- enforceItemRestrictions();
-
// update dirty flag to see if the state of the COF matches
// the saved outfit stored as a folder link
updateIsDirty();
@@ -2013,13 +2107,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
{
requestServerAppearanceUpdate();
}
- // DRANO really should wait for the appearance message to set this.
- // verify that deleting this line doesn't break anything.
- //gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion());
-
- //dumpCat(getCOF(),"COF, start");
- bool follow_folder_links = false;
LLUUID current_outfit_id = getCOF();
// Find all the wearables that are in the COF's subtree.
@@ -2027,7 +2115,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);
@@ -2046,6 +2134,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
sortItemsByActualDescription(wear_items);
+ LL_DEBUGS("Avatar") << "HP block starts" << llendl;
+ LLTimer hp_block_timer;
LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
holder->setObjItems(obj_items);
@@ -2095,7 +2185,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
}
}
- selfStartPhase("get_wearables");
+ selfStartPhase("get_wearables_2");
for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin();
it != holder->getFoundList().end(); ++it)
@@ -2119,12 +2209,14 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
{
doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder));
}
+ post_update_func();
+
+ LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << llendl;
}
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 +2224,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 +2238,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 +2246,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 +2255,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)
@@ -2183,10 +2270,36 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName()
<< " )" << LL_ENDL;
- selfStartPhase("wear_inventory_category_fetch");
- callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
- &LLAppearanceMgr::instance(),
- category->getUUID(), copy, append));
+ // If we are copying from library, attempt to use AIS to copy the category.
+ bool ais_ran=false;
+ if (copy && AISCommand::isAPIAvailable())
+ {
+ LLUUID parent_id;
+ parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
+ if (parent_id.isNull())
+ {
+ parent_id = gInventory.getRootFolderID();
+ }
+
+ LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append);
+ LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper(
+ std::string("wear_inventory_category_callback"), copy_cb);
+ LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb);
+ ais_ran=cmd_ptr->run_command();
+ }
+
+ if (!ais_ran)
+ {
+ selfStartPhase("wear_inventory_category_fetch");
+ callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
+ &LLAppearanceMgr::instance(),
+ category->getUUID(), copy, append));
+ }
+}
+
+S32 LLAppearanceMgr::getActiveCopyOperations() const
+{
+ return LLCallAfterInventoryCopyMgr::getInstanceCount();
}
void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append)
@@ -2267,7 +2380,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
// Avoid unintentionally overwriting old wearables. We have to do
// this up front to avoid having to deal with the case of multiple
// wearables being dirty.
- if(!category) return;
+ if (!category) return;
if ( !LLInventoryCallbackManager::is_instantiated() )
{
@@ -2287,6 +2400,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 +2454,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 +2471,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 +2485,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)
-{
- std::string link_description = description;
+void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item,
+ LLPointer<LLInventoryCallback> cb,
+ const std::string description)
+{
const LLViewerInventoryItem *vitem = dynamic_cast<const LLViewerInventoryItem*>(item);
if (!vitem)
{
@@ -2448,43 +2544,23 @@ 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 (!linked_already)
{
- if (do_update)
- {
- LLAppearanceMgr::updateAppearanceFromCOF();
- }
- return;
- }
- else
- {
- if(do_update && cb.isNull())
- {
- cb = new LLBoostFuncInventoryCallback(modified_cof_cb);
- }
- if (vitem->getIsLinkType())
- {
- link_description = vitem->getActualDescription();
- }
- link_inventory_item( gAgent.getID(),
- vitem->getLinkedUUID(),
- getCOF(),
- vitem->getName(),
- link_description,
- LLAssetType::AT_LINK,
- cb);
+ LLViewerInventoryItem *copy_item = new LLViewerInventoryItem;
+ copy_item->copyViewerItem(vitem);
+ copy_item->setDescription(description);
+ link_inventory_object(getCOF(), copy_item, cb);
}
- return;
}
LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id)
@@ -2524,8 +2600,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 +2644,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 +2659,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 +2677,7 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type)
const LLViewerInventoryItem* item = *it;
if (item->getIsLinkType()) // we must operate on links only
{
- gInventory.purgeObject(item->getUUID());
+ remove_inventory_item(item->getUUID(), cb);
}
}
}
@@ -2641,7 +2716,7 @@ void LLAppearanceMgr::updateIsDirty()
if (base_outfit.notNull())
{
- LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK);
+ LLIsValidItemLink collector;
LLInventoryModel::cat_array_t cof_cats;
LLInventoryModel::item_array_t cof_items;
@@ -2655,6 +2730,7 @@ void LLAppearanceMgr::updateIsDirty()
if(outfit_items.count() != cof_items.count())
{
+ LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.count() << " cof " << cof_items.count() << llendl;
// Current outfit folder should have one more item than the outfit folder.
// this one item is the link back to the outfit folder itself.
mOutfitIsDirty = true;
@@ -2674,11 +2750,30 @@ void LLAppearanceMgr::updateIsDirty()
item1->getName() != item2->getName() ||
item1->getActualDescription() != item2->getActualDescription())
{
+ if (item1->getLinkedUUID() != item2->getLinkedUUID())
+ {
+ LL_DEBUGS("Avatar") << "link id different " << llendl;
+ }
+ else
+ {
+ if (item1->getName() != item2->getName())
+ {
+ LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << llendl;
+ }
+ if (item1->getActualDescription() != item2->getActualDescription())
+ {
+ LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription()
+ << " " << item2->getActualDescription()
+ << " names " << item1->getName() << " " << item2->getName() << llendl;
+ }
+ }
mOutfitIsDirty = true;
return;
}
}
}
+ llassert(!mOutfitIsDirty);
+ LL_DEBUGS("Avatar") << "clean" << llendl;
}
// *HACK: Must match name in Library or agent inventory
@@ -2760,23 +2855,6 @@ void LLAppearanceMgr::copyLibraryGestures()
}
}
-void LLAppearanceMgr::autopopulateOutfits()
-{
- // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account)
- // then auto-populate outfits from the library into the My Outfits folder.
-
- LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL;
-
- static bool check_populate_my_outfits = true;
- if (check_populate_my_outfits &&
- (LLInventoryModel::getIsFirstTimeInViewer2()
- || gSavedSettings.getBOOL("MyOutfitsAutofill")))
- {
- gAgentWearables.populateMyOutfitsFolder();
- }
- check_populate_my_outfits = false;
-}
-
// Handler for anything that's deferred until avatar de-clouds.
void LLAppearanceMgr::onFirstFullyVisible()
{
@@ -2784,10 +2862,6 @@ void LLAppearanceMgr::onFirstFullyVisible()
gAgentAvatarp->reportAvatarRezTime();
gAgentAvatarp->debugAvatarVisible();
- // The auto-populate is failing at the point of generating outfits
- // folders, so don't do the library copy until that is resolved.
- // autopopulateOutfits();
-
// If this is the first time we've ever logged in,
// then copy default gestures from the library.
if (gAgent.isFirstLogin()) {
@@ -2802,9 +2876,27 @@ void appearance_mgr_update_dirty_state()
if (LLAppearanceMgr::instanceExists())
{
LLAppearanceMgr::getInstance()->updateIsDirty();
+ LLAppearanceMgr::getInstance()->setOutfitLocked(false);
+ gAgentWearables.notifyLoadingFinished();
}
}
+void update_base_outfit_after_ordering()
+{
+ LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance();
+
+ LLPointer<LLInventoryCallback> dirty_state_updater =
+ new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state);
+
+ //COF contains only links so we copy to the Base Outfit only links
+ const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID();
+ bool copy_folder_links = false;
+ app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater);
+
+}
+
+// Save COF changes - update the contents of the current base outfit
+// to match the current COF. Fails if no current base outfit is set.
bool LLAppearanceMgr::updateBaseOutfit()
{
if (isOutfitLocked())
@@ -2813,23 +2905,20 @@ bool LLAppearanceMgr::updateBaseOutfit()
llassert(!isOutfitLocked());
return false;
}
+
setOutfitLocked(true);
gAgentWearables.notifyLoadingStarted();
const LLUUID base_outfit_id = getBaseOutfitUUID();
if (base_outfit_id.isNull()) return false;
+ LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << llendl;
- updateClothingOrderingInfo();
-
- // in a Base Outfit we do not remove items, only links
- purgeCategory(base_outfit_id, false);
-
- LLPointer<LLInventoryCallback> dirty_state_updater =
- new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state);
-
- //COF contains only links so we copy to the Base Outfit only links
- shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater);
+ LLPointer<LLInventoryCallback> cb =
+ new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering);
+ // Really shouldn't be needed unless there's a race condition -
+ // updateAppearanceFromCOF() already calls updateClothingOrderingInfo.
+ updateClothingOrderingInfo(LLUUID::null, cb);
return true;
}
@@ -2877,12 +2966,6 @@ struct WearablesOrderComparator
bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)
{
- if (!item1 || !item2)
- {
- llwarning("either item1 or item2 is NULL", 0);
- return true;
- }
-
const std::string& desc1 = item1->getActualDescription();
const std::string& desc2 = item2->getActualDescription();
@@ -2896,260 +2979,374 @@ struct WearablesOrderComparator
//items with ordering information but not for the associated wearables type
if (!item1_valid && item2_valid)
return false;
+ else if (item1_valid && !item2_valid)
+ return true;
- return true;
+ return item1->getName() < item2->getName();
}
U32 mControlSize;
};
-void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering)
+void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items,
+ desc_map_t& desc_map)
{
- if (cat_id.isNull())
- {
- cat_id = getCOF();
- if (update_base_outfit_ordering)
- {
- const LLUUID base_outfit_id = getBaseOutfitUUID();
- if (base_outfit_id.notNull())
- {
- updateClothingOrderingInfo(base_outfit_id,false);
- }
- }
- }
-
- // COF is processed if cat_id is not specified
- LLInventoryModel::item_array_t wear_items;
- getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false);
-
wearables_by_type_t items_by_type(LLWearableType::WT_COUNT);
divvyWearablesByType(wear_items, items_by_type);
- bool inventory_changed = false;
for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++)
{
-
U32 size = items_by_type[type].size();
if (!size) continue;
-
+
//sinking down invalid items which need reordering
std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type));
-
+
//requesting updates only for those links which don't have "valid" descriptions
for (U32 i = 0; i < size; i++)
{
LLViewerInventoryItem* item = items_by_type[type][i];
if (!item) continue;
-
+
std::string new_order_str = build_order_string((LLWearableType::EType)type, i);
if (new_order_str == item->getActualDescription()) continue;
-
- item->setDescription(new_order_str);
- item->setComplete(TRUE);
- item->updateServer(FALSE);
- gInventory.updateItem(item);
- inventory_changed = true;
+ desc_map[item->getUUID()] = new_order_str;
}
}
-
- //*TODO do we really need to notify observers?
- if (inventory_changed) gInventory.notifyObservers();
}
-// This is intended for use with HTTP Clients/Responders, but is not
-// specifically coupled with those classes.
-class LLHTTPRetryPolicy: public LLThreadSafeRefCount
+bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id)
{
-public:
- LLHTTPRetryPolicy() {}
- virtual ~LLHTTPRetryPolicy() {}
- virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0;
-};
+ // COF is processed if cat_id is not specified
+ if (cat_id.isNull())
+ {
+ cat_id = getCOF();
+ }
-// Example of simplest possible policy, not necessarily recommended.
-class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy
-{
-public:
- LLAlwaysRetryImmediatelyPolicy() {}
- bool shouldRetry(U32 status, F32& seconds_to_wait)
+ LLInventoryModel::item_array_t wear_items;
+ getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING);
+
+ // Identify items for which desc needs to change.
+ desc_map_t desc_map;
+ getWearableOrderingDescUpdates(wear_items, desc_map);
+
+ for (desc_map_t::const_iterator it = desc_map.begin();
+ it != desc_map.end(); ++it)
{
- seconds_to_wait = 0.0;
- return true;
+ const LLUUID& item_id = it->first;
+ const std::string& new_order_str = it->second;
+ LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ llwarns << "Order validation fails: " << item->getName()
+ << " needs to update desc to: " << new_order_str
+ << " (from: " << item->getActualDescription() << ")" << llendl;
}
-};
+
+ return desc_map.size() == 0;
+}
-// Very general policy with geometric back-off after failures,
-// up to a maximum delay, and maximum number of retries.
-class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy
+void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,
+ LLPointer<LLInventoryCallback> cb)
{
-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)
+ // COF is processed if cat_id is not specified
+ if (cat_id.isNull())
{
+ cat_id = getCOF();
}
- bool shouldRetry(U32 status, F32& seconds_to_wait)
+ LLInventoryModel::item_array_t wear_items;
+ getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING);
+
+ // Identify items for which desc needs to change.
+ desc_map_t desc_map;
+ getWearableOrderingDescUpdates(wear_items, desc_map);
+
+ for (desc_map_t::const_iterator it = desc_map.begin();
+ it != desc_map.end(); ++it)
{
- seconds_to_wait = mDelay;
- mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay);
- mRetryCount++;
- return (mRetryCount<=mMaxRetries);
+ LLSD updates;
+ const LLUUID& item_id = it->first;
+ const std::string& new_order_str = it->second;
+ LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str
+ << " (was: " << item->getActualDescription() << ")" << llendl;
+ updates["desc"] = new_order_str;
+ update_inventory_item(item_id,updates,cb);
}
+
+}
+
+class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
+{
+ LOG_CLASS(RequestAgentUpdateAppearanceResponder);
+
+ friend class LLAppearanceMgr;
+
+public:
+ RequestAgentUpdateAppearanceResponder();
+
+ virtual ~RequestAgentUpdateAppearanceResponder();
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.
+ // Called when sendServerAppearanceUpdate called. May or may not
+ // trigger a request depending on various bits of state.
+ void onRequestRequested();
+
+ // Post the actual appearance request to cap.
+ void sendRequest();
+
+ void debugCOF(const LLSD& content);
+
+protected:
+ // Successful completion.
+ /* virtual */ void httpSuccess();
+
+ // Error
+ /*virtual*/ void httpFailure();
+
+ void onFailure();
+ void onSuccess();
+
+ S32 mInFlightCounter;
+ LLTimer mInFlightTimer;
+ LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
};
-class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
+RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder()
{
-public:
- RequestAgentUpdateAppearanceResponder()
+ bool retry_on_4xx = true;
+ mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx);
+ mInFlightCounter = 0;
+}
+
+RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder()
+{
+}
+
+void RequestAgentUpdateAppearanceResponder::onRequestRequested()
+{
+ // If we have already received an update for this or higher cof version, ignore.
+ S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
+ S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion;
+ S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion;
+ LL_DEBUGS("Avatar") << "cof_version " << cof_version
+ << " last_rcv " << last_rcv
+ << " last_req " << last_req
+ << " in flight " << mInFlightCounter << llendl;
+ if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired()))
{
- mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
+ LL_WARNS("Avatar") << "in flight timer expired, resetting " << llendl;
+ mInFlightCounter = 0;
}
-
- virtual ~RequestAgentUpdateAppearanceResponder()
+ if (cof_version < last_rcv)
{
+ LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
+ << " will not request for " << cof_version << llendl;
+ return;
}
-
- // Successful completion.
- /* virtual */ void result(const LLSD& content)
+ if (mInFlightCounter>0 && last_req >= cof_version)
{
- LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL;
- if (content["success"].asBoolean())
- {
- LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
- dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
- }
- }
- else
- {
- onFailure(200);
- }
+ LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
+ << " will not request for " << cof_version << llendl;
+ return;
}
- // Error
- /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+ // Actually send the request.
+ LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << llendl;
+ mRetryPolicy->reset();
+ sendRequest();
+}
+
+void RequestAgentUpdateAppearanceResponder::sendRequest()
+{
+ if (gAgentAvatarp->isEditingAppearance())
{
- llwarns << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << llendl;
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
- dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
- debugCOF(content);
-
- }
- onFailure(status);
- }
+ // don't send out appearance updates if in appearance editing mode
+ return;
+ }
- void onFailure(U32 status)
+ if (!gAgent.getRegion())
{
- F32 seconds_to_wait;
- if (mRetryPolicy->shouldRetry(status,seconds_to_wait))
- {
- llinfos << "retrying" << llendl;
- doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate,
- LLAppearanceMgr::getInstance(),
- LLCurl::ResponderPtr(this)),
- seconds_to_wait);
- }
- else
+ llwarns << "Region not set, cannot request server appearance update" << llendl;
+ return;
+ }
+ if (gAgent.getRegion()->getCentralBakeVersion()==0)
+ {
+ llwarns << "Region does not support baking" << llendl;
+ }
+ std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
+ if (url.empty())
+ {
+ llwarns << "No cap for UpdateAvatarAppearance." << llendl;
+ return;
+ }
+
+ LLSD body;
+ S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
+ if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
+ {
+ body = LLAppearanceMgr::instance().dumpCOF();
+ }
+ else
+ {
+ body["cof_version"] = cof_version;
+ if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
{
- llwarns << "giving up after too many retries" << llendl;
+ body["cof_version"] = cof_version+999;
}
- }
-
- void dumpContents(const std::string outprefix, const LLSD& content)
- {
- std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml");
- std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
- std::ofstream ofs(fullpath.c_str(), std::ios_base::out);
- ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY);
- LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL;
}
+ LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl;
- void debugCOF(const LLSD& content)
+ mInFlightCounter++;
+ mInFlightTimer.setTimerExpirySec(60.0);
+ LLHTTPClient::post(url, body, this);
+ llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
+ gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
+}
+
+void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content)
+{
+ 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();
+ it != cof_raw.endArray(); ++it)
{
- LL_DEBUGS("Avatar") << "AIS COF, version found: " << 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();
- it != cof_raw.endArray(); ++it)
+ const LLSD& item = *it;
+ if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF())
{
- const LLSD& item = *it;
- if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF())
+ ais_items.insert(item["item_id"].asUUID());
+ if (item["type"].asInteger() == 24) // link
{
- 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;
- }
- 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 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_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;
- }
+ }
+ else
+ {
+ 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;
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(),
- cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
- for (S32 i=0; i<item_array.count(); i++)
+ }
+ 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(),
+ cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH);
+ for (S32 i=0; i<item_array.count(); i++)
+ {
+ const LLViewerInventoryItem* inv_item = item_array.get(i).get();
+ local_items.insert(inv_item->getUUID());
+ 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())
{
- 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_INFOS("Avatar") << "LOCAL ONLY: " << *it << llendl;
+ local_only++;
}
- LL_DEBUGS("Avatar") << llendl;
- for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
+ }
+ for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
+ {
+ if (local_items.find(*it) == local_items.end())
{
- if (ais_items.find(*it) == ais_items.end())
- {
- LL_DEBUGS("Avatar") << "LOCAL ONLY: " << *it << llendl;
- }
+ LL_INFOS("Avatar") << "AIS ONLY: " << *it << llendl;
+ ais_only++;
}
- for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
+ }
+ 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;
+ }
+}
+
+/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess()
+{
+ const LLSD& content = getContent();
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
+ if (content["success"].asBoolean())
+ {
+ LL_DEBUGS("Avatar") << "succeeded" << llendl;
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
- if (local_items.find(*it) == local_items.end())
- {
- LL_DEBUGS("Avatar") << "AIS ONLY: " << *it << llendl;
- }
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);
}
+
+ onSuccess();
+ }
+ else
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content);
}
+}
+
+void RequestAgentUpdateAppearanceResponder::onSuccess()
+{
+ mInFlightCounter = llmax(mInFlightCounter-1,0);
+}
+
+/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure()
+{
+ LL_WARNS("Avatar") << "appearance update request failed, status "
+ << getStatus() << " reason " << getReason() << LL_ENDL;
+
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ const LLSD& content = getContent();
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
+ debugCOF(content);
+ }
+ onFailure();
+}
+
+void RequestAgentUpdateAppearanceResponder::onFailure()
+{
+ mInFlightCounter = llmax(mInFlightCounter-1,0);
+
+ F32 seconds_to_wait;
+ mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
+ if (mRetryPolicy->shouldRetry(seconds_to_wait))
+ {
+ llinfos << "retrying" << llendl;
+ doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this),
+ seconds_to_wait);
+ }
+ else
+ {
+ llwarns << "giving up after too many retries" << llendl;
+ }
+}
- LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
-};
LLSD LLAppearanceMgr::dumpCOF() const
{
@@ -3214,58 +3411,14 @@ LLSD LLAppearanceMgr::dumpCOF() const
return result;
}
-void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr)
+void LLAppearanceMgr::requestServerAppearanceUpdate()
{
- if (gAgentAvatarp->isEditingAppearance())
- {
- // don't send out appearance updates if in appearance editing mode
- return;
- }
-
- if (!gAgent.getRegion())
- {
- llwarns << "Region not set, cannot request server appearance update" << llendl;
- return;
- }
- if (gAgent.getRegion()->getCentralBakeVersion()==0)
- {
- llwarns << "Region does not support baking" << llendl;
- }
- std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
- if (url.empty())
- {
- llwarns << "No cap for UpdateAvatarAppearance." << llendl;
- return;
- }
-
- LLSD body;
- S32 cof_version = getCOFVersion();
- if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
- {
- body = dumpCOF();
- }
- else
- {
- body["cof_version"] = cof_version;
- if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
- {
- body["cof_version"] = cof_version+999;
- }
- }
- LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl;
-
- //LLCurl::ResponderPtr responder_ptr;
- if (!responder_ptr.get())
- {
- responder_ptr = new RequestAgentUpdateAppearanceResponder;
- }
- LLHTTPClient::post(url, body, responder_ptr);
- llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
- gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
+ mAppearanceResponder->onRequestRequested();
}
class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLIncrementCofVersionResponder);
public:
LLIncrementCofVersionResponder() : LLHTTPClient::Responder()
{
@@ -3276,22 +3429,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 +3467,7 @@ public:
}
}
+private:
LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
};
@@ -3337,6 +3500,15 @@ void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_p
LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);
}
+U32 LLAppearanceMgr::getNumAttachmentsInCOF()
+{
+ const LLUUID cof = getCOF();
+ LLInventoryModel::item_array_t obj_items;
+ getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
+ return obj_items.size();
+}
+
+
std::string LLAppearanceMgr::getAppearanceServiceURL() const
{
if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty())
@@ -3347,57 +3519,91 @@ std::string LLAppearanceMgr::getAppearanceServiceURL() const
}
void show_created_outfit(LLUUID& folder_id, bool show_panel = true)
+{
+ if (!LLApp::isRunning())
{
- if (!LLApp::isRunning())
- {
- llwarns << "called during shutdown, skipping" << llendl;
- return;
- }
-
- LLSD key;
-
+ llwarns << "called during shutdown, skipping" << llendl;
+ return;
+ }
+
+ LL_DEBUGS("Avatar") << "called" << llendl;
+ LLSD key;
+
//EXT-7727. For new accounts inventory callback is created during login process
// and may be processed after login process is finished
if (show_panel)
- {
- LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key);
-
- }
- LLOutfitsList *outfits_list =
- dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab"));
- if (outfits_list)
- {
+ {
+ LL_DEBUGS("Avatar") << "showing panel" << llendl;
+ LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key);
+
+ }
+ LLOutfitsList *outfits_list =
+ dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab"));
+ if (outfits_list)
+ {
outfits_list->setSelectedOutfitByUUID(folder_id);
- }
-
- LLAppearanceMgr::getInstance()->updateIsDirty();
- gAgentWearables.notifyLoadingFinished(); // New outfit is saved.
- LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
}
+
+ 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.
+ LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << llendl;
+ LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
+ LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb);
+}
-LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
+void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel)
{
- if (!isAgentAvatarValid()) return LLUUID::null;
-
- gAgentWearables.notifyLoadingStarted();
+ LLPointer<LLInventoryCallback> cb =
+ new LLBoostFuncInventoryCallback(no_op_inventory_func,
+ boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel));
+ updateClothingOrderingInfo(LLUUID::null, cb);
+}
- // First, make a folder in the My Outfits directory.
- const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- LLUUID folder_id = gInventory.createNewCategory(
- parent_id,
- LLFolderType::FT_OUTFIT,
- new_folder_name);
+void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel)
+{
+ LLPointer<LLInventoryCallback> cb =
+ new LLBoostFuncInventoryCallback(no_op_inventory_func,
+ boost::bind(show_created_outfit,folder_id,show_panel));
+ bool copy_folder_links = false;
+ slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb);
+}
- updateClothingOrderingInfo();
+void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
+{
+ if (!isAgentAvatarValid()) return;
- 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);
+ LL_DEBUGS("Avatar") << "creating new outfit" << llendl;
- dumpCat(folder_id,"COF, new outfit");
+ gAgentWearables.notifyLoadingStarted();
- return folder_id;
+ // First, make a folder in the My Outfits directory.
+ const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+ if (AISCommand::isAPIAvailable())
+ {
+ // cap-based category creation was buggy until recently. use
+ // existence of AIS as an indicator the fix is present. Does
+ // not actually use AIS to create the category.
+ inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel);
+ LLUUID folder_id = gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_OUTFIT,
+ new_folder_name,
+ func);
+ }
+ else
+ {
+ LLUUID folder_id = gInventory.createNewCategory(
+ parent_id,
+ LLFolderType::FT_OUTFIT,
+ new_folder_name);
+ onOutfitFolderCreated(folder_id, show_panel);
+ }
}
void LLAppearanceMgr::wearBaseOutfit()
@@ -3413,21 +3619,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);
- }
- updateAppearanceFromCOF();
+ removeCOFItemLinks(linked_item_id, cb);
}
+}
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)
@@ -3460,7 +3667,12 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b
swap_item->setDescription(item->getActualDescription());
item->setDescription(tmp);
+ // LL_DEBUGS("Inventory") << "swap, item "
+ // << ll_pretty_print_sd(item->asLLSD())
+ // << " swap_item "
+ // << ll_pretty_print_sd(swap_item->asLLSD()) << llendl;
+ // FIXME switch to use AISv3 where supported.
//items need to be updated on a dataserver
item->setComplete(TRUE);
item->updateServer(FALSE);
@@ -3536,7 +3748,8 @@ LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false),
mOutfitLocked(false),
- mIsInUpdateAppearanceFromCOF(false)
+ mIsInUpdateAppearanceFromCOF(false),
+ mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)
{
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
@@ -3586,7 +3799,8 @@ 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.
+ LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy();
+ LLAppearanceMgr::addCOFItemLink(item_id, cb); // Add COF link for item.
}
else
{
@@ -3610,22 +3824,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 +3855,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..3a90c3840a 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -38,6 +38,7 @@
class LLWearableHoldingPattern;
class LLInventoryCallback;
class LLOutfitUnLockTimer;
+class RequestAgentUpdateAppearanceResponder;
class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
{
@@ -49,7 +50,9 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
public:
typedef std::vector<LLInventoryModel::item_array_t> wearables_by_type_t;
- void updateAppearanceFromCOF(bool update_base_outfit_ordering = false);
+ void updateAppearanceFromCOF(bool enforce_item_restrictions = true,
+ bool enforce_ordering = true,
+ nullary_func_t post_update_func = no_op);
bool needToSaveCOF();
void updateCOF(const LLUUID& category, bool append = false);
void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
@@ -64,9 +67,18 @@ public:
S32 findExcessOrDuplicateItems(const LLUUID& cat_id,
LLAssetType::EType type,
S32 max_items,
- LLInventoryModel::item_array_t& items_to_kill);
- void enforceItemRestrictions();
-
+ LLInventoryObject::object_list_t& items_to_kill);
+ void findAllExcessOrDuplicateItems(const LLUUID& cat_id,
+ LLInventoryObject::object_list_t& items_to_kill);
+ void enforceCOFItemRestrictions(LLPointer<LLInventoryCallback> cb);
+
+ S32 getActiveCopyOperations() const;
+
+ // Replace category contents with copied links via the slam_inventory_folder
+ // command (single inventory operation where supported)
+ void slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id,
+ bool include_folder_links, LLPointer<LLInventoryCallback> cb);
+
// Copy all items and the src category itself.
void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id,
LLPointer<LLInventoryCallback> cb);
@@ -105,15 +117,18 @@ 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);
+ void updateAgentWearables(LLWearableHoldingPattern* holder);
+
+ S32 countActiveHoldingPatterns();
// For debugging - could be moved elsewhere.
void dumpCat(const LLUUID& cat_id, const std::string& msg);
@@ -124,21 +139,16 @@ public:
void registerAttachment(const LLUUID& item_id);
void setAttachmentInvLinkEnable(bool val);
- // utility function for bulk linking.
- void linkAll(const LLUUID& category,
- 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();
@@ -152,12 +162,11 @@ public:
// should only be necessary to do on initial login.
void updateIsDirty();
+ void setOutfitLocked(bool locked);
+
// Called when self avatar is first fully visible.
void onFirstFullyVisible();
- // Create initial outfits from library.
- void autopopulateOutfits();
-
// Copy initial gestures from library.
void copyLibraryGestures();
@@ -172,7 +181,10 @@ public:
void removeItemFromAvatar(const LLUUID& item_id);
- LLUUID makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true);
+ void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel);
+ void onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel);
+
+ void makeNewOutfitLinks(const std::string& new_folder_name,bool show_panel = true);
bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
@@ -181,18 +193,27 @@ public:
//Divvy items into arrays by wearable type
static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type);
+ typedef std::map<LLUUID,std::string> desc_map_t;
+
+ void getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, desc_map_t& desc_map);
+
//Check ordering information on wearables stored in links' descriptions and update if it is invalid
// COF is processed if cat_id is not specified
- void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false);
+ bool validateClothingOrderingInfo(LLUUID cat_id = LLUUID::null);
+
+ void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null,
+ LLPointer<LLInventoryCallback> cb = NULL);
bool isOutfitLocked() { return mOutfitLocked; }
bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; }
- void requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr = NULL);
+ void requestServerAppearanceUpdate();
void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL);
+ U32 getNumAttachmentsInCOF();
+
// *HACK Remove this after server side texture baking is deployed on all sims.
void incrementCofVersionLegacy();
@@ -213,24 +234,21 @@ private:
void getDescendentsOfAssetType(const LLUUID& category,
LLInventoryModel::item_array_t& items,
- LLAssetType::EType type,
- bool follow_folder_links);
+ LLAssetType::EType type);
void getUserDescendents(const LLUUID& category,
LLInventoryModel::item_array_t& wear_items,
LLInventoryModel::item_array_t& obj_items,
- LLInventoryModel::item_array_t& gest_items,
- bool follow_folder_links);
+ LLInventoryModel::item_array_t& gest_items);
- void purgeCategory(const LLUUID& category, bool keep_outfit_links, LLInventoryModel::item_array_t* keep_items = NULL);
static void onOutfitRename(const LLSD& notification, const LLSD& response);
- void setOutfitLocked(bool locked);
-
bool mAttachmentInvLinkEnabled;
bool mOutfitIsDirty;
bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
+ LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder;
+
/**
* Lock for blocking operations on outfit until server reply or timeout exceed
* to avoid unsynchronized outfit state or performing duplicate operations.
@@ -256,17 +274,31 @@ public:
class LLUpdateAppearanceOnDestroy: public LLInventoryCallback
{
public:
- LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false);
+ LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions = true,
+ bool enforce_ordering = true,
+ nullary_func_t post_update_func = no_op);
virtual ~LLUpdateAppearanceOnDestroy();
/* virtual */ void fire(const LLUUID& inv_item);
private:
U32 mFireCount;
- bool mUpdateBaseOrder;
+ bool mEnforceItemRestrictions;
+ bool mEnforceOrdering;
+ nullary_func_t mPostUpdateFunc;
};
+class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback
+{
+public:
+ LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id);
+
+ /* virtual */ void fire(const LLUUID& item_id) {}
-#define SUPPORT_ENSEMBLES 0
+ ~LLUpdateAppearanceAndEditWearableOnDestroy();
+
+private:
+ LLUUID mItemID;
+};
LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name);
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 c1630318e8..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,13 +206,13 @@ 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
- << (mDone ? " -- done" : "") << llendl;
+ llwarns << dumpResponse()
+ << " [count:" << mCount << "] "
+ << (mDone ? " -- done" : "") << llendl;
stop();
// At this point we have given up and the viewer will not receive HTTP messages from the simulator.
@@ -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 9d292ce7bb..e311e09c8b 100755
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -40,6 +40,7 @@
#include "llsecondlifeurls.h"
#include "llappviewer.h"
+#include "llbufferstream.h"
#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llviewercontrol.h"
@@ -561,6 +562,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) :
@@ -569,11 +571,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
@@ -592,7 +593,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 b26d520557..c51645afb8 100755
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -1070,9 +1070,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;
@@ -1080,13 +1080,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)");
}
@@ -1124,7 +1124,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:
@@ -1149,6 +1149,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 fea8e34729..29300ba90c 100755
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -79,14 +79,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();
};
///----------------------------------------------------------------------------
@@ -477,32 +472,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 c0afb72cff..c6003dcc17 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 5cb9df5625..bfad4a73f2 100755
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -1145,16 +1145,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/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp
index 4bfef8b45f..9986bdbd7f 100755
--- a/indra/newview/llfloateropenobject.cpp
+++ b/indra/newview/llfloateropenobject.cpp
@@ -162,21 +162,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear)
{
parent_category_id = gInventory.getRootFolderID();
}
-
- LLCategoryCreate* cat_data = new LLCategoryCreate(object_id, wear);
-
+
+ inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear);
LLUUID category_id = gInventory.createNewCategory(parent_category_id,
LLFolderType::FT_NONE,
name,
- callbackCreateInventoryCategory,
- (void*)cat_data);
+ func);
//If we get a null category ID, we are using a capability in createNewCategory and we will
//handle the following in the callbackCreateInventoryCategory routine.
if ( category_id.notNull() )
{
- delete cat_data;
-
LLCatAndWear* data = new LLCatAndWear;
data->mCatID = category_id;
data->mWear = wear;
@@ -198,20 +194,17 @@ void LLFloaterOpenObject::moveToInventory(bool wear)
}
// static
-void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, void* data)
+void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear)
{
- LLCategoryCreate* cat_data = (LLCategoryCreate*)data;
-
- LLUUID category_id = result["folder_id"].asUUID();
LLCatAndWear* wear_data = new LLCatAndWear;
wear_data->mCatID = category_id;
- wear_data->mWear = cat_data->mWear;
+ wear_data->mWear = wear;
wear_data->mFolderResponded = true;
// Copy and/or move the items into the newly created folder.
// Ignore any "you're going to break this item" messages.
- BOOL success = move_inv_category_world_to_agent(cat_data->mObjectID, category_id, TRUE,
+ BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE,
callbackMoveInventory,
(void*)wear_data);
if (!success)
@@ -221,7 +214,6 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, vo
LLNotificationsUtil::add("OpenObjectCannotCopy");
}
- delete cat_data;
}
// static
diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h
index bf7fe69c65..8e472804a4 100755
--- a/indra/newview/llfloateropenobject.h
+++ b/indra/newview/llfloateropenobject.h
@@ -45,15 +45,6 @@ public:
void dirty();
- class LLCategoryCreate
- {
- public:
- LLCategoryCreate(LLUUID object_id, bool wear) : mObjectID(object_id), mWear(wear) {}
- public:
- LLUUID mObjectID;
- bool mWear;
- };
-
struct LLCatAndWear
{
LLUUID mCatID;
@@ -72,7 +63,7 @@ protected:
void onClickMoveToInventory();
void onClickMoveAndWear();
- static void callbackCreateInventoryCategory(const LLSD& result, void* data);
+ static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear);
static void callbackMoveInventory(S32 result, void* data);
private:
diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp
index 3a7ca17b73..efc04ac358 100755
--- a/indra/newview/llfloaterregiondebugconsole.cpp
+++ b/indra/newview/llfloaterregiondebugconsole.cpp
@@ -73,24 +73,29 @@ namespace
// called if this request times out.
class AsyncConsoleResponder : public LLHTTPClient::Responder
{
- public:
+ LOG_CLASS(AsyncConsoleResponder);
+ protected:
/* virtual */
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+ void httpFailure()
{
+ LL_WARNS("Console") << dumpResponse() << LL_ENDL;
sConsoleReplySignal(UNABLE_TO_SEND_COMMAND);
}
};
class ConsoleResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(ConsoleResponder);
public:
ConsoleResponder(LLTextEditor *output) : mOutput(output)
{
}
+ protected:
/*virtual*/
- void error(U32 status, const std::string& reason)
+ void httpFailure()
{
+ LL_WARNS("Console") << dumpResponse() << LL_ENDL;
if (mOutput)
{
mOutput->appendText(
@@ -100,8 +105,10 @@ namespace
}
/*virtual*/
- void result(const LLSD& content)
+ void httpSuccess()
{
+ const LLSD& content = getContent();
+ LL_DEBUGS("Console") << content << LL_ENDL;
if (mOutput)
{
mOutput->appendText(
@@ -109,6 +116,7 @@ namespace
}
}
+ public:
LLTextEditor * mOutput;
};
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 50c013a49d..ddfae005bb 100755
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -756,12 +756,12 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L
class ConsoleRequestResponder : public LLHTTPClient::Responder
{
-public:
+ LOG_CLASS(ConsoleRequestResponder);
+protected:
/*virtual*/
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+ void httpFailure()
{
- llwarns << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:"
- << status << "]: " << content << llendl;
+ llwarns << "error requesting mesh_rez_enabled " << dumpResponse() << llendl;
}
};
@@ -769,12 +769,12 @@ public:
// called if this request times out.
class ConsoleUpdateResponder : public LLHTTPClient::Responder
{
-public:
+ LOG_CLASS(ConsoleUpdateResponder);
+protected:
/* virtual */
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+ void httpFailure()
{
- llwarns << "ConsoleRequestResponder error updating mesh enabled region setting [status:"
- << status << "]: " << content << llendl;
+ llwarns << "error updating mesh enabled region setting " << dumpResponse() << llendl;
}
};
@@ -2233,14 +2233,16 @@ void LLPanelEstateInfo::getEstateOwner()
class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLEstateChangeInfoResponder);
public:
LLEstateChangeInfoResponder(LLPanelEstateInfo* panel)
{
mpPanel = panel->getHandle();
}
+protected:
// if we get a normal response, handle it here
- virtual void result(const LLSD& content)
+ virtual void httpSuccess()
{
LL_INFOS("Windlight") << "Successfully committed estate info" << llendl;
@@ -2251,10 +2253,9 @@ public:
}
// if we get an error response
- virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+ virtual void httpFailure()
{
- llinfos << "LLEstateChangeInfoResponder::error [status:"
- << status << "]: " << content << llendl;
+ LL_WARNS("Windlight") << dumpResponse() << LL_ENDL;
}
private:
LLHandle<LLPanel> mpPanel;
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 35b63c5480..cc4199a758 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -707,16 +707,18 @@ public:
class LLUserReportResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLUserReportResponder);
public:
LLUserReportResponder(): LLHTTPClient::Responder() {}
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
- {
- // *TODO do some user messaging here
- LLUploadDialog::modalUploadFinished();
- }
- void result(const LLSD& content)
+private:
+ void httpCompleted()
{
+ if (!isGoodStatus())
+ {
+ // *TODO do some user messaging here
+ LL_WARNS("UserReport") << dumpResponse() << LL_ENDL;
+ }
// we don't care about what the server returns
LLUploadDialog::modalUploadFinished();
}
diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp
index 13cb3c2eb0..11a0d3ebe4 100755
--- a/indra/newview/llfloaterscriptlimits.cpp
+++ b/indra/newview/llfloaterscriptlimits.cpp
@@ -183,8 +183,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)
// Responders
///----------------------------------------------------------------------------
-void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)
+void fetchScriptLimitsRegionInfoResponder::httpSuccess()
{
+ const LLSD& content = getContent();
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
//we don't need to test with a fake respose here (shouldn't anyway)
#ifdef DUMP_REPLIES_TO_LLINFOS
@@ -221,13 +227,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content)
}
}
-void fetchScriptLimitsRegionInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsRegionInfoResponder::httpFailure()
{
- llwarns << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << llendl;
+ llwarns << dumpResponse() << llendl;
}
-void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
+void fetchScriptLimitsRegionSummaryResponder::httpSuccess()
{
+ const LLSD& content_ref = getContent();
#ifdef USE_FAKE_RESPONSES
LLSD fake_content;
@@ -268,6 +275,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
#endif
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
+
#ifdef DUMP_REPLIES_TO_LLINFOS
@@ -291,7 +304,7 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
if(tab)
{
- LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
+ LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
if(panel_memory)
{
panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
@@ -301,20 +314,21 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref)
{
btn->setEnabled(true);
}
-
- panel_memory->setRegionSummary(content);
- }
-}
+
+ panel_memory->setRegionSummary(content);
+ }
+ }
}
}
-void fetchScriptLimitsRegionSummaryResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsRegionSummaryResponder::httpFailure()
{
- llwarns << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << llendl;
+ llwarns << dumpResponse() << llendl;
}
-void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref)
+void fetchScriptLimitsRegionDetailsResponder::httpSuccess()
{
+ const LLSD& content_ref = getContent();
#ifdef USE_FAKE_RESPONSES
/*
Updated detail service, ** denotes field added:
@@ -377,6 +391,12 @@ result (map)
#endif
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
+
#ifdef DUMP_REPLIES_TO_LLINFOS
LLSDNotationStreamer notation_streamer(content);
@@ -417,13 +437,14 @@ result (map)
}
}
-void fetchScriptLimitsRegionDetailsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsRegionDetailsResponder::httpFailure()
{
- llwarns << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << llendl;
+ llwarns << dumpResponse() << llendl;
}
-void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
+void fetchScriptLimitsAttachmentInfoResponder::httpSuccess()
{
+ const LLSD& content_ref = getContent();
#ifdef USE_FAKE_RESPONSES
@@ -465,6 +486,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
#endif
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
+
#ifdef DUMP_REPLIES_TO_LLINFOS
LLSDNotationStreamer notation_streamer(content);
@@ -513,9 +540,9 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref)
}
}
-void fetchScriptLimitsAttachmentInfoResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content)
+void fetchScriptLimitsAttachmentInfoResponder::httpFailure()
{
- llwarns << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << llendl;
+ llwarns << dumpResponse() << llendl;
}
///----------------------------------------------------------------------------
@@ -586,7 +613,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id)
}
// virtual
-void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason)
+void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason)
{
llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
}
diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h
index f8732ef94b..a5cb1b6184 100755
--- a/indra/newview/llfloaterscriptlimits.h
+++ b/indra/newview/llfloaterscriptlimits.h
@@ -85,49 +85,49 @@ protected:
class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder
{
- public:
- fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {};
-
- void result(const LLSD& content);
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
- public:
- protected:
- LLSD mInfo;
+ LOG_CLASS(fetchScriptLimitsRegionInfoResponder);
+public:
+ fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {};
+
+private:
+ /* virtual */ void httpSuccess();
+ /* virtual */ void httpFailure();
+ LLSD mInfo;
};
class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder
{
- public:
- fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {};
-
- void result(const LLSD& content);
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
- public:
- protected:
- LLSD mInfo;
+ LOG_CLASS(fetchScriptLimitsRegionSummaryResponder);
+public:
+ fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {};
+
+private:
+ /* virtual */ void httpSuccess();
+ /* virtual */ void httpFailure();
+ LLSD mInfo;
};
class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder
{
- public:
- fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {};
-
- void result(const LLSD& content);
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
- public:
- protected:
- LLSD mInfo;
+ LOG_CLASS(fetchScriptLimitsRegionDetailsResponder);
+public:
+ fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {};
+
+private:
+ /* virtual */ void httpSuccess();
+ /* virtual */ void httpFailure();
+ LLSD mInfo;
};
class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder
{
- public:
- fetchScriptLimitsAttachmentInfoResponder() {};
+ LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder);
+public:
+ fetchScriptLimitsAttachmentInfoResponder() {};
- void result(const LLSD& content);
- void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
- public:
- protected:
+private:
+ /* virtual */ void httpSuccess();
+ /* virtual */ void httpFailure();
};
/////////////////////////////////////////////////////////////////////////////
@@ -190,7 +190,7 @@ protected:
// LLRemoteParcelInfoObserver interface:
/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
/*virtual*/ void setParcelID(const LLUUID& parcel_id);
-/*virtual*/ void setErrorStatus(U32 status, const std::string& reason);
+/*virtual*/ void setErrorStatus(S32 status, const std::string& reason);
static void onClickRefresh(void* userdata);
static void onClickHighlight(void* userdata);
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 2a946b1edf..a446b767ac 100755
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -30,6 +30,7 @@
#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "llfloatersearch.h"
+#include "llhttpconstants.h"
#include "llmediactrl.h"
#include "llnotificationsutil.h"
#include "lllogininstance.h"
@@ -200,5 +201,5 @@ void LLFloaterSearch::search(const SearchQuery &p)
url = LLWeb::expandURLSubstitutions(url, subs);
// and load the URL in the web view
- mWebBrowser->navigateTo(url, "text/html");
+ mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
}
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index a242b224cd..0613ffc94d 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -36,7 +36,7 @@
#include "llbutton.h"
#include "llevents.h"
#include "llhttpclient.h"
-#include "llhttpstatuscodes.h" // for HTTP_FOUND
+#include "llhttpconstants.h"
#include "llnotificationsutil.h"
#include "llradiogroup.h"
#include "lltextbox.h"
@@ -62,42 +62,46 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)
// on parent class indicating if the web server is working or not
class LLIamHere : public LLHTTPClient::Responder
{
- private:
- LLIamHere( LLFloaterTOS* parent ) :
- mParent( parent )
- {}
+ LOG_CLASS(LLIamHere);
+private:
+ LLIamHere( LLFloaterTOS* parent ) :
+ mParent( parent )
+ {}
- LLFloaterTOS* mParent;
+ LLFloaterTOS* mParent;
- public:
-
- static LLIamHere* build( LLFloaterTOS* parent )
- {
- return new LLIamHere( parent );
- };
-
- virtual void setParent( LLFloaterTOS* parentIn )
- {
- mParent = parentIn;
- };
-
- virtual void result( const LLSD& content )
+public:
+ static LLIamHere* build( LLFloaterTOS* parent )
+ {
+ return new LLIamHere( parent );
+ }
+
+ virtual void setParent( LLFloaterTOS* parentIn )
+ {
+ mParent = parentIn;
+ }
+
+protected:
+ virtual void httpSuccess()
+ {
+ if ( mParent )
{
- if ( mParent )
- mParent->setSiteIsAlive( true );
- };
+ mParent->setSiteIsAlive( true );
+ }
+ }
- virtual void error( U32 status, const std::string& reason )
+ virtual void httpFailure()
+ {
+ LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL;
+ if ( mParent )
{
- if ( mParent )
- {
- // *HACK: For purposes of this alive check, 302 Found
- // (aka Moved Temporarily) is considered alive. The web site
- // redirects this link to a "cache busting" temporary URL. JC
- bool alive = (status == HTTP_FOUND);
- mParent->setSiteIsAlive( alive );
- }
- };
+ // *HACK: For purposes of this alive check, 302 Found
+ // (aka Moved Temporarily) is considered alive. The web site
+ // redirects this link to a "cache busting" temporary URL. JC
+ bool alive = (getStatus() == HTTP_FOUND);
+ mParent->setSiteIsAlive( alive );
+ }
+ }
};
// this is global and not a class member to keep crud out of the header file
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index e85d849c9a..e26f1e9ea5 100755
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -48,31 +48,30 @@ static LLFloaterURLEntry* sInstance = NULL;
// on the Panel Land Media and to discover the MIME type
class LLMediaTypeResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLMediaTypeResponder);
public:
LLMediaTypeResponder( const LLHandle<LLFloater> parent ) :
- mParent( parent )
- {}
-
- LLHandle<LLFloater> mParent;
-
-
- virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- std::string media_type = content["content-type"].asString();
- std::string::size_type idx1 = media_type.find_first_of(";");
- std::string mime_type = media_type.substr(0, idx1);
- completeAny(status, mime_type);
- }
-
- void completeAny(U32 status, const std::string& mime_type)
- {
- // Set empty type to none/none. Empty string is reserved for legacy parcels
- // which have no mime type set.
- std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType();
- LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get();
- if ( floater_url_entry )
- floater_url_entry->headerFetchComplete( status, resolved_mime_type );
- }
+ mParent( parent )
+ {}
+
+ LLHandle<LLFloater> mParent;
+
+private:
+ /* virtual */ void httpCompleted()
+ {
+ const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE);
+ std::string::size_type idx1 = media_type.find_first_of(";");
+ std::string mime_type = media_type.substr(0, idx1);
+
+ // Set empty type to none/none. Empty string is reserved for legacy parcels
+ // which have no mime type set.
+ std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType();
+ LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get();
+ if ( floater_url_entry )
+ {
+ floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type );
+ }
+ }
};
//-----------------------------------------------------------------------------
@@ -136,7 +135,7 @@ void LLFloaterURLEntry::buildURLHistory()
}
}
-void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type)
+void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_type)
{
LLPanelLandMedia* panel_media = dynamic_cast<LLPanelLandMedia*>(mPanelLandMediaHandle.get());
if (panel_media)
diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h
index dfb49fe5ac..bdd1ebe592 100755
--- a/indra/newview/llfloaterurlentry.h
+++ b/indra/newview/llfloaterurlentry.h
@@ -40,7 +40,7 @@ public:
// that panel via the handle.
static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url);
/*virtual*/ BOOL postBuild();
- void headerFetchComplete(U32 status, const std::string& mime_type);
+ void headerFetchComplete(S32 status, const std::string& mime_type);
bool addURLToCombobox(const std::string& media_url);
diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp
index 3fe2518de6..21b171446f 100755
--- a/indra/newview/llfloaterwebcontent.cpp
+++ b/indra/newview/llfloaterwebcontent.cpp
@@ -29,6 +29,7 @@
#include "llcombobox.h"
#include "lliconctrl.h"
#include "llfloaterreg.h"
+#include "llhttpconstants.h"
#include "lllayoutstack.h"
#include "llpluginclassmedia.h"
#include "llprogressbar.h"
@@ -234,9 +235,9 @@ void LLFloaterWebContent::open_media(const Params& p)
{
// Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin.
LLViewerMedia::proxyWindowOpened(p.target(), p.id());
- mWebBrowser->setHomePageUrl(p.url, "text/html");
+ mWebBrowser->setHomePageUrl(p.url, HTTP_CONTENT_TEXT_HTML);
mWebBrowser->setTarget(p.target);
- mWebBrowser->navigateTo(p.url, "text/html");
+ mWebBrowser->navigateTo(p.url, HTTP_CONTENT_TEXT_HTML);
set_current_url(p.url);
@@ -451,7 +452,7 @@ void LLFloaterWebContent::onEnterAddress()
std::string url = mAddressCombo->getValue().asString();
if ( url.length() > 0 )
{
- mWebBrowser->navigateTo( url, "text/html");
+ mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
};
}
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index 16ed3f990c..a6be604222 100755
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -86,7 +86,7 @@ const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollect
if (cats_count > 1)
{
- LL_WARNS("LLFriendCardsManager")
+ LL_WARNS_ONCE("LLFriendCardsManager")
<< "There is more than one Friend card folder."
<< "The first folder will be used."
<< LL_ENDL;
diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp
index b56c34573d..08e209c847 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..ae429f11f8
--- /dev/null
+++ b/indra/newview/llhttpretrypolicy.cpp
@@ -0,0 +1,142 @@
+/**
+ * @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;
+}
+
+void LLAdaptiveRetryPolicy::reset()
+{
+ init();
+}
+
+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..cf79e0b401
--- /dev/null
+++ b/indra/newview/llhttpretrypolicy.h
@@ -0,0 +1,98 @@
+/**
+ * @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;
+
+ virtual void reset() = 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();
+
+ void reset();
+
+ // 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 9e23755d73..c667492427 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -254,7 +254,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)
// 0. nothing - exit
if (("noaction" == user_preferences ||
ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)
- && session_floater->isMessagePaneExpanded())
+ && session_floater->isMessagePaneExpanded())
{
return;
}
@@ -971,7 +971,7 @@ void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& m
LLIMSession* session = findIMSession(session_id);
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return;
}
@@ -993,7 +993,7 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)
LLIMSession* session = findIMSession(session_id);
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return;
}
@@ -1013,7 +1013,7 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return false;
}
@@ -1088,7 +1088,7 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return NULL;
}
@@ -1125,7 +1125,7 @@ const std::string LLIMModel::getName(const LLUUID& session_id) const
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return LLTrans::getString("no_session_message");
}
@@ -1137,7 +1137,7 @@ const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const
LLIMSession* session = findIMSession(session_id);
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return -1;
}
@@ -1161,7 +1161,7 @@ EInstantMessage LLIMModel::getType(const LLUUID& session_id) const
LLIMSession* session = findIMSession(session_id);
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return IM_COUNT;
}
@@ -1173,7 +1173,7 @@ LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const
LLIMSession* session = findIMSession(session_id);
if (!session)
{
- llwarns << "session " << session_id << "does not exist " << llendl;
+ llwarns << "session " << session_id << " does not exist " << llendl;
return NULL;
}
@@ -1459,6 +1459,7 @@ void start_deprecated_conference_chat(
class LLStartConferenceChatResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLStartConferenceChatResponder);
public:
LLStartConferenceChatResponder(
const LLUUID& temp_session_id,
@@ -1472,10 +1473,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,
@@ -1484,8 +1487,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
@@ -1577,6 +1579,7 @@ bool LLIMModel::sendStartSession(
class LLViewerChatterBoxInvitationAcceptResponder :
public LLHTTPClient::Responder
{
+ LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder);
public:
LLViewerChatterBoxInvitationAcceptResponder(
const LLUUID& session_id,
@@ -1586,8 +1589,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);
@@ -1632,19 +1642,17 @@ public:
}
}
- void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
- {
- llwarns << "LLViewerChatterBoxInvitationAcceptResponder error [status:"
- << statusNum << "]: " << content << llendl;
+ void httpFailure()
+ {
+ 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 e4fc469bb7..c9fe2127fe 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -200,6 +200,7 @@ const std::string& LLInvFVBridge::getDisplayName() const
{
buildDisplayName();
}
+
return mDisplayName;
}
@@ -1159,17 +1160,10 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid)
{
- LLInventoryCategory* cat = model->getCategory(uuid);
- if (cat)
- {
- model->purgeDescendentsOf(uuid);
- model->notifyObservers();
- }
LLInventoryObject* obj = model->getObject(uuid);
if (obj)
{
- model->purgeObject(uuid);
- model->notifyObservers();
+ remove_inventory_object(uuid, NULL);
}
}
@@ -1573,18 +1567,18 @@ void LLItemBridge::buildDisplayName() const
else
{
mDisplayName.assign(LLStringUtil::null);
-}
-
+ }
+
mSearchableName.assign(mDisplayName);
mSearchableName.append(getLabelSuffix());
LLStringUtil::toUpper(mSearchableName);
-
+
//Name set, so trigger a sort
if(mParent)
-{
- mParent->requestSort();
- }
+ {
+ mParent->requestSort();
}
+}
LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
{
@@ -1698,13 +1692,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)
LLViewerInventoryItem* item = getItem();
if(item && (item->getName() != new_name))
{
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->rename(new_name);
- new_item->updateServer(FALSE);
- model->updateItem(new_item);
-
- model->notifyObservers();
- buildDisplayName();
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_item(item->getUUID(),updates, NULL);
}
// return FALSE because we either notified observers (& therefore
// rebuilt) or we didn't update.
@@ -1901,49 +1891,19 @@ void LLFolderBridge::buildDisplayName() const
void LLFolderBridge::update()
{
- bool possibly_has_children = false;
- bool up_to_date = isUpToDate();
- if(!up_to_date && hasChildren()) // we know we have children but haven't fetched them (doesn't obey filter)
- {
- possibly_has_children = true;
- }
-
- bool loading = (possibly_has_children
- && !up_to_date );
+ // we know we have children but haven't fetched them (doesn't obey filter)
+ bool loading = !isUpToDate() && hasChildren() && mFolderViewItem->isOpen();
if (loading != mIsLoading)
{
- if ( loading && !mIsLoading )
+ if ( loading )
{
// Measure how long we've been in the loading state
mTimeSinceRequestStart.reset();
}
+ mIsLoading = loading;
- const BOOL in_inventory = gInventory.isObjectDescendentOf(getUUID(), gInventory.getRootFolderID());
- const BOOL in_library = gInventory.isObjectDescendentOf(getUUID(), gInventory.getLibraryRootFolderID());
-
- bool root_is_loading = false;
- if (in_inventory)
- {
- root_is_loading = LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress();
- }
- if (in_library)
- {
- root_is_loading = LLInventoryModelBackgroundFetch::instance().libraryFetchInProgress();
- }
- if ((mIsLoading
- && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime"))
- || (LLInventoryModelBackgroundFetch::instance().folderFetchActive()
- && root_is_loading))
- {
- mDisplayName = LLInvFVBridge::getDisplayName() + " ( " + LLTrans::getString("LoadingData") + " ) ";
- mIsLoading = true;
- }
- else
- {
- mDisplayName = LLInvFVBridge::getDisplayName();
- mIsLoading = false;
- }
+ mFolderViewItem->refresh();
}
}
@@ -2456,49 +2416,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
}
- // if target is an outfit or current outfit folder we use link
- if (move_is_into_current_outfit || move_is_into_outfit)
+ // if target is current outfit folder we use link
+ if (move_is_into_current_outfit &&
+ inv_cat->getPreferredType() == LLFolderType::FT_NONE)
{
- if (inv_cat->getPreferredType() == LLFolderType::FT_NONE)
- {
- if (move_is_into_current_outfit)
- {
- // traverse category and add all contents to currently worn.
- BOOL append = true;
- LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
- }
- else
- {
- // Recursively create links in target outfit.
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
- LLAppearanceMgr::instance().linkAll(mUUID,items,NULL);
- }
- }
- else
- {
-#if SUPPORT_ENSEMBLES
- // BAP - should skip if dup.
- if (move_is_into_current_outfit)
- {
- LLAppearanceMgr::instance().addEnsembleLink(inv_cat);
- }
- else
- {
- LLPointer<LLInventoryCallback> cb = NULL;
- const std::string empty_description = "";
- link_inventory_item(
- gAgent.getID(),
- cat_id,
- mUUID,
- inv_cat->getName(),
- empty_description,
- LLAssetType::AT_LINK_FOLDER,
- cb);
- }
-#endif
- }
+ // traverse category and add all contents to currently worn.
+ BOOL append = true;
+ LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
}
else if (move_is_into_outbox && !move_is_from_outbox)
{
@@ -2890,17 +2814,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
modifyOutfit(FALSE);
return;
}
-#if SUPPORT_ENSEMBLES
- else if ("wearasensemble" == action)
- {
- LLInventoryModel* model = getInventoryModel();
- if(!model) return;
- LLViewerInventoryCategory* cat = getCategory();
- if(!cat) return;
- LLAppearanceMgr::instance().addEnsembleLink(cat,true);
- return;
- }
-#endif
else if ("addtooutfit" == action)
{
modifyOutfit(TRUE);
@@ -3063,6 +2976,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)
{
@@ -3303,28 +3223,9 @@ void LLFolderBridge::pasteLinkFromClipboard()
dropToOutfit(item, move_is_into_current_outfit);
}
}
- else if (LLInventoryCategory *cat = model->getCategory(object_id))
- {
- const std::string empty_description = "";
- link_inventory_item(
- gAgent.getID(),
- cat->getUUID(),
- parent_id,
- cat->getName(),
- empty_description,
- LLAssetType::AT_LINK_FOLDER,
- LLPointer<LLInventoryCallback>(NULL));
- }
- else if (LLInventoryItem *item = model->getItem(object_id))
+ else if (LLConstPointer<LLInventoryObject> obj = model->getObject(object_id))
{
- link_inventory_item(
- gAgent.getID(),
- item->getLinkedUUID(),
- parent_id,
- item->getName(),
- item->getDescription(),
- LLAssetType::AT_LINK,
- LLPointer<LLInventoryCallback>(NULL));
+ link_inventory_object(parent_id, obj, LLPointer<LLInventoryCallback>(NULL));
}
}
// Change mode to paste for next paste
@@ -3415,16 +3316,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.push_back(std::string("New Clothes"));
items.push_back(std::string("New Body Parts"));
}
-#if SUPPORT_ENSEMBLES
- // Changing folder types is an unfinished unsupported feature
- // and can lead to unexpected behavior if enabled.
- items.push_back(std::string("Change Type"));
- const LLViewerInventoryCategory *cat = getCategory();
- if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
- {
- disabled_items.push_back(std::string("Change Type"));
- }
-#endif
getClipboardEntries(false, items, disabled_items, flags);
}
else
@@ -3586,6 +3477,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"));
}
}
@@ -3916,14 +3811,7 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c
else
{
LLPointer<LLInventoryCallback> cb = NULL;
- link_inventory_item(
- gAgent.getID(),
- inv_item->getLinkedUUID(),
- mUUID,
- inv_item->getName(),
- inv_item->getDescription(),
- LLAssetType::AT_LINK,
- cb);
+ link_inventory_object(mUUID, LLConstPointer<LLInventoryObject>(inv_item), cb);
}
}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 517153e171..2a937b574d 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -248,7 +248,7 @@ public:
LLFolderBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid)
- : LLInvFVBridge(inventory, root, uuid),
+ : LLInvFVBridge(inventory, root, uuid),
mCallingCards(FALSE),
mWearables(FALSE),
mIsLoading(false)
@@ -272,6 +272,8 @@ public:
virtual LLUIImagePtr getIconOverlay() const;
static LLUIImagePtr getIcon(LLFolderType::EType preferred_type);
+
+ virtual std::string getLabelSuffix() const;
virtual BOOL renameItem(const std::string& new_name);
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index f1a4889f5a..faa5d70952 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -123,12 +123,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
return;
}
- LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
- new_cat->rename(new_name);
- new_cat->updateServer(FALSE);
- model->updateCategory(new_cat);
-
- model->notifyObservers();
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_category(cat_id, updates, NULL);
}
void copy_inventory_category(LLInventoryModel* model,
@@ -741,6 +738,13 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item
return FALSE;
}
+bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+{
+ LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
+ if (!vitem) return false;
+ return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink());
+}
+
bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if(mType == LLAssetType::AT_CATEGORY)
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index f1066a4dc9..6b3861aa79 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -186,6 +186,13 @@ protected:
LLAssetType::EType mType;
};
+class LLIsValidItemLink : public LLInventoryCollectFunctor
+{
+public:
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+};
+
class LLIsTypeWithPermissions : public LLInventoryCollectFunctor
{
public:
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 935fe2b4d0..be1a396fff 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llinventorymodel.h"
+#include "llaisapi.h"
#include "llagent.h"
#include "llagentwearables.h"
#include "llappearancemgr.h"
@@ -48,6 +49,7 @@
#include "llcallbacklist.h"
#include "llvoavatarself.h"
#include "llgesturemgr.h"
+#include "llsdutil.h"
#include <typeinfo>
//#define DIFF_INVENTORY_FILES
@@ -252,6 +254,23 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL
return NULL;
}
+bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const
+{
+ LLInventoryObject *object = getObject(object_id);
+ while (object && object->getParentUUID().notNull())
+ {
+ LLInventoryObject *parent_object = getObject(object->getParentUUID());
+ if (!parent_object)
+ {
+ llwarns << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << llendl;
+ return false;
+ }
+ object = parent_object;
+ }
+ result = object->getUUID();
+ return true;
+}
+
// Get the object by id. Returns NULL if not found.
LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const
{
@@ -369,16 +388,13 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id)
mItemLock[cat_id] = false;
}
-// findCategoryUUIDForType() returns the uuid of the category that
-// specifies 'type' as what it defaults to containing. The category is
-// not necessarily only for that type. *NOTE: This will create a new
-// inventory category on the fly if one does not exist.
-const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder/*,
- bool find_in_library*/)
+const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
+ LLFolderType::EType preferred_type,
+ bool create_folder,
+ const LLUUID& root_id)
{
LLUUID rv = LLUUID::null;
- const LLUUID &root_id = /*(find_in_library) ? gInventory.getLibraryRootFolderID() :*/ gInventory.getRootFolderID();
if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
{
rv = root_id;
@@ -394,14 +410,17 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe
{
if(cats->get(i)->getPreferredType() == preferred_type)
{
- rv = cats->get(i)->getUUID();
- break;
+ const LLUUID& folder_id = cats->get(i)->getUUID();
+ if (rv.isNull() || folder_id < rv)
+ {
+ rv = folder_id;
+ }
}
}
}
}
- if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/))
+ if(rv.isNull() && isInventoryUsable() && create_folder)
{
if(root_id.notNull())
{
@@ -411,68 +430,49 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe
return rv;
}
-const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
+// findCategoryUUIDForType() returns the uuid of the category that
+// specifies 'type' as what it defaults to containing. The category is
+// not necessarily only for that type. *NOTE: This will create a new
+// inventory category on the fly if one does not exist.
+const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
{
- LLUUID rv = LLUUID::null;
-
- const LLUUID &root_id = gInventory.getLibraryRootFolderID();
- if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
- {
- rv = root_id;
- }
- else if (root_id.notNull())
- {
- cat_array_t* cats = NULL;
- cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
- if(cats)
- {
- S32 count = cats->count();
- for(S32 i = 0; i < count; ++i)
- {
- if(cats->get(i)->getPreferredType() == preferred_type)
- {
- rv = cats->get(i)->getUUID();
- break;
- }
- }
- }
- }
+ return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID());
+}
- if(rv.isNull() && isInventoryUsable() && (create_folder && true/*!find_in_library*/))
- {
- if(root_id.notNull())
- {
- return createNewCategory(root_id, preferred_type, LLStringUtil::null);
- }
- }
- return rv;
+const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder)
+{
+ return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());
}
class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLCreateInventoryCategoryResponder);
public:
LLCreateInventoryCategoryResponder(LLInventoryModel* model,
- void (*callback)(const LLSD&, void*),
- void* user_data) :
- mModel(model),
- mCallback(callback),
- mData(user_data)
+ boost::optional<inventory_func_type> callback):
+ mModel(model),
+ mCallback(callback)
{
}
- 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();
-
+ LL_DEBUGS("Avatar") << ll_pretty_print_sd(content) << llendl;
// Add the category to the internal representation
LLPointer<LLViewerInventoryCategory> cat =
new LLViewerInventoryCategory( category_id,
@@ -485,17 +485,15 @@ public:
LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
mModel->accountForUpdate(update);
mModel->updateCategory(cat);
-
- if (mCallback && mData)
+
+ if (mCallback)
{
- mCallback(content, mData);
+ mCallback.get()(category_id);
}
-
}
private:
- void (*mCallback)(const LLSD&, void*);
- void* mData;
+ boost::optional<inventory_func_type> mCallback;
LLInventoryModel* mModel;
};
@@ -506,8 +504,7 @@ private:
LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& pname,
- void (*callback)(const LLSD&, void*), //Default to NULL
- void* user_data) //Default to NULL
+ boost::optional<inventory_func_type> callback)
{
LLUUID id;
@@ -534,33 +531,32 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
}
- if ( callback && user_data ) //callback required for acked message.
+ LLViewerRegion* viewer_region = gAgent.getRegion();
+ std::string url;
+ if ( viewer_region )
+ url = viewer_region->getCapability("CreateInventoryCategory");
+
+ if (!url.empty() && callback.get_ptr())
{
- LLViewerRegion* viewer_region = gAgent.getRegion();
- std::string url;
- if ( viewer_region )
- url = viewer_region->getCapability("CreateInventoryCategory");
+ //Let's use the new capability.
- if (!url.empty())
- {
- //Let's use the new capability.
-
- LLSD request, body;
- body["folder_id"] = id;
- body["parent_id"] = parent_id;
- body["type"] = (LLSD::Integer) preferred_type;
- body["name"] = name;
-
- request["message"] = "CreateInventoryCategory";
- request["payload"] = body;
-
- // viewer_region->getCapAPI().post(request);
- LLHTTPClient::post(
- url,
- body,
- new LLCreateInventoryCategoryResponder(this, callback, user_data) );
- return LLUUID::null;
- }
+ LLSD request, body;
+ body["folder_id"] = id;
+ body["parent_id"] = parent_id;
+ body["type"] = (LLSD::Integer) preferred_type;
+ body["name"] = name;
+
+ request["message"] = "CreateInventoryCategory";
+ request["payload"] = body;
+
+ LL_DEBUGS("Avatar") << "create category request: " << ll_pretty_print_sd(request) << llendl;
+ // viewer_region->getCapAPI().post(request);
+ LLHTTPClient::post(
+ url,
+ body,
+ new LLCreateInventoryCategoryResponder(this, callback) );
+
+ return LLUUID::null;
}
// Add the category to the internal representation
@@ -587,6 +583,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 +648,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 +675,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 +747,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 +1126,197 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
notifyObservers();
}
+void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
+{
+ LLTimer timer;
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+ }
+
+ AISUpdate ais_update(update); // parse update llsd into stuff to do.
+ ais_update.doUpdate(); // execute the updates in the appropriate order.
+ llinfos << "elapsed: " << timer.getElapsedTimeF32() << llendl;
+}
+
+void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version)
+{
+ U32 mask = LLInventoryObserver::NONE;
+
+ LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id);
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << llendl;
+ if(item)
+ {
+ for (LLSD::map_const_iterator it = updates.beginMap();
+ it != updates.endMap(); ++it)
+ {
+ if (it->first == "name")
+ {
+ llinfos << "Updating name from " << item->getName() << " to " << it->second.asString() << llendl;
+ item->rename(it->second.asString());
+ mask |= LLInventoryObserver::LABEL;
+ }
+ else if (it->first == "desc")
+ {
+ llinfos << "Updating description from " << item->getActualDescription()
+ << " to " << it->second.asString() << llendl;
+ item->setDescription(it->second.asString());
+ }
+ else
+ {
+ llerrs << "unhandled updates for field: " << it->first << llendl;
+ }
+ }
+ mask |= LLInventoryObserver::INTERNAL;
+ addChangedMask(mask, item->getUUID());
+ if (update_parent_version)
+ {
+ // Descendent count is unchanged, but folder version incremented.
+ LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0);
+ accountForUpdate(up);
+ }
+ gInventory.notifyObservers(); // do we want to be able to make this optional?
+ }
+}
+
+void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates)
+{
+ U32 mask = LLInventoryObserver::NONE;
+
+ LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id);
+ LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << llendl;
+ if(cat)
+ {
+ for (LLSD::map_const_iterator it = updates.beginMap();
+ it != updates.endMap(); ++it)
+ {
+ if (it->first == "name")
+ {
+ llinfos << "Updating name from " << cat->getName() << " to " << it->second.asString() << llendl;
+ cat->rename(it->second.asString());
+ mask |= LLInventoryObserver::LABEL;
+ }
+ else
+ {
+ llerrs << "unhandled updates for field: " << it->first << llendl;
+ }
+ }
+ mask |= LLInventoryObserver::INTERNAL;
+ addChangedMask(mask, cat->getUUID());
+ gInventory.notifyObservers(); // do we want to be able to make this optional?
+ }
+}
+
+// Update model after descendents have been purged.
+void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links)
+{
+ LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id);
+ if (cat.notNull())
+ {
+ // do the cache accounting
+ S32 descendents = cat->getDescendentCount();
+ if(descendents > 0)
+ {
+ LLInventoryModel::LLCategoryUpdate up(object_id, -descendents);
+ accountForUpdate(up);
+ }
+
+ // we know that descendent count is 0, however since the
+ // accounting may actually not do an update, we should force
+ // it here.
+ cat->setDescendentCount(0);
+
+ // unceremoniously remove anything we have locally stored.
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+ collectDescendents(object_id,
+ categories,
+ items,
+ LLInventoryModel::INCLUDE_TRASH);
+ S32 count = items.count();
+
+ LLUUID uu_id;
+ for(S32 i = 0; i < count; ++i)
+ {
+ uu_id = items.get(i)->getUUID();
+
+ // This check prevents the deletion of a previously deleted item.
+ // This is necessary because deletion is not done in a hierarchical
+ // order. The current item may have been already deleted as a child
+ // of its deleted parent.
+ if (getItem(uu_id))
+ {
+ deleteObject(uu_id, fix_broken_links);
+ }
+ }
+
+ count = categories.count();
+ // Slightly kludgy way to make sure categories are removed
+ // only after their child categories have gone away.
+
+ // FIXME: Would probably make more sense to have this whole
+ // descendent-clearing thing be a post-order recursive
+ // function to get the leaf-up behavior automatically.
+ S32 deleted_count;
+ S32 total_deleted_count = 0;
+ do
+ {
+ deleted_count = 0;
+ for(S32 i = 0; i < count; ++i)
+ {
+ uu_id = categories.get(i)->getUUID();
+ if (getCategory(uu_id))
+ {
+ cat_array_t* cat_list = getUnlockedCatArray(uu_id);
+ if (!cat_list || (cat_list->size() == 0))
+ {
+ deleteObject(uu_id, fix_broken_links);
+ deleted_count++;
+ }
+ }
+ }
+ total_deleted_count += deleted_count;
+ }
+ while (deleted_count > 0);
+ if (total_deleted_count != count)
+ {
+ llwarns << "Unexpected count of categories deleted, got "
+ << total_deleted_count << " expected " << count << llendl;
+ }
+ //gInventory.validate();
+ }
+}
+
+// Update model after an item is confirmed as removed from
+// server. Works for categories or items.
+void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers)
+{
+ LLPointer<LLInventoryObject> obj = getObject(object_id);
+ if(obj)
+ {
+ if (getCategory(object_id))
+ {
+ // For category, need to delete/update all children first.
+ onDescendentsPurgedFromServer(object_id, fix_broken_links);
+ }
+
+
+ // From item/cat removeFromServer()
+ if (update_parent_version)
+ {
+ LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1);
+ accountForUpdate(up);
+ }
+
+ // From purgeObject()
+ LLPreview::hide(object_id);
+ deleteObject(object_id, fix_broken_links, do_notify_observers);
+ }
+}
+
+
// Delete a particular inventory object by ID.
-void LLInventoryModel::deleteObject(const LLUUID& id)
+void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers)
{
lldebugs << "LLInventoryModel::deleteObject()" << llendl;
LLPointer<LLInventoryObject> obj = getObject(id);
@@ -1155,31 +1347,37 @@ void LLInventoryModel::deleteObject(const LLUUID& id)
item_list = getUnlockedItemArray(id);
if(item_list)
{
+ if (item_list->size())
+ {
+ llwarns << "Deleting cat " << id << " while it still has child items" << llendl;
+ }
delete item_list;
mParentChildItemTree.erase(id);
}
cat_list = getUnlockedCatArray(id);
if(cat_list)
{
+ if (cat_list->size())
+ {
+ llwarns << "Deleting cat " << id << " while it still has child cats" << llendl;
+ }
delete cat_list;
mParentChildCategoryTree.erase(id);
}
addChangedMask(LLInventoryObserver::REMOVE, id);
+
+ // Can't have links to links, so there's no need for this update
+ // if the item removed is a link. Can also skip if source of the
+ // update is getting broken link info separately.
+ bool is_link_type = obj->getIsLinkType();
obj = NULL; // delete obj
- updateLinkedObjectsFromPurge(id);
- gInventory.notifyObservers();
-}
-
-// Delete a particular inventory item by ID, and remove it from the server.
-void LLInventoryModel::purgeObject(const LLUUID &id)
-{
- lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl;
- LLPointer<LLInventoryObject> obj = getObject(id);
- if(obj)
+ if (fix_broken_links && !is_link_type)
{
- obj->removeFromServer();
- LLPreview::hide(id);
- deleteObject(id);
+ updateLinkedObjectsFromPurge(id);
+ }
+ if (do_notify_observers)
+ {
+ notifyObservers();
}
}
@@ -1189,129 +1387,19 @@ void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)
// REBUILD is expensive, so clear the current change list first else
// everything else on the changelist will also get rebuilt.
- gInventory.notifyObservers();
- for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
- iter != item_array.end();
- iter++)
- {
- const LLViewerInventoryItem *linked_item = (*iter);
- const LLUUID &item_id = linked_item->getUUID();
- if (item_id == baseobj_id) continue;
- addChangedMask(LLInventoryObserver::REBUILD, item_id);
- }
- gInventory.notifyObservers();
-}
-
-// This is a method which collects the descendents of the id
-// provided. If the category is not found, no action is
-// taken. This method goes through the long winded process of
-// cancelling any calling cards, removing server representation of
-// folders, items, etc in a fairly efficient manner.
-void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
-{
- EHasChildren children = categoryHasChildren(id);
- if(children == CHILDREN_NO)
- {
- llinfos << "Not purging descendents of " << id << llendl;
- return;
- }
- LLPointer<LLViewerInventoryCategory> cat = getCategory(id);
- if (cat.notNull())
+ if (item_array.size() > 0)
{
- if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode())
+ gInventory.notifyObservers();
+ for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
+ iter != item_array.end();
+ iter++)
{
- // Something on the clipboard is in "cut mode" and needs to be preserved
- llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
- << " iterate and purge non hidden items" << llendl;
- cat_array_t* categories;
- item_array_t* items;
- // Get the list of direct descendants in tha categoy passed as argument
- getDirectDescendentsOf(id, categories, items);
- std::vector<LLUUID> list_uuids;
- // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently)
- // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists
- for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it)
- {
- list_uuids.push_back((*it)->getUUID());
- }
- for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it)
- {
- list_uuids.push_back((*it)->getUUID());
- }
- // Iterate through the list and only purge the UUIDs that are not on the clipboard
- for (std::vector<LLUUID>::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it)
- {
- if (!LLClipboard::instance().isOnClipboard(*it))
- {
- purgeObject(*it);
- }
- }
- }
- else
- {
- // Fast purge
- // do the cache accounting
- llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
- << llendl;
- S32 descendents = cat->getDescendentCount();
- if(descendents > 0)
- {
- LLCategoryUpdate up(id, -descendents);
- accountForUpdate(up);
- }
-
- // we know that descendent count is 0, however since the
- // accounting may actually not do an update, we should force
- // it here.
- cat->setDescendentCount(0);
-
- // send it upstream
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("PurgeInventoryDescendents");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->nextBlock("InventoryData");
- msg->addUUID("FolderID", id);
- gAgent.sendReliableMessage();
-
- // unceremoniously remove anything we have locally stored.
- cat_array_t categories;
- item_array_t items;
- collectDescendents(id,
- categories,
- items,
- INCLUDE_TRASH);
- S32 count = items.count();
-
- item_map_t::iterator item_map_end = mItemMap.end();
- cat_map_t::iterator cat_map_end = mCategoryMap.end();
- LLUUID uu_id;
-
- for(S32 i = 0; i < count; ++i)
- {
- uu_id = items.get(i)->getUUID();
-
- // This check prevents the deletion of a previously deleted item.
- // This is necessary because deletion is not done in a hierarchical
- // order. The current item may have been already deleted as a child
- // of its deleted parent.
- if (mItemMap.find(uu_id) != item_map_end)
- {
- deleteObject(uu_id);
- }
- }
-
- count = categories.count();
- for(S32 i = 0; i < count; ++i)
- {
- uu_id = categories.get(i)->getUUID();
- if (mCategoryMap.find(uu_id) != cat_map_end)
- {
- deleteObject(uu_id);
- }
- }
+ const LLViewerInventoryItem *linked_item = (*iter);
+ const LLUUID &item_id = linked_item->getUUID();
+ if (item_id == baseobj_id) continue;
+ addChangedMask(LLInventoryObserver::REBUILD, item_id);
}
+ gInventory.notifyObservers();
}
}
@@ -1396,8 +1484,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 +1550,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();
}
@@ -1601,7 +1695,6 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);
if(cat)
{
- bool accounted = false;
S32 version = cat->getVersion();
if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)
{
@@ -1616,22 +1709,27 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
}
if(descendents_server == descendents_actual)
{
- accounted = true;
descendents_actual += update.mDescendentDelta;
cat->setDescendentCount(descendents_actual);
cat->setVersion(++version);
- lldebugs << "accounted: '" << cat->getName() << "' "
+ LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' "
<< version << " with " << descendents_actual
- << " descendents." << llendl;
+ << " descendents." << LL_ENDL;
+ }
+ else
+ {
+ // Error condition, this means that the category did not register that
+ // it got new descendents (perhaps because it is still being loaded)
+ // which means its descendent count will be wrong.
+ llwarns << "Accounting failed for '" << cat->getName() << "' version:"
+ << version << " due to mismatched descendent count: server == "
+ << descendents_server << ", viewer == " << descendents_actual << llendl;
}
}
- if(!accounted)
+ else
{
- // Error condition, this means that the category did not register that
- // it got new descendents (perhaps because it is still being loaded)
- // which means its descendent count will be wrong.
- llwarns << "Accounting failed for '" << cat->getName() << "' version:"
- << version << llendl;
+ llwarns << "Accounting failed for '" << cat->getName() << "' version: unknown ("
+ << version << ")" << llendl;
}
}
else
@@ -1665,47 +1763,6 @@ void LLInventoryModel::accountForUpdate(
}
}
-
-/*
-void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id)
-{
- LLViewerInventoryCategory* cat = getCategory(category_id);
- if(cat)
- {
- S32 version = cat->getVersion();
- if(LLViewerInventoryCategory::VERSION_UNKNOWN != version)
- {
- cat->setVersion(version + 1);
- llinfos << "IncrementVersion: " << cat->getName() << " "
- << cat->getVersion() << llendl;
- }
- else
- {
- llinfos << "Attempt to increment version when unknown: "
- << category_id << llendl;
- }
- }
- else
- {
- llinfos << "Attempt to increment category: " << category_id << llendl;
- }
-}
-void LLInventoryModel::incrementCategorySetVersion(
- const std::set<LLUUID>& categories)
-{
- if(!categories.empty())
- {
- std::set<LLUUID>::const_iterator it = categories.begin();
- std::set<LLUUID>::const_iterator end = categories.end();
- for(; it != end; ++it)
- {
- incrementCategoryVersion(*it);
- }
- }
-}
-*/
-
-
LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(
const LLUUID& cat_id) const
{
@@ -2091,11 +2148,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 +2169,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 +2180,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 +2344,11 @@ void LLInventoryModel::buildParentChildMap()
notifyObservers();
}
}
+
+ if (!gInventory.validate())
+ {
+ llwarns << "model failed validity check!" << llendl;
+ }
}
struct LLUUIDAndName
@@ -2809,7 +2887,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 +2899,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 +2941,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 +3019,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 +3080,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 +3167,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 +3182,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 +3469,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..7afe1dea35 100755
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -34,6 +34,7 @@
#include "llhttpclient.h"
#include "lluuid.h"
#include "llpermissionsflags.h"
+#include "llviewerinventory.h"
#include "llstring.h"
#include "llmd5.h"
#include <map>
@@ -45,14 +46,9 @@ class LLInventoryObserver;
class LLInventoryObject;
class LLInventoryItem;
class LLInventoryCategory;
-class LLViewerInventoryItem;
-class LLViewerInventoryCategory;
-class LLViewerInventoryItem;
-class LLViewerInventoryCategory;
class LLMessageSystem;
class LLInventoryCollectFunctor;
-
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLInventoryModel
//
@@ -81,11 +77,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 +201,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 +212,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,10 +223,18 @@ 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
//--------------------------------------------------------------------
public:
+ const LLUUID findCategoryUUIDForTypeInRoot(
+ LLFolderType::EType preferred_type,
+ bool create_folder,
+ const LLUUID& root_id);
+
// Returns the uuid of the category that specifies 'type' as what it
// defaults to containing. The category is not necessarily only for that type.
// NOTE: If create_folder is true, this will create a new inventory category
@@ -322,11 +329,31 @@ public:
// Delete
//--------------------------------------------------------------------
public:
+
+ // Update model after an AISv3 update received for any operation.
+ void onAISUpdateReceived(const std::string& context, const LLSD& update);
+
+ // Update model after an item is confirmed as removed from
+ // server. Works for categories or items.
+ void onObjectDeletedFromServer(const LLUUID& item_id,
+ bool fix_broken_links = true,
+ bool update_parent_version = true,
+ bool do_notify_observers = true);
+
+ // Update model after all descendents removed from server.
+ void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);
+
+ // Update model after an existing item gets updated on server.
+ void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version);
+
+ // Update model after an existing category gets updated on server.
+ void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates);
+
// Delete a particular inventory object by ID. Will purge one
// object from the internal data structures, maintaining a
// consistent internal state. No cache accounting, observer
// notification, or server update is performed.
- void deleteObject(const LLUUID& id);
+ void deleteObject(const LLUUID& id, bool fix_broken_links = true, bool do_notify_observers = true);
/// move Item item_id to Trash
void removeItem(const LLUUID& item_id);
/// move Category category_id to Trash
@@ -334,17 +361,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);
@@ -379,8 +395,7 @@ public:
LLUUID createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& name,
- void (*callback)(const LLSD&, void*) = NULL,
- void* user_data = NULL );
+ boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>());
protected:
// Internal methods that add inventory and make sure that all of
// the internal data structures are consistent. These methods
@@ -551,6 +566,7 @@ private:
//--------------------------------------------------------------------
public:
void dumpInventory() const;
+ bool validate() const;
/** Miscellaneous
** **
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index d88e0c3192..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;
@@ -686,63 +695,46 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
{
if (folder_count)
{
- std::string url = region->getCapability("FetchInventoryDescendents2");
+ 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);
- LLHTTPClient::post(url, folder_request_body, fetcher, 300.0);
- }
- if (folder_request_body_lib["folders"].size())
- {
- std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
+ if (folder_request_body["folders"].size())
+ {
+ LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
+ LLHTTPClient::post(url, folder_request_body, fetcher, 300.0);
+ }
+ if (folder_request_body_lib["folders"].size())
+ {
+ std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
- LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
- LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
+ LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
+ LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
+ }
}
}
- }
if (item_count)
{
std::string url;
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 8d3539d297..a888445060 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -29,7 +29,7 @@
#include "apr_pools.h"
#include "apr_dso.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
#include "llmeshrepository.h"
#include "llagent.h"
@@ -203,6 +203,7 @@ U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
class LLMeshHeaderResponder : public LLCurl::Responder
{
+ LOG_CLASS(LLMeshHeaderResponder);
public:
LLVolumeParams mMeshParams;
bool mProcessed;
@@ -231,14 +232,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;
@@ -267,14 +268,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;
@@ -292,14 +293,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;
@@ -317,14 +318,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;
@@ -342,8 +343,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);
};
@@ -399,6 +399,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;
@@ -422,21 +423,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();
@@ -449,13 +449,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());
}
}
}
@@ -464,6 +465,7 @@ public:
class LLWholeModelUploadResponder: public LLCurl::Responder
{
+ LOG_CLASS(LLWholeModelUploadResponder);
LLMeshUploadThread* mThread;
LLSD mModelData;
LLHandle<LLWholeModelUploadObserver> mObserverHandle;
@@ -488,11 +490,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");
@@ -504,7 +505,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";
@@ -517,9 +518,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)
{
@@ -808,7 +809,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())
@@ -890,7 +891,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())
@@ -971,7 +972,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())
@@ -1052,7 +1053,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())
@@ -1127,7 +1128,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())
@@ -1899,10 +1900,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
@@ -1913,14 +1914,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++;
@@ -1928,8 +1930,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;
}
@@ -1963,10 +1965,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
@@ -1977,14 +1979,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++;
@@ -1992,8 +1995,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;
}
@@ -2027,10 +2030,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 )
@@ -2040,14 +2043,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++;
@@ -2055,8 +2059,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;
}
@@ -2090,10 +2094,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
@@ -2104,14 +2108,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++;
@@ -2119,8 +2124,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;
}
@@ -2154,10 +2159,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
@@ -2166,6 +2171,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
@@ -2179,9 +2185,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++;
@@ -2193,7 +2199,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
}
else
{
- llwarns << "Unhandled status." << llendl;
+ llwarns << "Unhandled status " << dumpResponse() << llendl;
}
}
@@ -2215,9 +2221,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..582998c973 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1079,10 +1079,10 @@ 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());
+ // the name of the wearable has changed, re-save wearable with new name
+ LLAppearanceMgr::instance().removeCOFItemLinks(mWearablePtr->getItemID(),gAgentAvatarp->mEndCustomizeCallback);
gAgentWearables.saveWearableAs(mWearablePtr->getType(), index, new_name, description, FALSE);
- mNameEditor->setText(mWearableItem->getName());
+ mNameEditor->setText(mWearableItem->getName());
}
else
{
@@ -1092,17 +1092,19 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
if (link_item)
{
// Create new link
- link_inventory_item( gAgent.getID(),
- link_item->getLinkedUUID(),
- LLAppearanceMgr::instance().getCOF(),
- link_item->getName(),
- description,
- LLAssetType::AT_LINK,
- NULL);
+ LL_DEBUGS("Avatar") << "link refresh, creating new link to " << link_item->getLinkedUUID()
+ << " removing old link at " << link_item->getUUID()
+ << " wearable item id " << mWearablePtr->getItemID() << llendl;
+
+ LLInventoryObject::const_object_list_t obj_array;
+ obj_array.push_back(LLConstPointer<LLInventoryObject>(link_item));
+ link_inventory_array(LLAppearanceMgr::instance().getCOF(),
+ obj_array,
+ gAgentAvatarp->mEndCustomizeCallback);
// Remove old link
- gInventory.purgeObject(link_item->getUUID());
+ remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback);
}
- 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 911ecaad9d..3ce066aa3c 100755
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -432,7 +432,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);
}
@@ -786,7 +786,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..21b77ef471 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);
@@ -183,7 +184,7 @@ bool LLPanelOutfitsInventory::onSaveCommit(const LLSD& notification, const LLSD&
LLStringUtil::trim(outfit_name);
if( !outfit_name.empty() )
{
- LLUUID outfit_folder = LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);
+ LLAppearanceMgr::getInstance()->makeNewOutfitLinks(outfit_name);
LLSidepanelAppearance* panel_appearance = getAppearanceSP();
if (panel_appearance)
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 df413ab849..e5637bcaf7 100755
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -452,7 +452,7 @@ void LLSidepanelAppearance::editWearable(LLViewerWearable *wearable, LLView *dat
LLFloaterSidePanelContainer::showPanel("appearance", LLSD());
LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data);
if (panel)
- {
+ {
panel->showWearableEditPanel(wearable, disable_camera_switch);
}
}
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index a4582071e8..bf209df863 100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -268,21 +268,23 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)
class ModerationResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(ModerationResponder);
public:
ModerationResponder(const LLUUID& session_id)
{
mSessionID = session_id;
}
- virtual void error(U32 status, const std::string& reason)
+protected:
+ virtual void httpFailure()
{
- llwarns << status << ": " << reason << llendl;
+ llwarns << dumpResponse() << llendl;;
if ( gIMMgr )
{
//403 == you're not a mod
//should be disabled if you're not a moderator
- if ( 403 == status )
+ if ( HTTP_FORBIDDEN == getStatus() )
{
gIMMgr->showSessionEventError(
"mute",
@@ -853,10 +855,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)
}
}
}
-/*prep#
- virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
- llwarns << "ModerationResponder error [status:" << status << "]: " << content << llendl;
- */
+
void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)
{
LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 67a76460a7..1c9276bab9 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1287,6 +1287,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();
@@ -2617,10 +2619,10 @@ void LLStartUp::saveInitialOutfit()
if (sWearablesLoadedCon.connected())
{
- lldebugs << "sWearablesLoadedCon is connected, disconnecting" << llendl;
+ LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << llendl;
sWearablesLoadedCon.disconnect();
}
- lldebugs << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << llendl;
+ LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << llendl;
LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);
}
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 6173e76a35..70e2c0f2dc 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,7 +36,7 @@
#include "lldir.h"
#include "llhttpclient.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
#include "llimage.h"
#include "llimagej2c.h"
#include "llimageworker.h"
@@ -63,6 +63,8 @@
#include "bufferarray.h"
#include "bufferstream.h"
+#include "llhttpretrypolicy.h"
+
bool LLTextureFetchDebugger::sDebuggerEnabled = false ;
LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128);
LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128);
@@ -244,6 +246,25 @@ static const S32 HTTP_REQUESTS_IN_QUEUE_LOW_WATER = 20; // Active level at whi
//////////////////////////////////////////////////////////////////////////////
+static const char* e_state_name[] =
+{
+ "INVALID",
+ "INIT",
+ "LOAD_FROM_TEXTURE_CACHE",
+ "CACHE_POST",
+ "LOAD_FROM_NETWORK",
+ "LOAD_FROM_SIMULATOR",
+ "WAIT_HTTP_RESOURCE",
+ "WAIT_HTTP_RESOURCE2",
+ "SEND_HTTP_REQ",
+ "WAIT_HTTP_REQ",
+ "DECODE_IMAGE",
+ "DECODE_IMAGE_UPDATE",
+ "WRITE_TO_CACHE",
+ "WAIT_ON_WRITE",
+ "DONE"
+};
+
class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
{
@@ -382,12 +403,14 @@ public:
void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
bool getCanUseHTTP() const { return mCanUseHTTP; }
+ void setUrl(const std::string& url) { mUrl = url; }
+
LLTextureFetch & getFetcher() { return *mFetcher; }
// Inherited from LLCore::HttpHandler
// Threads: Ttf
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
-
+
protected:
LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type,
const std::string& url, const LLUUID& id, const LLHost& host,
@@ -547,6 +570,8 @@ private:
S32 mActiveCount;
LLCore::HttpStatus mGetStatus;
std::string mGetReason;
+ LLAdaptiveRetryPolicy mFetchRetryPolicy;
+
// Work Data
LLMutex mWorkMutex;
@@ -889,7 +914,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mHttpHasResource(false),
mCacheReadCount(0U),
mCacheWriteCount(0U),
- mResourceWaitCount(0U)
+ mResourceWaitCount(0U),
+ mFetchRetryPolicy(10.0,3600.0,2.0,10)
{
mCanUseNET = mUrl.empty() ;
@@ -1148,6 +1174,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE
LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
<< " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
+
// fall through
}
@@ -1270,6 +1297,21 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (mState == LOAD_FROM_NETWORK)
{
+ // Check for retries to previous server failures.
+ F32 wait_seconds;
+ if (mFetchRetryPolicy.shouldRetry(wait_seconds))
+ {
+ if (wait_seconds <= 0.0)
+ {
+ llinfos << mID << " retrying now" << llendl;
+ }
+ else
+ {
+ //llinfos << mID << " waiting to retry for " << wait_seconds << " seconds" << llendl;
+ return false;
+ }
+ }
+
static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
// if (mHost != LLHost::invalid) get_url = false;
@@ -1286,7 +1328,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
std::string http_url = region->getHttpUrl() ;
if (!http_url.empty())
{
- mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
+ setUrl(http_url + "/?texture_id=" + mID.asString().c_str());
mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
}
else
@@ -1340,7 +1382,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
//recordTextureStart(false);
//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
- LL_DEBUGS("Texture") << mID << " does this happen?" << llendl;
return false;
}
}
@@ -1482,12 +1523,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
<< LL_ENDL;
// Will call callbackHttpGet when curl request completes
+ // Only server bake images use the returned headers currently, for getting retry-after field.
+ LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions;
mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass,
mWorkPriority,
mUrl,
mRequestedOffset,
mRequestedSize,
- mFetcher->mHttpOptions,
+ options,
mFetcher->mHttpHeaders,
this);
}
@@ -1519,15 +1562,22 @@ bool LLTextureFetchWorker::doWork(S32 param)
{
if (http_not_found == mGetStatus)
{
- if(mWriteToCacheState == NOT_WRITE) //map tiles
+ if (mFTType != FTT_MAP_TILE)
+ {
+ llwarns << "Texture missing from server (404): " << mUrl << llendl;
+ }
+
+ if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes
{
setState(DONE);
releaseHttpSemaphore();
- LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl;
- return true; // failed, means no map tile on the empty region.
+ if (mFTType != FTT_MAP_TILE)
+ {
+ LL_WARNS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << llendl;
+ }
+ return true;
}
- llwarns << "Texture missing from server (404): " << mUrl << llendl;
// roll back to try UDP
if (mCanUseNET)
@@ -1543,6 +1593,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
else if (http_service_unavail == mGetStatus)
{
LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL;
+ llinfos << "503: HTTP GET failed for: " << mUrl
+ << " Status: " << mGetStatus.toHex()
+ << " Reason: '" << mGetReason << "'"
+ << llendl;
}
else if (http_not_sat == mGetStatus)
{
@@ -1551,7 +1605,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
else
{
- llinfos << "HTTP GET failed for: " << mUrl
+ llinfos << "other: HTTP GET failed for: " << mUrl
<< " Status: " << mGetStatus.toHex()
<< " Reason: '" << mGetReason << "'"
<< llendl;
@@ -1891,14 +1945,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe
mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
}
+ static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate");
+ F32 rand_val = ll_frand();
+ F32 rate = fake_failure_rate;
+ if (mFTType == FTT_SERVER_BAKE && (fake_failure_rate > 0.0) && (rand_val < fake_failure_rate))
+ {
+ llwarns << mID << " for debugging, setting fake failure status for texture " << mID
+ << " (rand was " << rand_val << "/" << rate << ")" << llendl;
+ response->setStatus(LLCore::HttpStatus(503));
+ }
bool success = true;
bool partial = false;
LLCore::HttpStatus status(response->getStatus());
+ if (!status && (mFTType == FTT_SERVER_BAKE))
+ {
+ llinfos << mID << " state " << e_state_name[mState] << llendl;
+ mFetchRetryPolicy.onFailure(response);
+ F32 retry_after;
+ if (mFetchRetryPolicy.shouldRetry(retry_after))
+ {
+ llinfos << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << llendl;
+ mFetcher->removeFromHTTPQueue(mID, 0);
+ std::string reason(status.toString());
+ setGetStatus(status, reason);
+ releaseHttpSemaphore();
+ setState(LOAD_FROM_NETWORK);
+ return;
+ }
+ else
+ {
+ llinfos << mID << " will not retry" << llendl;
+ }
+ }
+ else
+ {
+ mFetchRetryPolicy.onSuccess();
+ }
LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID
- << " status: " << status.toHex()
- << " '" << status.toString() << "'"
- << llendl;
+ << " status: " << status.toHex()
+ << " '" << status.toString() << "'"
+ << llendl;
+
// unsigned int offset(0), length(0), full_length(0);
// response->getRange(&offset, &length, &full_length);
// llwarns << "HTTP COMPLETE: " << mID << " handle: " << handle
@@ -1907,13 +1995,16 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe
// << " offset: " << offset << " length: " << length
// << llendl;
+ std::string reason(status.toString());
+ setGetStatus(status, reason);
if (! status)
{
success = false;
- std::string reason(status.toString());
- setGetStatus(status, reason);
- llwarns << "CURL GET FAILED, status: " << status.toHex()
- << " reason: " << reason << llendl;
+ if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them.
+ {
+ llwarns << mID << " CURL GET FAILED, status: " << status.toHex()
+ << " reason: " << reason << llendl;
+ }
}
else
{
@@ -2376,6 +2467,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
mQAMode(qa_mode),
mHttpRequest(NULL),
mHttpOptions(NULL),
+ mHttpOptionsWithHeaders(NULL),
mHttpHeaders(NULL),
mHttpMetricsHeaders(NULL),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
@@ -2406,10 +2498,13 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
mHttpRequest = new LLCore::HttpRequest;
mHttpOptions = new LLCore::HttpOptions;
+ mHttpOptionsWithHeaders = new LLCore::HttpOptions;
+ mHttpOptionsWithHeaders->setWantHeaders(true);
mHttpHeaders = new LLCore::HttpHeaders;
- mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c");
+ // *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ?
+ mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);
mHttpMetricsHeaders = new LLCore::HttpHeaders;
- mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml");
+ mHttpMetricsHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault();
}
@@ -2430,6 +2525,12 @@ LLTextureFetch::~LLTextureFetch()
mHttpOptions = NULL;
}
+ if (mHttpOptionsWithHeaders)
+ {
+ mHttpOptionsWithHeaders->release();
+ mHttpOptionsWithHeaders = NULL;
+ }
+
if (mHttpHeaders)
{
mHttpHeaders->release();
@@ -2464,7 +2565,11 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
{
return false;
}
-
+
+ if (f_type == FTT_SERVER_BAKE)
+ {
+ LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << llendl;
+ }
LLTextureFetchWorker* worker = getWorker(id) ;
if (worker)
{
@@ -2522,7 +2627,8 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
worker->mNeedsAux = needs_aux;
worker->setImagePriority(priority);
worker->setDesiredDiscard(desired_discard, desired_size);
- worker->setCanUseHTTP(can_use_http) ;
+ worker->setCanUseHTTP(can_use_http);
+ worker->setUrl(url);
if (!worker->haveWork())
{
worker->setState(LLTextureFetchWorker::INIT);
@@ -2549,7 +2655,7 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const
worker->unlockWorkMutex(); // -Mw
}
- LL_DEBUGS("Texture") << "REQUESTED: " << id << " Discard: " << desired_discard << " size " << desired_size << llendl;
+ LL_DEBUGS("Texture") << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) << " Discard: " << desired_discard << " size " << desired_size << llendl;
return true;
}
@@ -2728,7 +2834,8 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
// Threads: T*
bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
- LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux)
+ LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux,
+ LLCore::HttpStatus& last_http_get_status)
{
bool res = false;
LLTextureFetchWorker* worker = getWorker(id);
@@ -2750,6 +2857,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
else if (worker->checkWork())
{
worker->lockWorkMutex(); // +Mw
+ last_http_get_status = worker->mGetStatus;
discard_level = worker->mDecodedDiscard;
raw = worker->mRawImage;
aux = worker->mAuxImage;
@@ -3220,25 +3328,14 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)
void LLTextureFetchWorker::setState(e_state new_state)
{
- static const char* e_state_name[] =
- {
- "INVALID",
- "INIT",
- "LOAD_FROM_TEXTURE_CACHE",
- "CACHE_POST",
- "LOAD_FROM_NETWORK",
- "LOAD_FROM_SIMULATOR",
- "WAIT_HTTP_RESOURCE",
- "WAIT_HTTP_RESOURCE2",
- "SEND_HTTP_REQ",
- "WAIT_HTTP_REQ",
- "DECODE_IMAGE",
- "DECODE_IMAGE_UPDATE",
- "WRITE_TO_CACHE",
- "WAIT_ON_WRITE",
- "DONE"
- };
- LL_DEBUGS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl;
+ if (mFTType == FTT_SERVER_BAKE)
+ {
+ // NOTE: turning on these log statements is a reliable way to get
+ // blurry images fairly frequently. Presumably this is an
+ // indication of some subtle timing or locking issue.
+
+// LL_INFOS("Texture") << "id: " << mID << " FTType: " << mFTType << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << llendl;
+ }
mState = new_state;
}
@@ -4041,7 +4138,8 @@ void LLTextureFetchDebugger::init()
if (! mHttpHeaders)
{
mHttpHeaders = new LLCore::HttpHeaders;
- mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c");
+ // *TODO: Should this be 'image/j2c' instead of 'image/x-j2c' ?
+ mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);
}
}
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 902a3d7a25..237912cde7 100755
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
+ * Copyright (C) 2012-2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -95,7 +95,8 @@ public:
// Threads: T*
bool getRequestFinished(const LLUUID& id, S32& discard_level,
- LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux);
+ LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux,
+ LLCore::HttpStatus& last_http_get_status);
// Threads: T*
bool updateRequestPriority(const LLUUID& id, F32 priority);
@@ -351,6 +352,7 @@ private:
// LLCurl interfaces used in the past.
LLCore::HttpRequest * mHttpRequest; // Ttf
LLCore::HttpOptions * mHttpOptions; // Ttf
+ LLCore::HttpOptions * mHttpOptionsWithHeaders; // Ttf
LLCore::HttpHeaders * mHttpHeaders; // Ttf
LLCore::HttpHeaders * mHttpMetricsHeaders; // Ttf
LLCore::HttpRequest::policy_t mHttpPolicyClass; // T*
@@ -395,6 +397,9 @@ private:
e_tex_source mFetchSource;
e_tex_source mOriginFetchSource;
+ // Retry logic
+ //LLAdaptiveRetryPolicy mFetchRetryPolicy;
+
public:
//debug use
LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;}
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 148e5a015b..71e0509d03 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->setVolatile(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->setVolatile(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/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp
index a179b61cff..4e028d2163 100755
--- a/indra/newview/llviewerfoldertype.cpp
+++ b/indra/newview/llviewerfoldertype.cpp
@@ -139,14 +139,10 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()
addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, false, "default"));
-#if SUPPORT_ENSEMBLES
- initEnsemblesFromFile();
-#else
for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type)
{
addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "Inv_FolderOpen", "Inv_FolderClosed", FALSE, false));
- }
-#endif
+ }
}
bool LLViewerFolderDictionary::initEnsemblesFromFile()
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index fff9821e86..ede6eb8490 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -31,6 +31,7 @@
#include "llsdserialize.h"
#include "message.h"
+#include "llaisapi.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentwearables.h"
@@ -65,9 +66,12 @@
#include "llavataractions.h"
#include "lllogininstance.h"
#include "llfavoritesbar.h"
+#include "llclipboard.h"
+#include "llhttpretrypolicy.h"
-// Two do-nothing ops for use in callbacks.
+// do-nothing ops for use in callbacks.
void no_op_inventory_func(const LLUUID&) {}
+void no_op_llsd_func(const LLSD&) {}
void no_op() {}
///----------------------------------------------------------------------------
@@ -256,7 +260,6 @@ public:
};
LLInventoryHandler gInventoryHandler;
-
///----------------------------------------------------------------------------
/// Class LLViewerInventoryItem
///----------------------------------------------------------------------------
@@ -345,24 +348,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)
@@ -376,7 +361,8 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const
if(gAgent.getID() != mPermissions.getOwner())
{
// *FIX: deal with this better.
- llwarns << "LLViewerInventoryItem::updateServer() - for unowned item"
+ llwarns << "LLViewerInventoryItem::updateServer() - for unowned item "
+ << ll_pretty_print_sd(this->asLLSD())
<< llendl;
return;
}
@@ -444,7 +430,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const
}
// virtual
-BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
+BOOL LLViewerInventoryItem::unpackMessage(const LLSD& item)
{
BOOL rv = LLInventoryItem::fromLLSD(item);
@@ -469,7 +455,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_
{
mTransactionID = transaction_id;
}
-// virtual
+
void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
{
msg->addUUIDFast(_PREHASH_ItemID, mUUID);
@@ -488,6 +474,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
U32 crc = getCRC32();
msg->addU32Fast(_PREHASH_CRC, crc);
}
+
// virtual
BOOL LLViewerInventoryItem::importFile(LLFILE* fp)
{
@@ -599,6 +586,15 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego
}
+void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const
+{
+ msg->addUUIDFast(_PREHASH_FolderID, mUUID);
+ msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
+ S8 type = static_cast<S8>(mPreferredType);
+ msg->addS8Fast(_PREHASH_Type, type);
+ msg->addStringFast(_PREHASH_Name, mName);
+}
+
void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const
{
LLMessageSystem* msg = gMessageSystem;
@@ -637,30 +633,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;
@@ -894,6 +866,21 @@ void LLViewerInventoryCategory::localizeName()
LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
}
+// virtual
+BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category)
+{
+ BOOL rv = LLInventoryCategory::fromLLSD(category);
+ localizeName();
+ return rv;
+}
+
+// virtual
+void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
+{
+ LLInventoryCategory::unpackMessage(msg, block, block_num);
+ localizeName();
+}
+
///----------------------------------------------------------------------------
/// Local function definitions
///----------------------------------------------------------------------------
@@ -1087,77 +1074,152 @@ void copy_inventory_item(
gAgent.sendReliableMessage();
}
-void link_inventory_item(
- const LLUUID& agent_id,
- const LLUUID& item_id,
- const LLUUID& parent_id,
- const std::string& new_name,
- const std::string& new_description,
- const LLAssetType::EType asset_type,
- LLPointer<LLInventoryCallback> cb)
+// Create link to single inventory object.
+void link_inventory_object(const LLUUID& category,
+ LLConstPointer<LLInventoryObject> baseobj,
+ LLPointer<LLInventoryCallback> cb)
{
- const LLInventoryObject *baseobj = gInventory.getObject(item_id);
if (!baseobj)
{
- llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl;
- return;
- }
- if (baseobj && baseobj->getIsLinkType())
- {
- llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl;
+ llwarns << "Attempt to link to non-existent object" << llendl;
return;
}
- if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType()))
- {
- // Fail if item can be found but is of a type that can't be linked.
- // Arguably should fail if the item can't be found too, but that could
- // be a larger behavioral change.
- llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl;
- return;
- }
-
- LLUUID transaction_id;
- LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
- if (dynamic_cast<const LLInventoryCategory *>(baseobj))
- {
- inv_type = LLInventoryType::IT_CATEGORY;
- }
- else
+ LLInventoryObject::const_object_list_t obj_array;
+ obj_array.push_back(baseobj);
+ link_inventory_array(category, obj_array, cb);
+}
+
+void link_inventory_object(const LLUUID& category,
+ const LLUUID& id,
+ LLPointer<LLInventoryCallback> cb)
+{
+ LLConstPointer<LLInventoryObject> baseobj = gInventory.getObject(id);
+ link_inventory_object(category, baseobj, cb);
+}
+
+// Create links to all listed inventory objects.
+void link_inventory_array(const LLUUID& category,
+ LLInventoryObject::const_object_list_t& baseobj_array,
+ LLPointer<LLInventoryCallback> cb)
+{
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ const LLViewerInventoryCategory *cat = gInventory.getCategory(category);
+ const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND";
+#endif
+ LLInventoryObject::const_object_list_t::const_iterator it = baseobj_array.begin();
+ LLInventoryObject::const_object_list_t::const_iterator end = baseobj_array.end();
+ LLSD links = LLSD::emptyArray();
+ for (; it != end; ++it)
{
- const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj);
- if (baseitem)
+ const LLInventoryObject* baseobj = *it;
+ if (!baseobj)
{
- inv_type = baseitem->getInventoryType();
+ llwarns << "attempt to link to unknown object" << llendl;
+ continue;
}
- }
-#if 1 // debugging stuff
- LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
- lldebugs << "cat: " << cat << llendl;
-
+ if (!LLAssetType::lookupCanLink(baseobj->getType()))
+ {
+ // Fail if item can be found but is of a type that can't be linked.
+ // Arguably should fail if the item can't be found too, but that could
+ // be a larger behavioral change.
+ llwarns << "attempt to link an unlinkable object, type = " << baseobj->getActualType() << llendl;
+ continue;
+ }
+
+ LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
+ LLAssetType::EType asset_type = LLAssetType::AT_NONE;
+ std::string new_desc;
+ LLUUID linkee_id;
+ if (dynamic_cast<const LLInventoryCategory *>(baseobj))
+ {
+ inv_type = LLInventoryType::IT_CATEGORY;
+ asset_type = LLAssetType::AT_LINK_FOLDER;
+ linkee_id = baseobj->getUUID();
+ }
+ else
+ {
+ const LLViewerInventoryItem *baseitem = dynamic_cast<const LLViewerInventoryItem *>(baseobj);
+ if (baseitem)
+ {
+ inv_type = baseitem->getInventoryType();
+ new_desc = baseitem->getActualDescription();
+ switch (baseitem->getActualType())
+ {
+ case LLAssetType::AT_LINK:
+ case LLAssetType::AT_LINK_FOLDER:
+ linkee_id = baseobj->getLinkedUUID();
+ asset_type = baseitem->getActualType();
+ break;
+ default:
+ linkee_id = baseobj->getUUID();
+ asset_type = LLAssetType::AT_LINK;
+ break;
+ }
+ }
+ else
+ {
+ llwarns << "could not convert object into an item or category: " << baseobj->getUUID() << llendl;
+ continue;
+ }
+ }
+
+ LLSD link = LLSD::emptyMap();
+ link["linked_id"] = linkee_id;
+ link["type"] = (S8)asset_type;
+ link["inv_type"] = (S8)inv_type;
+ link["name"] = baseobj->getName();
+ link["desc"] = new_desc;
+ links.append(link);
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ LL_DEBUGS("Inventory") << "Linking Object [ name:" << baseobj->getName()
+ << " UUID:" << baseobj->getUUID()
+ << " ] into Category [ name:" << cat_name
+ << " UUID:" << category << " ] " << LL_ENDL;
#endif
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_LinkInventoryItem);
- msg->nextBlock(_PREHASH_AgentData);
+ }
+
+ bool ais_ran = false;
+ if (AISCommand::isAPIAvailable())
{
- msg->addUUIDFast(_PREHASH_AgentID, agent_id);
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ LLSD new_inventory = LLSD::emptyMap();
+ new_inventory["links"] = links;
+ LLPointer<AISCommand> cmd_ptr = new CreateInventoryCommand(category, new_inventory, cb);
+ ais_ran = cmd_ptr->run_command();
}
- msg->nextBlock(_PREHASH_InventoryBlock);
+
+ if (!ais_ran)
{
- msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
- msg->addUUIDFast(_PREHASH_FolderID, parent_id);
- msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
- msg->addUUIDFast(_PREHASH_OldItemID, item_id);
- msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
- msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
- msg->addStringFast(_PREHASH_Name, new_name);
- msg->addStringFast(_PREHASH_Description, new_description);
+ LLMessageSystem* msg = gMessageSystem;
+ for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter )
+ {
+ msg->newMessageFast(_PREHASH_LinkInventoryItem);
+ msg->nextBlock(_PREHASH_AgentData);
+ {
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ }
+ msg->nextBlock(_PREHASH_InventoryBlock);
+ {
+ LLSD link = (*iter);
+ msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
+ msg->addUUIDFast(_PREHASH_FolderID, category);
+ msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null);
+ msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID());
+ msg->addS8Fast(_PREHASH_Type, link["type"].asInteger());
+ msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger());
+ msg->addStringFast(_PREHASH_Name, link["name"].asString());
+ msg->addStringFast(_PREHASH_Description, link["desc"].asString());
+ }
+ gAgent.sendReliableMessage();
+ }
}
- gAgent.sendReliableMessage();
}
+
+
void move_inventory_item(
const LLUUID& agent_id,
const LLUUID& session_id,
@@ -1179,6 +1241,387 @@ void move_inventory_item(
gAgent.sendReliableMessage();
}
+// Should call this with an update_item that's been copied and
+// modified from an original source item, rather than modifying the
+// source item directly.
+void update_inventory_item(
+ LLViewerInventoryItem *update_item,
+ LLPointer<LLInventoryCallback> cb)
+{
+ const LLUUID& item_id = update_item->getUUID();
+ bool ais_ran = false;
+ if (AISCommand::isAPIAvailable())
+ {
+ LLSD updates = update_item->asLLSD();
+ // Replace asset_id with transaction_id (hash_id)
+ if (updates.has("asset_id"))
+ {
+ updates.erase("asset_id");
+ updates["hash_id"] = update_item->getTransactionID();
+ }
+ LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
+ ais_ran = cmd_ptr->run_command();
+ }
+ if (!ais_ran)
+ {
+ LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << llendl;
+ if(obj)
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_UpdateInventoryItem);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID());
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ msg->addU32Fast(_PREHASH_CallbackID, 0);
+ update_item->packMessage(msg);
+ gAgent.sendReliableMessage();
+
+ LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0);
+ gInventory.accountForUpdate(up);
+ gInventory.updateItem(update_item);
+ if (cb)
+ {
+ cb->fire(item_id);
+ }
+ }
+ }
+}
+
+// Note this only supports updating an existing item. Goes through AISv3
+// code path where available. Not all uses of item->updateServer() can
+// easily be switched to this paradigm.
+void update_inventory_item(
+ const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb)
+{
+ bool ais_ran = false;
+ if (AISCommand::isAPIAvailable())
+ {
+ LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
+ ais_ran = cmd_ptr->run_command();
+ }
+ if (!ais_ran)
+ {
+ LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+ if(obj)
+ {
+ LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
+ new_item->copyViewerItem(obj);
+ new_item->fromLLSD(updates,false);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_UpdateInventoryItem);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID());
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ msg->addU32Fast(_PREHASH_CallbackID, 0);
+ new_item->packMessage(msg);
+ gAgent.sendReliableMessage();
+
+ LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0);
+ gInventory.accountForUpdate(up);
+ gInventory.updateItem(new_item);
+ if (cb)
+ {
+ cb->fire(item_id);
+ }
+ }
+ }
+}
+
+void update_inventory_category(
+ const LLUUID& cat_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb)
+{
+ LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id);
+ LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+ if(obj)
+ {
+ if (LLFolderType::lookupIsProtectedType(obj->getPreferredType()))
+ {
+ LLNotificationsUtil::add("CannotModifyProtectedCategories");
+ return;
+ }
+
+ LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj);
+ new_cat->fromLLSD(updates);
+ // FIXME - restore this once the back-end work has been done.
+ if (AISCommand::isAPIAvailable())
+ {
+ LLSD new_llsd = new_cat->asLLSD();
+ LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb);
+ cmd_ptr->run_command();
+ }
+ else // no cap
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_FolderData);
+ new_cat->packMessage(msg);
+ gAgent.sendReliableMessage();
+
+ LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0);
+ gInventory.accountForUpdate(up);
+ gInventory.updateCategory(new_cat);
+ if (cb)
+ {
+ cb->fire(cat_id);
+ }
+ }
+ }
+}
+
+void remove_inventory_items(
+ LLInventoryObject::object_list_t& items_to_kill,
+ LLPointer<LLInventoryCallback> cb)
+{
+ for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin();
+ it != items_to_kill.end();
+ ++it)
+ {
+ remove_inventory_item(*it, cb);
+ }
+}
+
+void remove_inventory_item(
+ const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> cb)
+{
+ LLPointer<LLInventoryObject> obj = gInventory.getItem(item_id);
+ if (obj)
+ {
+ remove_inventory_item(obj, cb);
+ }
+ else
+ {
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << "(NOT FOUND)" << llendl;
+ }
+}
+
+void remove_inventory_item(
+ LLPointer<LLInventoryObject> obj,
+ LLPointer<LLInventoryCallback> cb)
+{
+ if(obj)
+ {
+ const LLUUID item_id(obj->getUUID());
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << obj->getName() << llendl;
+ if (AISCommand::isAPIAvailable())
+ {
+ 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
+ {
+ // *TODO: Clean up callback?
+ llwarns << "remove_inventory_item called for invalid or nonexistent item." << 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;
+ }
+ if (AISCommand::isAPIAvailable())
+ {
+ 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
+ {
+ if (AISCommand::isAPIAvailable())
+ {
+ LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb);
+ cmd_ptr->run_command();
+ }
+ else // no cap
+ {
+ // Fast purge
+ LL_DEBUGS("Inventory") << "purge_descendents_of fast case " << cat->getName() << llendl;
+
+ // send it upstream
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("PurgeInventoryDescendents");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->nextBlock("InventoryData");
+ msg->addUUID("FolderID", id);
+ gAgent.sendReliableMessage();
+
+ // Update model immediately because there is no callback mechanism.
+ gInventory.onDescendentsPurgedFromServer(id);
+ if (cb)
+ {
+ cb->fire(id);
+ }
+ }
+ }
+ }
+}
+
const LLUUID get_folder_by_itemtype(const LLInventoryItem *src)
{
LLUUID retval = LLUUID::null;
@@ -1278,6 +1721,53 @@ void create_new_item(const std::string& name,
}
+void slam_inventory_folder(const LLUUID& folder_id,
+ const LLSD& contents,
+ LLPointer<LLInventoryCallback> cb)
+{
+ if (AISCommand::isAPIAvailable())
+ {
+ LL_DEBUGS("Avatar") << "using AISv3 to slam folder, id " << folder_id
+ << " new contents: " << ll_pretty_print_sd(contents) << llendl;
+ LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb);
+ cmd_ptr->run_command();
+ }
+ else // no cap
+ {
+ LL_DEBUGS("Avatar") << "using item-by-item calls to slam folder, id " << folder_id
+ << " new contents: " << ll_pretty_print_sd(contents) << llendl;
+ for (LLSD::array_const_iterator it = contents.beginArray();
+ it != contents.endArray();
+ ++it)
+ {
+ const LLSD& item_contents = *it;
+ LLViewerInventoryItem *item = new LLViewerInventoryItem;
+ item->fromLLSD(item_contents);
+ link_inventory_object(folder_id, item, cb);
+ }
+ remove_folder_contents(folder_id,false,cb);
+ }
+}
+
+void remove_folder_contents(const LLUUID& category, bool keep_outfit_links,
+ LLPointer<LLInventoryCallback> cb)
+{
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendents(category, cats, items,
+ LLInventoryModel::EXCLUDE_TRASH);
+ for (S32 i = 0; i < items.count(); ++i)
+ {
+ LLViewerInventoryItem *item = items.get(i);
+ if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER))
+ continue;
+ if (item->getIsLinkType())
+ {
+ remove_inventory_item(item->getUUID(), cb);
+ }
+ }
+}
+
const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not)
const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not)
const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not)
@@ -1713,3 +2203,5 @@ BOOL LLViewerInventoryItem::regenerateLink()
gInventory.notifyObservers();
return TRUE;
}
+
+
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index ab19a12014..c82c2b6fbe 100755
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -118,14 +118,13 @@ public:
void cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const;
// virtual methods
- virtual void removeFromServer( void );
virtual void updateParentOnServer(BOOL restamp) const;
virtual void updateServer(BOOL is_new) const;
void fetchFromServer(void) const;
- //virtual void packMessage(LLMessageSystem* msg) const;
+ virtual void packMessage(LLMessageSystem* msg) const;
virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
- virtual BOOL unpackMessage(LLSD item);
+ virtual BOOL unpackMessage(const LLSD& item);
virtual BOOL importFile(LLFILE* fp);
virtual BOOL importLegacyStream(std::istream& input_stream);
@@ -139,7 +138,6 @@ public:
void setComplete(BOOL complete) { mIsComplete = complete; }
//void updateAssetOnServer() const;
- virtual void packMessage(LLMessageSystem* msg) const;
virtual void setTransactionID(const LLTransactionID& transaction_id);
struct comparePointers
{
@@ -198,10 +196,11 @@ public:
LLViewerInventoryCategory(const LLViewerInventoryCategory* other);
void copyViewerCategory(const LLViewerInventoryCategory* other);
- virtual void removeFromServer();
virtual void updateParentOnServer(BOOL restamp_children) const;
virtual void updateServer(BOOL is_new) const;
+ virtual void packMessage(LLMessageSystem* msg) const;
+
const LLUUID& getOwnerID() const { return mOwnerID; }
// Version handling
@@ -225,6 +224,8 @@ public:
bool importFileLocal(LLFILE* fp);
void determineFolderType();
void changeType(LLFolderType::EType new_folder_type);
+ virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
+ virtual BOOL unpackMessage(const LLSD& category);
private:
friend class LLInventoryModel;
@@ -264,9 +265,11 @@ private:
};
typedef boost::function<void(const LLUUID&)> inventory_func_type;
-void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func
-
+typedef boost::function<void(const LLSD&)> llsd_func_type;
typedef boost::function<void()> nullary_func_type;
+
+void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func
+void no_op_llsd_func(const LLSD&); // likewise for LLSD
void no_op(); // A do-nothing nullary func.
// Shim between inventory callback and boost function/callable
@@ -274,7 +277,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)
@@ -348,14 +351,16 @@ void copy_inventory_item(
const std::string& new_name,
LLPointer<LLInventoryCallback> cb);
-void link_inventory_item(
- const LLUUID& agent_id,
- const LLUUID& item_id,
- const LLUUID& parent_id,
- const std::string& new_name,
- const std::string& new_description,
- const LLAssetType::EType asset_type,
- LLPointer<LLInventoryCallback> cb);
+// utility functions for inventory linking.
+void link_inventory_object(const LLUUID& category,
+ LLConstPointer<LLInventoryObject> baseobj,
+ LLPointer<LLInventoryCallback> cb);
+void link_inventory_object(const LLUUID& category,
+ const LLUUID& id,
+ LLPointer<LLInventoryCallback> cb);
+void link_inventory_array(const LLUUID& category,
+ LLInventoryObject::const_object_list_t& baseobj_array,
+ LLPointer<LLInventoryCallback> cb);
void move_inventory_item(
const LLUUID& agent_id,
@@ -365,6 +370,44 @@ void move_inventory_item(
const std::string& new_name,
LLPointer<LLInventoryCallback> cb);
+void update_inventory_item(
+ LLViewerInventoryItem *update_item,
+ LLPointer<LLInventoryCallback> cb);
+
+void update_inventory_item(
+ const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb);
+
+void update_inventory_category(
+ const LLUUID& cat_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb);
+
+void remove_inventory_items(
+ LLInventoryObject::object_list_t& items,
+ LLPointer<LLInventoryCallback> cb);
+
+void remove_inventory_item(
+ LLPointer<LLInventoryObject> obj,
+ LLPointer<LLInventoryCallback> cb);
+
+void remove_inventory_item(
+ const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> cb);
+
+void remove_inventory_category(
+ const LLUUID& cat_id,
+ LLPointer<LLInventoryCallback> cb);
+
+void remove_inventory_object(
+ const LLUUID& object_id,
+ LLPointer<LLInventoryCallback> cb);
+
+void purge_descendents_of(
+ const LLUUID& cat_id,
+ LLPointer<LLInventoryCallback> cb);
+
const LLUUID get_folder_by_itemtype(const LLInventoryItem *src);
void copy_inventory_from_notecard(const LLUUID& destination_id,
@@ -379,4 +422,11 @@ void menu_create_inventory_item(LLInventoryPanel* root,
const LLSD& userdata,
const LLUUID& default_parent_uuid = LLUUID::null);
+void slam_inventory_folder(const LLUUID& folder_id,
+ const LLSD& contents,
+ LLPointer<LLInventoryCallback> cb);
+
+void remove_folder_contents(const LLUUID& folder_id, bool keep_outfit_links,
+ LLPointer<LLInventoryCallback> cb);
+
#endif // LL_LLVIEWERINVENTORY_H
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 2df028de69..2cec808f19 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -158,7 +158,7 @@ LLViewerMediaObserver::~LLViewerMediaObserver()
// on the Panel Land Media and to discover the MIME type
class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
{
-LOG_CLASS(LLMimeDiscoveryResponder);
+ LOG_CLASS(LLMimeDiscoveryResponder);
public:
LLMimeDiscoveryResponder( viewer_media_t media_impl)
: mMediaImpl(media_impl),
@@ -177,13 +177,19 @@ public:
disconnectOwner();
}
- virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+private:
+ /* virtual */ void httpCompleted()
{
- std::string media_type = content["content-type"].asString();
+ if (!isGoodStatus())
+ {
+ llwarns << dumpResponse()
+ << " [headers:" << getResponseHeaders() << "]" << llendl;
+ }
+ const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE);
std::string::size_type idx1 = media_type.find_first_of(";");
std::string mime_type = media_type.substr(0, idx1);
- lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl;
+ lldebugs << "status is " << getStatus() << ", media type \"" << media_type << "\"" << llendl;
// 2xx status codes indicate success.
// Most 4xx status codes are successful enough for our purposes.
@@ -200,32 +206,27 @@ public:
// )
// We now no longer check the error code returned from the probe.
// If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting.
- if(1)
+ //if(1)
{
// The probe was successful.
if(mime_type.empty())
{
// Some sites don't return any content-type header at all.
// Treat an empty mime type as text/html.
- mime_type = "text/html";
+ mime_type = HTTP_CONTENT_TEXT_HTML;
}
-
- completeAny(status, mime_type);
}
- else
- {
- llwarns << "responder failed with status " << status << ", reason " << reason << llendl;
-
- if(mMediaImpl)
- {
- mMediaImpl->mMediaSourceFailed = true;
- }
- }
-
- }
+ //else
+ //{
+ // llwarns << "responder failed with status " << dumpResponse() << llendl;
+ //
+ // if(mMediaImpl)
+ // {
+ // mMediaImpl->mMediaSourceFailed = true;
+ // }
+ // return;
+ //}
- void completeAny(U32 status, const std::string& mime_type)
- {
// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
// Make a local copy so we can call loadURI() afterwards.
LLViewerMediaImpl *impl = mMediaImpl;
@@ -241,6 +242,7 @@ public:
}
}
+public:
void cancelRequest()
{
disconnectOwner();
@@ -269,7 +271,7 @@ public:
class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder
{
-LOG_CLASS(LLViewerMediaOpenIDResponder);
+ LOG_CLASS(LLViewerMediaOpenIDResponder);
public:
LLViewerMediaOpenIDResponder( )
{
@@ -279,23 +281,17 @@ public:
{
}
- /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
- LL_DEBUGS("MediaAuth") << content << LL_ENDL;
- std::string cookie = content["set-cookie"].asString();
-
- LLViewerMedia::openIDCookieResponse(cookie);
- }
-
/* virtual */ void completedRaw(
- U32 status,
- const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer)
{
- // This is just here to disable the default behavior (attempting to parse the response as llsd).
- // We don't care about the content of the response, only the set-cookie header.
+ // We don't care about the content of the response, only the Set-Cookie header.
+ LL_DEBUGS("MediaAuth") << dumpResponse()
+ << " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
+ const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
+
+ // *TODO: What about bad status codes? Does this destroy previous cookies?
+ LLViewerMedia::openIDCookieResponse(cookie);
}
};
@@ -313,17 +309,23 @@ public:
{
}
- /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ void completedRaw(
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
{
- LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
+ // We don't care about the content of the response, only the set-cookie header.
+ LL_WARNS("MediaAuth") << dumpResponse()
+ << " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
- LLSD stripped_content = content;
- stripped_content.erase("set-cookie");
+ LLSD stripped_content = getResponseHeaders();
+ // *TODO: Check that this works.
+ stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE);
LL_WARNS("MediaAuth") << stripped_content << LL_ENDL;
- std::string cookie = content["set-cookie"].asString();
+ const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL;
+ // *TODO: What about bad status codes? Does this destroy previous cookies?
LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
// Set cookie for snapshot publishing.
@@ -331,16 +333,6 @@ public:
LLWebProfile::setAuthCookie(auth_cookie);
}
- void completedRaw(
- U32 status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- // This is just here to disable the default behavior (attempting to parse the response as llsd).
- // We don't care about the content of the response, only the set-cookie header.
- }
-
std::string mHost;
};
@@ -1387,10 +1379,12 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom
LLSD LLViewerMedia::getHeaders()
{
LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "*/*";
- headers["Content-Type"] = "application/xml";
- headers["Cookie"] = sOpenIDCookie;
- headers["User-Agent"] = getCurrentUserAgent();
+ headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
+ // *TODO: Should this be 'application/llsd+xml' ?
+ // *TODO: Should this even be set at all? This header is only not overridden in 'GET' methods.
+ headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML;
+ headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie;
+ headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();
return headers;
}
@@ -1431,9 +1425,9 @@ void LLViewerMedia::setOpenIDCookie()
// Do a web profile get so we can store the cookie
LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "*/*";
- headers["Cookie"] = sOpenIDCookie;
- headers["User-Agent"] = getCurrentUserAgent();
+ headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
+ headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie;
+ headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();
std::string profile_url = getProfileURL("");
LLURL raw_profile_url( profile_url.c_str() );
@@ -1463,9 +1457,9 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string
LLSD headers = LLSD::emptyMap();
// Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header
- headers["Accept"] = "*/*";
+ headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
// and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream"
- headers["Content-Type"] = "application/x-www-form-urlencoded";
+ headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded";
// postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here.
size_t size = openid_token.size();
@@ -1537,7 +1531,7 @@ void LLViewerMedia::createSpareBrowserMediaSource()
// The null owner will keep the browser plugin from fully initializing
// (specifically, it keeps LLPluginClassMedia from negotiating a size change,
// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
- sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
+ sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType(HTTP_CONTENT_TEXT_HTML, NULL, 0, 0);
}
}
@@ -2633,16 +2627,16 @@ void LLViewerMediaImpl::navigateInternal()
// Accept: application/llsd+xml
// which is really not what we want.
LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "*/*";
+ headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
// Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com
- headers["Cookie"] = "";
+ headers[HTTP_OUT_HEADER_COOKIE] = "";
LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f);
}
else if("data" == scheme || "file" == scheme || "about" == scheme)
{
// FIXME: figure out how to really discover the type for these schemes
// We use "data" internally for a text/html url for loading the login screen
- if(initializeMedia("text/html"))
+ if(initializeMedia(HTTP_CONTENT_TEXT_HTML))
{
loadURI();
}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index e3335c9cd8..aecffb4ff5 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3970,6 +3970,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
@@ -4224,6 +4226,9 @@ void process_crossed_region(LLMessageSystem* msg, void**)
send_complete_agent_movement(sim_host);
LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
+
+ LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == "
+ << seedCap << LL_ENDL;
regionp->setSeedCapability(seedCap);
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 6f7b2f40e6..91efed1508 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5257,6 +5257,28 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive)
}
}
+BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const
+{
+ BOOL matches = FALSE;
+ if (mDrawable)
+ {
+ matches = mDrawable->isState(state);
+ }
+ if (recursive)
+ {
+ for (child_list_t::const_iterator iter = mChildList.begin();
+ (iter != mChildList.end()) && matches; iter++)
+ {
+ LLViewerObject* child = *iter;
+ matches &= child->isDrawableState(state, recursive);
+ }
+ }
+
+ return matches;
+}
+
+
+
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// RN: these functions assume a 2-level hierarchy
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index ea0d55cda5..0b92af4a93 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -410,6 +410,7 @@ public:
void setDrawableState(U32 state, BOOL recursive = TRUE);
void clearDrawableState(U32 state, BOOL recursive = TRUE);
+ BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const;
// Called when the drawable shifts
virtual void onShift(const LLVector4a &shift_vector) { }
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 66615657d8..a90694da7a 100755
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -670,6 +670,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
class LLObjectCostResponder : public LLCurl::Responder
{
+ LOG_CLASS(LLObjectCostResponder);
public:
LLObjectCostResponder(const LLSD& object_ids)
: mObjectIDs(object_ids)
@@ -690,20 +691,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,
@@ -759,6 +759,7 @@ private:
class LLPhysicsFlagsResponder : public LLCurl::Responder
{
+ LOG_CLASS(LLPhysicsFlagsResponder);
public:
LLPhysicsFlagsResponder(const LLSD& object_ids)
: mObjectIDs(object_ids)
@@ -779,20 +780,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 8422708add..7150089380 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -30,6 +30,7 @@
// linden libraries
#include "indra_constants.h"
+#include "llaisapi.h"
#include "llavatarnamecache.h" // name lookup cap url
#include "llfloaterreg.h"
#include "llmath.h"
@@ -75,6 +76,11 @@
#pragma warning(disable:4355)
#endif
+// When we receive a base grant of capabilities that has a different number of
+// capabilities than the original base grant received for the region, print
+// out the two lists of capabilities for analysis.
+//#define DEBUG_CAPS_GRANTS
+
const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region
const S16 MAX_MAP_DIST = 10;
// The server only keeps our pending agent info for 60 seconds.
@@ -87,6 +93,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)
@@ -143,7 +151,7 @@ public:
CapabilityMap mCapabilities;
CapabilityMap mSecondCapabilitiesTracker;
-
+
LLEventPoll* mEventPoll;
S32 mSeedCapMaxAttempts;
@@ -204,24 +212,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 +248,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 +277,6 @@ public:
}
}
- static BaseCapabilitiesComplete* build( U64 region_handle, S32 id )
- {
- return new BaseCapabilitiesComplete(region_handle, id);
- }
-
private:
U64 mRegionHandle;
S32 mID;
@@ -278,19 +293,32 @@ public:
virtual ~BaseCapabilitiesCompleteTracker()
{ }
- void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
+ static BaseCapabilitiesCompleteTracker* build( U64 region_handle )
+ {
+ return new BaseCapabilitiesCompleteTracker( region_handle );
+ }
+
+private:
+ /* virtual */ void httpFailure()
{
- llwarns << "BaseCapabilitiesCompleteTracker error [status:"
- << statusNum << "]: " << content << llendl;
+ llwarns << dumpResponse() << llendl;
}
- void result(const LLSD& content)
+ /* 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 +328,46 @@ 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;
+#ifdef DEBUG_CAPS_GRANTS
+ 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);
+
+#endif
+
+ 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;
};
@@ -1568,7 +1615,11 @@ void LLViewerRegion::unpackRegionHandshake()
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID("SessionID", gAgent.getSessionID());
msg->nextBlock("RegionInfo");
- msg->addU32("Flags", 0x0 );
+
+ U32 flags = 0;
+ flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE;
+
+ msg->addU32("Flags", flags );
msg->sendReliable(host);
}
@@ -1587,12 +1638,13 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("EventQueueGet");
if (gSavedSettings.getBOOL("UseHTTPInventory"))
- {
+ {
capabilityNames.append("FetchLib2");
capabilityNames.append("FetchLibDescendents2");
capabilityNames.append("FetchInventory2");
capabilityNames.append("FetchInventoryDescendents2");
capabilityNames.append("IncrementCOFVersion");
+ AISCommand::getCapabilityNames(capabilityNames);
}
capabilityNames.append("GetDisplayNames");
@@ -1606,7 +1658,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("LandResources");
capabilityNames.append("MapLayer");
capabilityNames.append("MapLayerGod");
- capabilityNames.append("MeshUploadFlag");
+ capabilityNames.append("MeshUploadFlag");
capabilityNames.append("NavMeshGenerationStatus");
capabilityNames.append("NewFileAgentInventory");
capabilityNames.append("ObjectMedia");
@@ -1617,7 +1669,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("ProductInfoRequest");
capabilityNames.append("ProvisionVoiceAccountRequest");
capabilityNames.append("RemoteParcelRequest");
- capabilityNames.append("RenderMaterials");
capabilityNames.append("RequestTextureDownload");
capabilityNames.append("ResourceCostSelected");
capabilityNames.append("RetrieveNavMeshSrc");
@@ -1647,7 +1698,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("ViewerMetrics");
capabilityNames.append("ViewerStartAuction");
capabilityNames.append("ViewerStats");
-
+
// Please add new capabilities alphabetically to reduce
// merge conflicts.
}
@@ -1655,8 +1706,10 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
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();
@@ -1729,31 +1782,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)
@@ -1763,7 +1822,7 @@ private:
LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
}
}
-
+
std::string mRetryURL;
U64 mRegionHandle;
S32 mAttempt;
@@ -1800,7 +1859,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)
@@ -1812,7 +1880,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
{
if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
{
- llwarns << "getCapability called before caps received" << llendl;
+ llwarns << "getCapability called before caps received for " << name << llendl;
}
CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
@@ -1824,6 +1892,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
return iter->second;
}
+bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const
+{
+ if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
+ {
+ llwarns << "isCapabilityAvailable called before caps received for " << name << llendl;
+ }
+
+ CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
+ if(iter == mImpl->mCapabilities.end())
+ {
+ return false;
+ }
+
+ return true;
+}
+
bool LLViewerRegion::capabilitiesReceived() const
{
return mCapabilitiesReceived;
@@ -1851,16 +1935,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)
@@ -1944,3 +2019,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/llviewerregion.h b/indra/newview/llviewerregion.h
index 56cd0c9ea1..6beaaf0e7b 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -49,6 +49,8 @@
#define WATER 2
const U32 MAX_OBJECT_CACHE_ENTRIES = 50000;
+// Region handshake flags
+const U32 REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE = 1U << 2;
class LLEventPoll;
class LLVLComposition;
@@ -242,6 +244,7 @@ public:
S32 getNumSeedCapRetries();
void setCapability(const std::string& name, const std::string& url);
void setCapabilityDebug(const std::string& name, const std::string& url);
+ bool isCapabilityAvailable(const std::string& name) const;
// implements LLCapabilityProvider
virtual std::string getCapability(const std::string& name) const;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 35bba4184e..68633fba6e 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -527,18 +527,19 @@ void update_statistics()
class ViewerStatsResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(ViewerStatsResponder);
public:
- ViewerStatsResponder() { }
+ ViewerStatsResponder() { }
- void error(U32 statusNum, const std::string& reason)
- {
- llinfos << "ViewerStatsResponder::error " << statusNum << " "
- << reason << llendl;
- }
+private:
+ /* virtual */ void httpFailure()
+ {
+ llwarns << dumpResponse() << llendl;
+ }
- void result(const LLSD& content)
- {
- llinfos << "ViewerStatsResponder::result" << llendl;
+ /* virtual */ void httpSuccess()
+ {
+ llinfos << "OK" << llendl;
}
};
@@ -733,44 +734,28 @@ void send_stats()
LLHTTPClient::post(url, body, new ViewerStatsResponder());
}
-LLFrameTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)
+LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name)
{
phase_map_t::iterator iter = mPhaseMap.find(phase_name);
if (iter == mPhaseMap.end())
{
- LLFrameTimer timer;
+ LLTimer timer;
mPhaseMap[phase_name] = timer;
}
- LLFrameTimer& timer = mPhaseMap[phase_name];
+ LLTimer& timer = mPhaseMap[phase_name];
return timer;
}
void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name)
{
- LLFrameTimer& timer = getPhaseTimer(phase_name);
- lldebugs << "startPhase " << phase_name << llendl;
- timer.unpause();
-}
-
-void LLViewerStats::PhaseMap::stopAllPhases()
-{
- for (phase_map_t::iterator iter = mPhaseMap.begin();
- iter != mPhaseMap.end(); ++iter)
- {
- const std::string& phase_name = iter->first;
- if (iter->second.getStarted())
- {
- // Going from started to paused state - record stats.
- recordPhaseStat(phase_name,iter->second.getElapsedTimeF32());
- }
- lldebugs << "stopPhase (all) " << phase_name << llendl;
- iter->second.pause();
- }
+ LLTimer& timer = getPhaseTimer(phase_name);
+ timer.start();
+ LL_DEBUGS("Avatar") << "startPhase " << phase_name << llendl;
}
void LLViewerStats::PhaseMap::clearPhases()
{
- lldebugs << "clearPhases" << llendl;
+ LL_DEBUGS("Avatar") << "clearPhases" << llendl;
mPhaseMap.clear();
}
@@ -795,7 +780,6 @@ LLViewerStats::PhaseMap::PhaseMap()
{
}
-
void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)
{
phase_map_t::iterator iter = mPhaseMap.find(phase_name);
@@ -808,6 +792,7 @@ void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)
}
}
}
+
// static
LLViewerStats::StatsAccumulator& LLViewerStats::PhaseMap::getPhaseStats(const std::string& phase_name)
{
@@ -831,14 +816,18 @@ void LLViewerStats::PhaseMap::recordPhaseStat(const std::string& phase_name, F32
bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed)
{
phase_map_t::iterator iter = mPhaseMap.find(phase_name);
+ bool found = false;
if (iter != mPhaseMap.end())
{
+ found = true;
elapsed = iter->second.getElapsedTimeF32();
completed = !iter->second.getStarted();
- return true;
+ LL_DEBUGS("Avatar") << " phase_name " << phase_name << " elapsed " << elapsed << " completed " << completed << " timer addr " << (S32)(&iter->second) << llendl;
}
else
{
- return false;
+ LL_DEBUGS("Avatar") << " phase_name " << phase_name << " NOT FOUND" << llendl;
}
+
+ return found;
}
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 6b2461be41..eaa0b6beff 100755
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -279,7 +279,7 @@ public:
// Phase tracking (originally put in for avatar rezzing), tracking
// progress of active/completed phases for activities like outfit changing.
- typedef std::map<std::string,LLFrameTimer> phase_map_t;
+ typedef std::map<std::string,LLTimer> phase_map_t;
typedef std::map<std::string,StatsAccumulator> phase_stats_t;
class PhaseMap
{
@@ -288,11 +288,10 @@ public:
static phase_stats_t sStats;
public:
PhaseMap();
- LLFrameTimer& getPhaseTimer(const std::string& phase_name);
+ LLTimer& getPhaseTimer(const std::string& phase_name);
bool getPhaseValues(const std::string& phase_name, F32& elapsed, bool& completed);
void startPhase(const std::string& phase_name);
void stopPhase(const std::string& phase_name);
- void stopAllPhases();
void clearPhases();
LLSD dumpPhases();
static StatsAccumulator& getPhaseStats(const std::string& phase_name);
diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp
index 777e1f9c76..777e1f9c76 100755..100644
--- a/indra/newview/llviewertexlayer.cpp
+++ b/indra/newview/llviewertexlayer.cpp
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 84f66c359f..7e35af7e63 100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -931,6 +931,27 @@ void LLViewerTexture::updateBindStatsForTester()
//end of LLViewerTexture
//----------------------------------------------------------------------------------------------
+const std::string& fttype_to_string(const FTType& fttype)
+{
+ static const std::string ftt_unknown("FTT_UNKNOWN");
+ static const std::string ftt_default("FTT_DEFAULT");
+ static const std::string ftt_server_bake("FTT_SERVER_BAKE");
+ static const std::string ftt_host_bake("FTT_HOST_BAKE");
+ static const std::string ftt_map_tile("FTT_MAP_TILE");
+ static const std::string ftt_local_file("FTT_LOCAL_FILE");
+ static const std::string ftt_error("FTT_ERROR");
+ switch(fttype)
+ {
+ case FTT_UNKNOWN: return ftt_unknown; break;
+ case FTT_DEFAULT: return ftt_default; break;
+ case FTT_SERVER_BAKE: return ftt_server_bake; break;
+ case FTT_HOST_BAKE: return ftt_host_bake; break;
+ case FTT_MAP_TILE: return ftt_map_tile; break;
+ case FTT_LOCAL_FILE: return ftt_local_file; break;
+ }
+ return ftt_error;
+}
+
//----------------------------------------------------------------------------------------------
//start of LLViewerFetchedTexture
//----------------------------------------------------------------------------------------------
@@ -1799,7 +1820,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)
@@ -1864,10 +1886,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;
}
@@ -2046,29 +2073,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 10101a4b9b..d9a537d304 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -34,7 +34,7 @@
#include "llgltypes.h"
#include "llrender.h"
#include "llmetricperformancetester.h"
-#include "llface.h"
+#include "httpcommon.h"
#include <map>
#include <list>
@@ -42,6 +42,7 @@
#define MIN_VIDEO_RAM_IN_MEGA_BYTES 32
#define MAX_VIDEO_RAM_IN_MEGA_BYTES 512 // 512MB max for performance reasons.
+class LLFace;
class LLImageGL ;
class LLImageRaw;
class LLViewerObject;
@@ -98,6 +99,7 @@ public:
DYNAMIC_TEXTURE,
FETCHED_TEXTURE,
LOD_TEXTURE,
+ ATLAS_TEXTURE,
INVALID_TEXTURE_TYPE
};
@@ -120,7 +122,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) ;
@@ -217,7 +219,8 @@ public:
static S32 sMaxSmallImageSize ;
static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
static F32 sCurrentTime ;
-
+ static BOOL sUseTextureAtlas ;
+
enum EDebugTexels
{
DEBUG_TEXELS_OFF,
@@ -244,6 +247,8 @@ enum FTType
FTT_LOCAL_FILE // fetch directly from a local file.
};
+const std::string& fttype_to_string(const FTType& fttype);
+
//
//textures are managed in gTextureList.
//raw image data is fetched from remote or local cache
@@ -340,8 +345,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
@@ -402,12 +407,17 @@ protected:
S32 getCurrentDiscardLevelForFetching() ;
private:
- void init(bool firstinit) ;
+ void init(bool firstinit) ;
void cleanup() ;
void saveRawImage() ;
void setCachedRawImage() ;
+ //for atlas
+ void resetFaceAtlas() ;
+ void invalidateAtlas(BOOL rebuild_geom) ;
+ BOOL insertToAtlas() ;
+
private:
BOOL mFullyLoaded;
BOOL mInDebug;
@@ -443,8 +453,9 @@ 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.
diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp
index e8425dc76a..76f94935b8 100644
--- a/indra/newview/llviewerwearable.cpp
+++ b/indra/newview/llviewerwearable.cpp
@@ -72,14 +72,16 @@ private:
static std::string asset_id_to_filename(const LLUUID &asset_id);
LLViewerWearable::LLViewerWearable(const LLTransactionID& transaction_id) :
- LLWearable()
+ LLWearable(),
+ mVolatile(FALSE)
{
mTransactionID = transaction_id;
mAssetID = mTransactionID.makeAssetID(gAgent.getSecureSessionID());
}
LLViewerWearable::LLViewerWearable(const LLAssetID& asset_id) :
- LLWearable()
+ LLWearable(),
+ mVolatile(FALSE)
{
mAssetID = asset_id;
mTransactionID.setNull();
diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h
index 65566f23a5..ef8c29323e 100644
--- a/indra/newview/llviewerwearable.h
+++ b/indra/newview/llviewerwearable.h
@@ -68,6 +68,8 @@ public:
void setParamsToDefaults();
void setTexturesToDefaults();
+ void setVolatile(BOOL is_volatile) { mVolatile = is_volatile; } // TRUE when doing preview renders, some updates will be suppressed.
+ BOOL getVolatile() { return mVolatile; }
/*virtual*/ LLUUID getDefaultTextureImageID(LLAvatarAppearanceDefines::ETextureIndex index) const;
@@ -96,6 +98,8 @@ protected:
LLAssetID mAssetID;
LLTransactionID mTransactionID;
+ BOOL mVolatile; // 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 40b8560071..f8e2a27f63 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1966,7 +1966,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)
@@ -1974,7 +1974,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 1a050800b4..0bd51d9c15 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -106,7 +106,7 @@ extern F32 SPEED_ADJUST_MAX;
extern F32 SPEED_ADJUST_MAX_SEC;
extern F32 ANIM_SPEED_MAX;
extern F32 ANIM_SPEED_MIN;
-
+extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG;
// #define OUTPUT_BREAST_DATA
@@ -802,17 +802,17 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c
//------------------------------------------------------------------------
LLVOAvatar::~LLVOAvatar()
{
- if (!mFullyLoaded)
- {
+ if (!mFullyLoaded)
+ {
debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud");
- }
- else
- {
+ }
+ else
+ {
debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding");
- }
+ }
logPendingPhases();
-
+
lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());
@@ -1196,7 +1196,7 @@ void LLVOAvatar::initInstance(void)
registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create );
registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create );
}
-
+
LLAvatarAppearance::initInstance();
// preload specific motions here
@@ -1234,6 +1234,7 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet()
const LLVector3 LLVOAvatar::getRenderPosition() const
{
+
if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
{
return getPositionAgent();
@@ -1256,6 +1257,8 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
{
return getPosition() * mDrawable->getParent()->getRenderMatrix();
}
+
+
}
void LLVOAvatar::updateDrawable(BOOL force_damped)
@@ -1291,6 +1294,8 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition();
mDrawable->setPositionGroup(pos_group);
}
+
+
}
void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
@@ -1543,7 +1548,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
return hit;
}
-
+
LLVOAvatar* LLVOAvatar::asAvatar()
{
return this;
@@ -1878,22 +1883,26 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
}
if (!result)
-{
+ {
const std::string url = getImageURL(te,uuid);
if (!url.empty())
- {
- LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl;
+ {
+ LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << llendl;
result = LLViewerTextureManager::getFetchedTextureFromUrl(
url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
- }
- else
- {
- LL_DEBUGS("Avatar") << avString() << "from host " << uuid << llendl;
+ if (result->isMissingAsset())
+ {
+ result->setIsMissingAsset(false);
+ }
+ }
+ else
+ {
+ LL_DEBUGS("Avatar") << avString() << "get old-bake image from host " << uuid << llendl;
LLHost host = getObjectHost();
result = LLViewerTextureManager::getFetchedTexture(
uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
+ }
}
-}
return result;
}
@@ -2145,7 +2154,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 )
@@ -2886,6 +2895,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);
@@ -2987,7 +2998,7 @@ bool LLVOAvatar::isVisuallyMuted() const
// called on both your avatar and other avatars
//------------------------------------------------------------------------
BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
-{
+{
// clear debug text
mDebugText.clear();
@@ -3502,6 +3513,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//mesh vertices need to be reskinned
mNeedsSkin = TRUE;
+
+
+
return TRUE;
}
//-----------------------------------------------------------------------------
@@ -3535,9 +3549,9 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,
{
mHasPelvisOffset = hasOffset;
if ( mHasPelvisOffset )
- {
+ {
//Store off last pelvis to foot value
- mLastPelvisToFoot = mPelvisToFoot;
+ mLastPelvisToFoot = mPelvisToFoot;
mPelvisOffset = offsetAmount;
mLastPelvisFixup = mPelvisFixup;
mPelvisFixup = pelvisFixup;
@@ -3547,18 +3561,16 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,
// postPelvisSetRecalc
//------------------------------------------------------------------------
void LLVOAvatar::postPelvisSetRecalc( void )
-{
- computeBodySize();
- mRoot->touch();
- mRoot->updateWorldMatrixChildren();
- dirtyMesh();
- updateHeadOffset();
+{
+ mRoot->updateWorldMatrixChildren();
+ computeBodySize();
+ dirtyMesh(2);
}
//------------------------------------------------------------------------
-// pelisPoke
+// setPelvisOffset
//------------------------------------------------------------------------
void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
-{
+{
mHasPelvisOffset = true;
mLastPelvisFixup = mPelvisFixup;
mPelvisFixup = pelvisFixupAmount;
@@ -3980,7 +3992,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
{
LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
if (hair_mesh)
- {
+ {
num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
}
first_pass = FALSE;
@@ -3990,7 +4002,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
}
}
-
+
return num_indices;
}
@@ -4409,7 +4421,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
@@ -4472,11 +4484,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);
@@ -4920,70 +4932,39 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )
return jointp;
}
-
-//-----------------------------------------------------------------------------
-// resetJointPositions
-//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointPositions( void )
-{
- avatar_joint_list_t::iterator iter = mSkeleton.begin();
- avatar_joint_list_t::iterator end = mSkeleton.end();
- for (; iter != end; ++iter)
- {
- (*iter)->restoreOldXform();
- (*iter)->setId( LLUUID::null );
- }
- mHasPelvisOffset = false;
- mPelvisFixup = mLastPelvisFixup;
-}
-//-----------------------------------------------------------------------------
-// resetSpecificJointPosition
-//-----------------------------------------------------------------------------
-void LLVOAvatar::resetSpecificJointPosition( const std::string& name )
-{
- LLJoint* pJoint = mRoot->findJoint( name );
-
- if ( pJoint && pJoint->doesJointNeedToBeReset() )
- {
- pJoint->restoreOldXform();
- pJoint->setId( LLUUID::null );
- //If we're reseting the pelvis position make sure not to apply offset
- if ( name == "mPelvis" )
- {
- mHasPelvisOffset = false;
- }
- }
- else
- {
- llinfos<<"Did not find "<< name.c_str()<<llendl;
- }
-}
//-----------------------------------------------------------------------------
// resetJointPositionsToDefault
//-----------------------------------------------------------------------------
void LLVOAvatar::resetJointPositionsToDefault( void )
-{
+{
//Subsequent joints are relative to pelvis
avatar_joint_list_t::iterator iter = mSkeleton.begin();
avatar_joint_list_t::iterator end = mSkeleton.end();
+
+ LLJoint* pJointPelvis = getJoint("mPelvis");
+
for (; iter != end; ++iter)
{
LLJoint* pJoint = (*iter);
- if ( pJoint->doesJointNeedToBeReset() )
+ //Reset joints except for pelvis
+ if ( pJoint && pJoint != pJointPelvis && pJoint->doesJointNeedToBeReset() )
+ {
+ pJoint->setId( LLUUID::null );
+ pJoint->restoreOldXform();
+ }
+ else
+ if ( pJoint && pJoint == pJointPelvis && pJoint->doesJointNeedToBeReset() )
{
pJoint->setId( LLUUID::null );
- //restore joints to default positions, however skip over the pelvis
- // *TODO: How does this pointer check skip over pelvis?
- if ( pJoint )
- {
- pJoint->restoreOldXform();
- }
- }
- }
+ pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) );
+ pJoint->setJointResetFlag( false );
+ }
+ }
+
//make sure we don't apply the joint offset
mHasPelvisOffset = false;
mPelvisFixup = mLastPelvisFixup;
- postPelvisSetRecalc();
+ postPelvisSetRecalc();
}
//-----------------------------------------------------------------------------
// getCharacterPosition()
@@ -5107,9 +5088,9 @@ BOOL LLVOAvatar::loadSkeletonNode ()
{
if (!LLAvatarAppearance::loadSkeletonNode())
{
- return FALSE;
- }
-
+ return FALSE;
+ }
+
// ATTACHMENTS
{
LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
@@ -5138,7 +5119,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()
{
attachment->setOriginalPosition(info->mPosition);
}
-
+
if (info->mHasRotation)
{
LLQuaternion rotation;
@@ -5208,7 +5189,6 @@ void LLVOAvatar::updateVisualParams()
dirtyMesh();
updateHeadOffset();
}
-
//-----------------------------------------------------------------------------
// isActive()
//-----------------------------------------------------------------------------
@@ -5547,6 +5527,7 @@ void LLVOAvatar::lazyAttach()
void LLVOAvatar::resetHUDAttachments()
{
+
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -5599,10 +5580,10 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
{
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );
if (pSkinData
- && pSkinData->mJointNames.size() > 20 // full rig
- && pSkinData->mAlternateBindMatrix.size() > 0)
- {
- LLVOAvatar::resetJointPositionsToDefault();
+ && pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig
+ && pSkinData->mAlternateBindMatrix.size() > 0 )
+ {
+ LLVOAvatar::resetJointPositionsToDefault();
//Need to handle the repositioning of the cam, updating rig data etc during outfit editing
//This handles the case where we detach a replacement rig.
if ( gAgentCamera.cameraCustomizeAvatar() )
@@ -5620,6 +5601,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
{
+
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -5628,7 +5610,9 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
+
cleanupAttachedMesh( viewer_object );
+
attachment->removeObject(viewer_object);
lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;
return TRUE;
@@ -5826,26 +5810,24 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
{
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second;
if (texture_dict->mWearableType == type)
- {
+ {
// Thus, you must check to see if the corresponding baked texture is defined.
// NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing
// this works for detecting a skirt (most important), but is ineffective at any piece of clothing that
// gets baked into a texture that always exists (upper or lower).
if (texture_dict->mIsUsedByBakedTexture)
- {
+ {
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex);
- }
+ }
return FALSE;
- }
+ }
}
return FALSE;
}
-
-
// virtual
void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )
{
@@ -5880,7 +5862,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL
{
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setColor( color );
}
}
@@ -5948,9 +5930,9 @@ void LLVOAvatar::updateRezzedStatusTimers()
{
// load level has decreased. start phase timers for higher load levels.
for (S32 i = rez_status+1; i <= mLastRezzedStatus; i++)
- {
+ {
startPhase("load_" + LLVOAvatar::rezStatusToString(i));
- }
+ }
}
else if (rez_status > mLastRezzedStatus)
{
@@ -5959,16 +5941,16 @@ void LLVOAvatar::updateRezzedStatusTimers()
{
stopPhase("load_" + LLVOAvatar::rezStatusToString(i));
stopPhase("first_load_" + LLVOAvatar::rezStatusToString(i), false);
- }
+ }
if (rez_status == 3)
- {
+ {
// "fully loaded", mark any pending appearance change complete.
selfStopPhase("update_appearance_from_cof");
selfStopPhase("wear_inventory_category", false);
selfStopPhase("process_initial_wearables_update", false);
}
}
-
+
mLastRezzedStatus = rez_status;
}
}
@@ -5980,9 +5962,12 @@ void LLVOAvatar::clearPhases()
void LLVOAvatar::startPhase(const std::string& phase_name)
{
- F32 elapsed;
- bool completed;
- if (getPhases().getPhaseValues(phase_name, elapsed, completed))
+ F32 elapsed = 0.0;
+ bool completed = false;
+ bool found = getPhases().getPhaseValues(phase_name, elapsed, completed);
+ //LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name
+ // << " found " << found << " elapsed " << elapsed << " completed " << completed << llendl;
+ if (found)
{
if (!completed)
{
@@ -5990,15 +5975,18 @@ void LLVOAvatar::startPhase(const std::string& phase_name)
return;
}
}
- LL_DEBUGS("Avatar") << "started phase " << phase_name << llendl;
+ LL_DEBUGS("Avatar") << avString() << " started phase " << phase_name << llendl;
getPhases().startPhase(phase_name);
}
void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
- {
- F32 elapsed;
- bool completed;
- if (getPhases().getPhaseValues(phase_name, elapsed, completed))
+{
+ F32 elapsed = 0.0;
+ bool completed = false;
+ bool found = getPhases().getPhaseValues(phase_name, elapsed, completed);
+ //LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name
+ // << " found " << found << " elapsed " << elapsed << " completed " << completed << llendl;
+ if (found)
{
if (!completed)
{
@@ -6027,7 +6015,7 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
void LLVOAvatar::logPendingPhases()
{
if (!isAgentAvatarValid())
- {
+ {
return;
}
@@ -6043,14 +6031,14 @@ void LLVOAvatar::logPendingPhases()
if (!completed)
{
logMetricsTimerRecord(phase_name, elapsed, completed);
- }
+ }
}
}
- }
+}
//static
void LLVOAvatar::logPendingPhasesAllAvatars()
- {
+{
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
iter != LLCharacter::sInstances.end(); ++iter)
{
@@ -6061,14 +6049,14 @@ void LLVOAvatar::logPendingPhasesAllAvatars()
}
inst->logPendingPhases();
}
- }
+}
void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed)
- {
+{
if (!isAgentAvatarValid())
- {
+ {
return;
- }
+ }
LLSD record;
record["timer_name"] = phase_name;
@@ -6077,15 +6065,15 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
record["completed"] = completed;
U32 grid_x(0), grid_y(0);
if (getRegion())
- {
+ {
record["central_bake_version"] = LLSD::Integer(getRegion()->getCentralBakeVersion());
grid_from_region_handle(getRegion()->getHandle(), &grid_x, &grid_y);
- }
+ }
record["grid_x"] = LLSD::Integer(grid_x);
record["grid_y"] = LLSD::Integer(grid_y);
record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
record["is_self"] = isSelf();
-
+
if (isAgentAvatarValid())
{
gAgentAvatarp->addMetricsTimerRecord(record);
@@ -6293,28 +6281,28 @@ void LLVOAvatar::updateMeshTextures()
use_lkg_baked_layer[i],
last_id_string.c_str());
}
-
+
for (U32 i=0; i < mBakedTextureDatas.size(); i++)
{
debugColorizeSubMeshes(i, LLColor4::white);
LLViewerTexLayerSet* layerset = getTexLayerSet(i);
if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() )
- {
+ {
LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID);
mBakedTextureDatas[i].mIsUsed = TRUE;
debugColorizeSubMeshes(i,LLColor4::red);
-
+
avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
for (; iter != end; ++iter)
- {
+ {
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setTexture( baked_img );
- }
+ }
}
}
else if (!isUsingLocalAppearance() && is_layer_baked[i])
@@ -6340,6 +6328,9 @@ void LLVOAvatar::updateMeshTextures()
}
baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ),
src_callback_list, paused );
+
+ // this could add paused texture callbacks
+ mLoadedCallbacksPaused |= paused;
}
}
else if (layerset && isUsingLocalAppearance())
@@ -6358,7 +6349,7 @@ void LLVOAvatar::updateMeshTextures()
if (mesh)
{
mesh->setLayerSet( layerset );
- }
+ }
}
}
else
@@ -6380,7 +6371,7 @@ void LLVOAvatar::updateMeshTextures()
{
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setColor( color );
mesh->setTexture( hair_img );
}
@@ -6468,18 +6459,17 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com
for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin();
iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter)
-{
+ {
const LLMaskedMorph* maskedMorph = (*iter);
LLPolyMorphTarget* morph_target = dynamic_cast<LLPolyMorphTarget*>(maskedMorph->mMorphTarget);
if (morph_target)
- {
+ {
morph_target->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert);
-}
+ }
}
}
-
// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise
BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index)
{
@@ -6690,6 +6680,9 @@ void LLVOAvatar::onFirstTEMessageReceived()
LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL;
image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ),
src_callback_list, paused );
+
+ // this could add paused texture callbacks
+ mLoadedCallbacksPaused |= paused;
}
}
@@ -6757,12 +6750,12 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)
LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
// param_location_name(vparam->getParamLocation()).c_str()
);
- }
-
+}
+
void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
const LLAppearanceMessageContents& contents)
- {
+{
std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");
const std::vector<F32>& params_for_dump = contents.mParamWeights;
const LLTEContents& tec = contents.mTEContents;
@@ -6772,9 +6765,9 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
outfile.open(fullpath, LL_APR_WB );
apr_file_t* file = outfile.getFileHandle();
if (!file)
- {
- return;
- }
+ {
+ return;
+ }
else
{
LL_DEBUGS("Avatar") << "dumping appearance message to " << fullpath << llendl;
@@ -6789,7 +6782,8 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
LLVisualParam* param = getFirstVisualParam();
for (S32 i = 0; i < params_for_dump.size(); i++)
{
- while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
+ (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
{
param = getNextVisualParam();
}
@@ -6808,7 +6802,7 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", i, uuid_str.c_str());
}
apr_file_printf(file, "</textures>\n");
- }
+}
void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& contents)
{
@@ -6825,7 +6819,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
// For future use:
//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);
}
-
+
// Parse visual params, if any.
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
@@ -6843,7 +6837,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
{
for( S32 i = 0; i < num_blocks; i++ )
{
- while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
+ (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
{
param = getNextVisualParam();
}
@@ -6864,7 +6859,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
}
}
- const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) +
+ getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
if (num_blocks != expected_tweakable_count)
{
LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
@@ -6931,7 +6927,7 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
{
LL_DEBUGS("Avatar") << "starts" << llendl;
-
+
bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";
if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages"))
@@ -7006,7 +7002,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
return;
}
- mLastUpdateReceivedCOFVersion = this_update_cof_version;
+ // No backsies zone - if we get here, the message should be valid and usable.
+ if (appearance_version > 0)
+ {
+ // Note:
+ // RequestAgentUpdateAppearanceResponder::onRequestRequested()
+ // assumes that cof version is only updated with server-bake
+ // appearance messages.
+ mLastUpdateReceivedCOFVersion = this_update_cof_version;
+ }
setIsUsingServerBakes(appearance_version > 0);
@@ -7019,9 +7023,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT
&& baked_index != BAKED_SKIRT)
{
+ LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << llendl;
setTEImage(mBakedTextureDatas[baked_index].mTextureIndex,
LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
}
+ else
+ {
+ LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using texture id "
+ << getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << llendl;
+ }
}
// runway - was
@@ -7047,32 +7057,38 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;
BOOL params_changed = FALSE;
BOOL interp_params = FALSE;
+ S32 params_changed_count = 0;
for( S32 i = 0; i < num_params; i++ )
{
LLVisualParam* param = contents.mParams[i];
F32 newWeight = contents.mParamWeights[i];
- if (is_first_appearance_message || (param->getWeight() != newWeight))
+ if (is_first_appearance_message || (param->getWeight() != newWeight))
+ {
+ params_changed = TRUE;
+ params_changed_count++;
+ if(is_first_appearance_message)
{
- params_changed = TRUE;
- if(is_first_appearance_message)
- {
- param->setWeight(newWeight, FALSE);
- }
- else
- {
- interp_params = TRUE;
- param->setAnimationTarget(newWeight, FALSE);
- }
+ //LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << llendl;
+ param->setWeight(newWeight, FALSE);
+ }
+ else
+ {
+ //LL_DEBUGS("Avatar") << std::setprecision(5) << " param target " << i << " " << param->getWeight() << " -> " << newWeight << llendl;
+ interp_params = TRUE;
+ param->setAnimationTarget(newWeight, FALSE);
}
+ }
}
- const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) +
+ getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
if (num_params != expected_tweakable_count)
{
LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
}
+ LL_DEBUGS("Avatar") << "Changed " << params_changed_count << " params" << llendl;
if (params_changed)
{
if (interp_params)
@@ -7122,7 +7138,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
updateMeshTextures();
-
//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");
}
@@ -7305,7 +7320,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;
@@ -7321,12 +7336,12 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
for (; iter != end; ++iter)
- {
+ {
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setTexture( image_baked );
- }
+ }
}
}
@@ -7350,7 +7365,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
{
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setColor( LLColor4::white );
}
}
@@ -7369,7 +7384,7 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,
file_num_type::iterator it = file_nums.find(prefix);
S32 num = 0;
if (it != file_nums.end())
-{
+ {
num = it->second;
}
file_nums[prefix] = num+1;
@@ -7378,6 +7393,15 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,
return outfilename;
}
+void dump_sequential_xml(const std::string outprefix, const LLSD& content)
+{
+ std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml");
+ std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
+ std::ofstream ofs(fullpath.c_str(), std::ios_base::out);
+ ofs << LLSDOStreamer<LLSDXMLFormatter>(content, LLSDFormatter::OPTIONS_PRETTY);
+ LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL;
+}
+
void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables )
{
std::string outprefix(prefix);
@@ -7386,10 +7410,6 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
outprefix = getFullname() + (isSelf()?"_s":"_o");
}
if (outprefix.empty())
-{
- outprefix = getFullname() + (isSelf()?"_s":"_o");
- }
- if (outprefix.empty())
{
outprefix = std::string("new_archetype");
}
@@ -7415,36 +7435,36 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
if (group_by_wearables)
{
for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
- {
- const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
- apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
+ {
+ const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
+ apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
- {
- LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
- if( (viewer_param->getWearableType() == type) &&
- (viewer_param->isTweakable() ) )
{
+ LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
+ if( (viewer_param->getWearableType() == type) &&
+ (viewer_param->isTweakable() ) )
+ {
dump_visual_param(file, viewer_param, viewer_param->getWeight());
+ }
}
- }
- for (U8 te = 0; te < TEX_NUM_INDICES; te++)
- {
- if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
+ for (U8 te = 0; te < TEX_NUM_INDICES; te++)
{
- // MULTIPLE_WEARABLES: extend to multiple wearables?
- LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
- if( te_image )
+ if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
{
- std::string uuid_str;
- te_image->getID().toString( uuid_str );
- apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
+ // MULTIPLE_WEARABLES: extend to multiple wearables?
+ LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
+ if( te_image )
+ {
+ std::string uuid_str;
+ te_image->getID().toString( uuid_str );
+ apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
+ }
}
}
}
}
- }
else
{
// Just dump all params sequentially.
@@ -7456,6 +7476,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
{
+ {
// MULTIPLE_WEARABLES: extend to multiple wearables?
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
if( te_image )
@@ -7467,6 +7488,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
}
}
+ }
apr_file_printf( file, "\t</archetype>\n" );
apr_file_printf( file, "\n</linden_genepool>\n" );
@@ -7588,14 +7610,14 @@ void LLVOAvatar::startAppearanceAnimation()
}
}
-// virtual
+//virtual
void LLVOAvatar::bodySizeChanged()
-{
+{
if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
{ // notify simulator of change in size
// but not if we are in the middle of updating appearance
gAgent.sendAgentSetAppearance();
-}
+ }
}
BOOL LLVOAvatar::isUsingServerBakes() const
@@ -7607,25 +7629,25 @@ BOOL LLVOAvatar::isUsingServerBakes() const
F32 wt = appearance_version_param->getWeight();
F32 expect_wt = mUseServerBakes ? 1.0 : 0.0;
if (!is_approx_equal(wt,expect_wt))
-{
+ {
llwarns << "wt " << wt << " differs from expected " << expect_wt << llendl;
}
#endif
return mUseServerBakes;
- }
-
+}
+
void LLVOAvatar::setIsUsingServerBakes(BOOL newval)
- {
+{
mUseServerBakes = newval;
LLVisualParam* appearance_version_param = getVisualParam(11000);
llassert(appearance_version_param);
appearance_version_param->setWeight(newval ? 1.0 : 0.0, false);
- }
+}
// virtual
void LLVOAvatar::removeMissingBakedTextures()
- {
+{
}
//virtual
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index b05eed344b..8d047045cb 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -199,9 +199,7 @@ public:
virtual LLJoint* getJoint(const std::string &name);
- void resetJointPositions( void );
void resetJointPositionsToDefault( void );
- void resetSpecificJointPosition( const std::string& name );
/*virtual*/ const LLUUID& getID() const;
/*virtual*/ void addDebugText(const std::string& text);
@@ -210,7 +208,7 @@ public:
/*virtual*/ F32 getPixelArea() const;
/*virtual*/ LLVector3d getPosGlobalFromAgent(const LLVector3 &position);
/*virtual*/ LLVector3 getPosAgentFromGlobal(const LLVector3d &position);
- virtual void updateVisualParams();
+ virtual void updateVisualParams();
/** Inherited
@@ -991,10 +989,11 @@ protected: // Shared with LLVOAvatarSelf
}; // LLVOAvatar
extern const F32 SELF_ADDITIONAL_PRI;
-extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL;
+extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL;
std::string get_sequential_numbered_file_name(const std::string& prefix,
const std::string& suffix);
+void dump_sequential_xml(const std::string outprefix, const LLSD& content);
void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);
#endif // LL_VOAVATAR_H
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 15628d5ab2..ac59aa0907 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -63,6 +63,7 @@
#include "llsdutil.h"
#include "llstartup.h"
#include "llsdserialize.h"
+#include "llversioninfo.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -234,6 +235,33 @@ void LLVOAvatarSelf::initInstance()
//doPeriodically(output_self_av_texture_diagnostics, 30.0);
doPeriodically(update_avatar_rez_metrics, 5.0);
doPeriodically(check_for_unsupported_baked_appearance, 120.0);
+ doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0);
+}
+
+bool LLVOAvatarSelf::checkStuckAppearance()
+{
+ const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0;
+ const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0;
+
+ if (gAgentWearables.isCOFChangeInProgress())
+ {
+ LL_DEBUGS("Avatar") << "checking for stuck appearance" << llendl;
+ F32 change_time = gAgentWearables.getCOFChangeTime();
+ LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << llendl;
+ S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns();
+ LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << llendl;
+ S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations();
+ LL_DEBUGS("Avatar") << "active copy operations " << active_copies << llendl;
+
+ if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) ||
+ (change_time > UNCONDITIONAL_UNSTICK_INTERVAL))
+ {
+ gAgentWearables.notifyLoadingFinished();
+ }
+ }
+
+ // Return false to continue running check periodically.
+ return LLApp::isExiting();
}
// virtual
@@ -602,7 +630,7 @@ LLVOAvatarSelf::~LLVOAvatarSelf()
** **
*********************************************************************************/
-//virtual
+// virtual
BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent)
{
// update screen joint size
@@ -644,11 +672,6 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)
}
return LLVOAvatar::getJoint(name);
}
-//virtual
-void LLVOAvatarSelf::resetJointPositions( void )
-{
- return LLVOAvatar::resetJointPositions();
-}
// virtual
BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake )
{
@@ -866,10 +889,10 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
updateMeshTextures();
if (getRegion() && !getRegion()->getCentralBakeVersion())
{
- requestLayerSetUploads();
+ requestLayerSetUploads();
+ }
}
}
-}
//virtual
void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
@@ -1310,7 +1333,7 @@ void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *sr
discard_level < local_tex_obj->getDiscard())
{
local_tex_obj->setDiscard(discard_level);
- requestLayerSetUpdate(index);
+ requestLayerSetUpdate(index);
if (isEditingAppearance())
{
LLVisualParamHint::requestHintUpdates();
@@ -1799,11 +1822,11 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te
{
requestLayerSetUpdate(type);
if (isEditingAppearance())
- {
- LLVisualParamHint::requestHintUpdates();
+ {
+ LLVisualParamHint::requestHintUpdates();
+ }
}
}
- }
else
{
tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type), NULL);
@@ -2241,6 +2264,7 @@ LLSD LLVOAvatarSelf::metricsData()
class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder
{
+ LOG_CLASS(ViewerAppearanceChangeMetricsResponder);
public:
ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,
volatile const S32 & live_sequence,
@@ -2251,32 +2275,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;
@@ -2357,12 +2374,29 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,
return result;
}
+// Valid characters for tsdb are alphanumeric, _-./. Others must be cleaned out.
+void sanitize_for_tsdb_tag(std::string& s)
+{
+ for (std::string::iterator it = s.begin(); it != s.end(); ++it)
+ {
+ if (std::isalnum(*it) || *it == '.' || *it == '_' || *it == '-' || *it == '/')
+ {
+ continue;
+ }
+ *it = '_';
+ }
+}
+
void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
{
- // gAgentAvatarp->stopAllPhases();
static volatile bool reporting_started(false);
static volatile S32 report_sequence(0);
+ std::string viewer_version_channel = LLVersionInfo::getChannel();
+ sanitize_for_tsdb_tag(viewer_version_channel);
+ std::string viewer_version_short = LLVersionInfo::getShortVersion();
+ std::string viewer_version_build = llformat("%d", LLVersionInfo::getBuild());
+
LLSD msg; // = metricsData();
msg["message"] = "ViewerAppearanceChangeMetrics";
msg["session_id"] = gAgentSessionID;
@@ -2371,6 +2405,9 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
msg["initial"] = !reporting_started;
msg["break"] = false;
msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32();
+ msg["viewer_version_channel"] = viewer_version_channel;
+ msg["viewer_version_short"] = viewer_version_short;
+ msg["viewer_version_build"] = viewer_version_build;
// Status of our own rezzing.
msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
@@ -2425,6 +2462,7 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder
{
+ LOG_CLASS(CheckAgentAppearanceServiceResponder);
public:
CheckAgentAppearanceServiceResponder()
{
@@ -2434,22 +2472,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
@@ -2580,25 +2620,25 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
//if (!covered_by_baked)
{
if (imagep->getID() != IMG_DEFAULT_AVATAR)
- {
+ {
imagep->setNoDelete();
if (imagep->getDiscardLevel() != 0)
- {
- F32 desired_pixels;
- desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
-
- imagep->setBoostLevel(getAvatarBoostLevel());
- imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
- imagep->resetTextureStats();
- imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
- imagep->addTextureStats( desired_pixels / texel_area_ratio );
- imagep->forceUpdateBindStats() ;
- if (imagep->getDiscardLevel() < 0)
{
- mHasGrey = TRUE; // for statistics gathering
+ F32 desired_pixels;
+ desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
+
+ imagep->setBoostLevel(getAvatarBoostLevel());
+ imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
+ imagep->resetTextureStats();
+ imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);
+ imagep->addTextureStats( desired_pixels / texel_area_ratio );
+ imagep->forceUpdateBindStats() ;
+ if (imagep->getDiscardLevel() < 0)
+ {
+ mHasGrey = TRUE; // for statistics gathering
+ }
}
}
- }
else
{
// texture asset is missing
@@ -2921,17 +2961,17 @@ void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index )
LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const
{
- /* switch(index)
- case TEX_HEAD_BAKED:
- case TEX_HEAD_BODYPAINT:
- return mHeadLayerSet; */
+ /* switch(index)
+ case TEX_HEAD_BAKED:
+ case TEX_HEAD_BODYPAINT:
+ return mHeadLayerSet; */
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index);
- if (texture_dict->mIsUsedByBakedTexture)
- {
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
+ if (texture_dict->mIsUsedByBakedTexture)
+ {
+ const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
return getLayerSet(baked_index);
- }
- return NULL;
+ }
+ return NULL;
}
LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const
@@ -2955,11 +2995,16 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)
{
if (isAgentAvatarValid())
{
+ if (!gAgentAvatarp->mEndCustomizeCallback.get())
+ {
+ gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy;
+ }
+
gAgentAvatarp->mIsEditingAppearance = true;
gAgentAvatarp->mUseLocalAppearance = true;
if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch)
-{
+ {
gAgentCamera.changeCameraToCustomizeAvatar();
}
@@ -2994,8 +3039,11 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)
gAgentCamera.changeCameraToDefault();
gAgentCamera.resetView();
}
-
- LLAppearanceMgr::instance().updateAppearanceFromCOF();
+
+ // Dereferencing the previous callback will cause
+ // updateAppearanceFromCOF to be called, whenever all refs
+ // have resolved.
+ gAgentAvatarp->mEndCustomizeCallback = NULL;
}
}
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 3b7b6bac64..3cbf2b5cf5 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -32,6 +32,7 @@
#include "llvoavatar.h"
struct LocalTextureData;
+class LLInventoryCallback;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -138,6 +139,7 @@ public:
public:
/*virtual*/ BOOL updateCharacter(LLAgent &agent);
/*virtual*/ void idleUpdateTractorBeam();
+ bool checkStuckAppearance();
//--------------------------------------------------------------------
// Loading state
@@ -341,6 +343,7 @@ private:
public:
static void onCustomizeStart(bool disable_camera_switch = false);
static void onCustomizeEnd(bool disable_camera_switch = false);
+ LLPointer<LLInventoryCallback> mEndCustomizeCallback;
//--------------------------------------------------------------------
// Visibility
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 cff3551607..d30fd5677d 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:
@@ -190,33 +196,34 @@ static bool sMuteListListener_listening = false;
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"];
@@ -2647,7 +2654,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;
@@ -3149,7 +3156,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;
@@ -3422,7 +3429,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;
@@ -5389,9 +5396,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta
{
switch(mAudioSession->mErrorStatusCode)
{
- case 404: // NOT_FOUND
+ case HTTP_NOT_FOUND: // NOT_FOUND
+ // *TODO: Should this be 503?
case 480: // TEMPORARILY_UNAVAILABLE
- case 408: // REQUEST_TIMEOUT
+ case HTTP_REQUEST_TIME_OUT: // REQUEST_TIMEOUT
// call failed because other user was not available
// treat this as an error case
status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e6385dceea..fab900cc74 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -83,7 +83,7 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30;
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
const F32 FORCE_CULL_AREA = 8.f;
const F32 MAX_LOD_DISTANCE = 24.f;
-
+U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 20;
BOOL gAnimateTextures = TRUE;
//extern BOOL gHideSelectedObjects;
@@ -4396,6 +4396,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
bool emissive = false;
+ //Determine if we've received skininfo that contains an
+ //alternate bind matrix - if it does then apply the translational component
+ //to the joints of the avatar.
+ bool pelvisGotSet = false;
+
{
LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST);
@@ -4477,18 +4482,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
is_rigged = true;
//get drawpool of avatar with rigged face
- LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
-
- //Determine if we've received skininfo that contains an
- //alternate bind matrix - if it does then apply the translational component
- //to the joints of the avatar.
- bool pelvisGotSet = false;
-
+ LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+
if ( pAvatarVO )
{
- LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+ LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
-
if ( pSkinData )
{
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
@@ -4496,43 +4495,42 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
const int jointCnt = pSkinData->mJointNames.size();
const F32 pelvisZOffset = pSkinData->mPelvisOffset;
- bool fullRig = (jointCnt>=20) ? true : false;
+ bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;
if ( fullRig )
- {
+ {
for ( int i=0; i<jointCnt; ++i )
{
std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
- //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
if ( pJoint && pJoint->getId() != currentId )
{
pJoint->setId( currentId );
const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
+
//Set the joint position
- pJoint->storeCurrentXform( jointPos );
+ pJoint->storeCurrentXform( jointPos );
+
//If joint is a pelvis then handle old/new pelvis to foot values
if ( lookingForJoint == "mPelvis" )
{
- pJoint->storeCurrentXform( jointPos );
if ( !pAvatarVO->hasPelvisOffset() )
{
pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
- //Trigger to rebuild viewer AV
pelvisGotSet = true;
}
}
- }
- }
+ }
+ }
}
}
}
}
- //If we've set the pelvis to a new position we need to also rebuild some information that the
- //viewer does at launch (e.g. body size etc.)
- if ( pelvisGotSet )
+
+ //Rebuild body data if we altered joints/pelvis
+ if ( pelvisGotSet && pAvatarVO )
{
pAvatarVO->postPelvisSetRecalc();
- }
+ }
if (pool)
{
@@ -4852,7 +4850,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
drawablep->clearState(LLDrawable::RIGGED);
}
+
}
+
+
+
+
+
+
+
+
}
group->mBufferUsage = useage;
diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp
index ef1a953f59..49b3c27ea0 100755
--- a/indra/newview/llwearablelist.cpp
+++ b/indra/newview/llwearablelist.cpp
@@ -81,6 +81,7 @@ void LLWearableList::getAsset(const LLAssetID& assetID, const std::string& weara
LLViewerWearable* instance = get_if_there(mList, assetID, (LLViewerWearable*)NULL );
if( instance )
{
+ LL_DEBUGS("Avatar") << "wearable " << assetID << " found in LLWearableList" << llendl;
asset_arrived_callback( instance, userdata );
}
else
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 7996f8a640..ebd96702a1 100755
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1080,6 +1080,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 ebd2799ebf..6b95a0cb61 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -10146,5 +10146,7 @@ Cannot create large prims that intersect other players. Please re-try when othe
name="okignore"
yestext="OK"/>
</notification>
-
+
+
+
</notifications>
diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp
new file mode 100755
index 0000000000..25e6de46d9
--- /dev/null
+++ b/indra/newview/tests/llhttpretrypolicy_test.cpp
@@ -0,0 +1,328 @@
+/**
+ * @file llhttpretrypolicy_test.cpp
+ * @brief Header tests to exercise the LLHTTPRetryPolicy classes.
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "../llviewerprecompiledheaders.h"
+#include "../llhttpretrypolicy.h"
+#include "lltut.h"
+
+namespace tut
+{
+struct TestData
+{
+};
+
+typedef test_group<TestData> RetryPolicyTestGroup;
+typedef RetryPolicyTestGroup::object RetryPolicyTestObject;
+RetryPolicyTestGroup retryPolicyTestGroup("retry_policy");
+
+template<> template<>
+void RetryPolicyTestObject::test<1>()
+{
+ LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0);
+ LLSD headers;
+ F32 wait_seconds;
+
+ // No retry until we've failed a try.
+ ensure("never retry 0", !never_retry.shouldRetry(wait_seconds));
+
+ // 0 retries max.
+ never_retry.onFailure(500,headers);
+ ensure("never retry 1", !never_retry.shouldRetry(wait_seconds));
+}
+
+template<> template<>
+void RetryPolicyTestObject::test<2>()
+{
+ LLSD headers;
+ F32 wait_seconds;
+
+ // Normally only retry on server error (5xx)
+ LLAdaptiveRetryPolicy noRetry404(1.0,2.0,3.0,10);
+ noRetry404.onFailure(404,headers);
+ ensure("no retry on 404", !noRetry404.shouldRetry(wait_seconds));
+
+ // Can retry on 4xx errors if enabled by flag.
+ bool do_retry_4xx = true;
+ LLAdaptiveRetryPolicy doRetry404(1.0,2.0,3.0,10,do_retry_4xx);
+ doRetry404.onFailure(404,headers);
+ ensure("do retry on 404", doRetry404.shouldRetry(wait_seconds));
+}
+
+template<> template<>
+void RetryPolicyTestObject::test<3>()
+{
+ // Should retry after 1.0, 2.0, 3.0, 3.0 seconds.
+ LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4);
+ LLSD headers;
+ F32 wait_seconds;
+ bool should_retry;
+ U32 frac_bits = 6;
+
+ // No retry until we've failed a try.
+ ensure("basic_retry 0", !basic_retry.shouldRetry(wait_seconds));
+
+ // Starting wait 1.0
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 1", should_retry);
+ ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits);
+
+ // Double wait to 2.0
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 2", should_retry);
+ ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits);
+
+ // Hit max wait of 3.0 (4.0 clamped to max 3)
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 3", should_retry);
+ ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits);
+
+ // At max wait, should stay at 3.0
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 4", should_retry);
+ ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits);
+
+ // Max retries, should fail now.
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 5", !should_retry);
+
+ // Max retries, should fail now.
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 5", !should_retry);
+
+ // After a success, should reset to the starting state.
+ basic_retry.onSuccess();
+
+ // No retry until we've failed a try.
+ ensure("basic_retry 6", !basic_retry.shouldRetry(wait_seconds));
+
+ // Starting wait 1.0
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 7", should_retry);
+ ensure_approximately_equals("basic_retry 7", wait_seconds, 1.0F, frac_bits);
+
+ // Double wait to 2.0
+ basic_retry.onFailure(500,headers);
+ should_retry = basic_retry.shouldRetry(wait_seconds);
+ ensure("basic_retry 8", should_retry);
+ ensure_approximately_equals("basic_retry 8", wait_seconds, 2.0F, frac_bits);
+}
+
+// Retries should stop as soon as a non-5xx error is received.
+template<> template<>
+void RetryPolicyTestObject::test<4>()
+{
+ // Should retry after 1.0, 2.0, 3.0, 3.0 seconds.
+ LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4);
+ LLSD headers;
+ F32 wait_seconds;
+ bool should_retry;
+ U32 frac_bits = 6;
+
+ // Starting wait 1.0
+ killer404.onFailure(500,headers);
+ should_retry = killer404.shouldRetry(wait_seconds);
+ ensure("killer404 1", should_retry);
+ ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits);
+
+ // Double wait to 2.0
+ killer404.onFailure(500,headers);
+ should_retry = killer404.shouldRetry(wait_seconds);
+ ensure("killer404 2", should_retry);
+ ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits);
+
+ // Should fail on non-5xx
+ killer404.onFailure(404,headers);
+ should_retry = killer404.shouldRetry(wait_seconds);
+ ensure("killer404 3", !should_retry);
+
+ // After a non-5xx, should keep failing.
+ killer404.onFailure(500,headers);
+ should_retry = killer404.shouldRetry(wait_seconds);
+ ensure("killer404 4", !should_retry);
+}
+
+// Test handling of "retry-after" header. If present, this header
+// value overrides the computed delay, but does not affect the
+// progression of delay values. For example, if the normal
+// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls
+// get a retry header of 33, the pattern would become 1,33,33,8...
+template<> template<>
+void RetryPolicyTestObject::test<5>()
+{
+ LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6);
+ LLSD headers_with_retry;
+ headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666";
+ LLSD headers_without_retry;
+ F32 wait_seconds;
+ bool should_retry;
+ U32 frac_bits = 6;
+
+ policy.onFailure(500,headers_without_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 1", should_retry);
+ ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits);
+
+ policy.onFailure(500,headers_without_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 2", should_retry);
+ ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits);
+
+ policy.onFailure(500,headers_with_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 3", should_retry);
+ // 4.0 overrides by header -> 666.0
+ ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits);
+
+ policy.onFailure(500,headers_with_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 4", should_retry);
+ // 8.0 overrides by header -> 666.0
+ ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits);
+
+ policy.onFailure(500,headers_without_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 5", should_retry);
+ ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits);
+
+ policy.onFailure(500,headers_without_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 6", should_retry);
+ ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits);
+
+ policy.onFailure(500,headers_with_retry);
+ should_retry = policy.shouldRetry(wait_seconds);
+ ensure("retry header 7", !should_retry);
+}
+
+// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait),
+// used by header parsing of the retry policy.
+template<> template<>
+void RetryPolicyTestObject::test<6>()
+{
+ F32 seconds_to_wait;
+ bool success;
+
+ std::string str1("0");
+ seconds_to_wait = F32_MAX;
+ success = getSecondsUntilRetryAfter(str1, seconds_to_wait);
+ ensure("parse 1", success);
+ ensure_equals("parse 1", seconds_to_wait, 0.0);
+
+ std::string str2("999.9");
+ seconds_to_wait = F32_MAX;
+ success = getSecondsUntilRetryAfter(str2, seconds_to_wait);
+ ensure("parse 2", success);
+ ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8);
+
+ time_t nowseconds;
+ time(&nowseconds);
+ std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123();
+ seconds_to_wait = F32_MAX;
+ success = getSecondsUntilRetryAfter(str3, seconds_to_wait);
+ std::cerr << " str3 [" << str3 << "]" << std::endl;
+ ensure("parse 3", success);
+ ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F);
+}
+
+// Test retry-after field in both llmessage and CoreHttp headers.
+template<> template<>
+void RetryPolicyTestObject::test<7>()
+{
+ std::cerr << "7 starts" << std::endl;
+
+ LLSD sd_headers;
+ time_t nowseconds;
+ time(&nowseconds);
+ LLAdaptiveRetryPolicy policy(17.0,644.0,3.0,5);
+ F32 seconds_to_wait;
+ bool should_retry;
+
+ // No retry until we've failed a try.
+ ensure("header 0", !policy.shouldRetry(seconds_to_wait));
+
+ // no retry header, use default.
+ policy.onFailure(500,LLSD());
+ should_retry = policy.shouldRetry(seconds_to_wait);
+ ensure("header 1", should_retry);
+ ensure_approximately_equals("header 1", seconds_to_wait, 17.0F, 6);
+
+ // retry header should override, give delay of 0
+ std::string date_string = LLDate((F64)(nowseconds+7)).asRFC1123();
+ sd_headers[HTTP_IN_HEADER_RETRY_AFTER] = date_string;
+ policy.onFailure(503,sd_headers);
+ should_retry = policy.shouldRetry(seconds_to_wait);
+ ensure("header 2", should_retry);
+ ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F);
+
+ LLCore::HttpResponse *response;
+ LLCore::HttpHeaders *headers;
+
+ response = new LLCore::HttpResponse();
+ headers = new LLCore::HttpHeaders();
+ response->setStatus(503);
+ response->setHeaders(headers);
+ headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600"));
+ policy.onFailure(response);
+ should_retry = policy.shouldRetry(seconds_to_wait);
+ ensure("header 3",should_retry);
+ ensure_approximately_equals("header 3", seconds_to_wait, 600.0F, 6);
+ response->release();
+
+ response = new LLCore::HttpResponse();
+ headers = new LLCore::HttpHeaders();
+ response->setStatus(503);
+ response->setHeaders(headers);
+ time(&nowseconds);
+ date_string = LLDate((F64)(nowseconds+77)).asRFC1123();
+ std::cerr << "date_string [" << date_string << "]" << std::endl;
+ headers->append(HTTP_IN_HEADER_RETRY_AFTER,date_string);
+ policy.onFailure(response);
+ should_retry = policy.shouldRetry(seconds_to_wait);
+ ensure("header 4",should_retry);
+ ensure_approximately_equals_range("header 4", seconds_to_wait, 77.0F, 2.0F);
+ response->release();
+
+ // Timeout should be clamped at max.
+ policy.onFailure(500,LLSD());
+ should_retry = policy.shouldRetry(seconds_to_wait);
+ ensure("header 5", should_retry);
+ ensure_approximately_equals("header 5", seconds_to_wait, 644.0F, 6);
+
+ // No more retries.
+ policy.onFailure(500,LLSD());
+ should_retry = policy.shouldRetry(seconds_to_wait);
+ ensure("header 6", !should_retry);
+}
+
+}
+
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index 3e55336f2d..6f57daf151 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"
@@ -129,7 +129,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)
@@ -137,8 +137,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 d6e06e5316..970b55c1c7 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -131,12 +131,13 @@ void LLUpdateChecker::Implementation::checkVersion(std::string const & urlBase,
}
}
-void LLUpdateChecker::Implementation::completed(U32 status,
- const std::string & reason,
- const LLSD & content)
+void LLUpdateChecker::Implementation::httpCompleted()
{
mInProgress = false;
-
+
+ S32 status = getStatus();
+ const LLSD& content = getContent();
+ const std::string& reason = getReason();
if(status != 200)
{
std::string server_error;
@@ -192,8 +193,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 4244007340..3163a6d53c 100755
--- a/indra/viewer_components/updater/llupdatechecker.h
+++ b/indra/viewer_components/updater/llupdatechecker.h
@@ -52,11 +52,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;