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
-rwxr-xr-x[-rw-r--r--]indra/llappearance/llavatarappearance.cpp28
-rwxr-xr-x[-rw-r--r--]indra/llappearance/llavatarappearance.h10
-rwxr-xr-x[-rw-r--r--]indra/llappearance/lldriverparam.cpp28
-rwxr-xr-x[-rw-r--r--]indra/llappearance/lldriverparam.h8
-rw-r--r--indra/llappearance/llpolymorph.cpp2
-rw-r--r--indra/llappearance/llpolyskeletaldistortion.cpp14
-rwxr-xr-x[-rw-r--r--]indra/llappearance/lltexglobalcolor.cpp4
-rwxr-xr-x[-rw-r--r--]indra/llappearance/lltexglobalcolor.h2
-rw-r--r--indra/llappearance/lltexlayer.cpp19
-rwxr-xr-x[-rw-r--r--]indra/llappearance/lltexlayerparams.cpp36
-rwxr-xr-x[-rw-r--r--]indra/llappearance/lltexlayerparams.h14
-rw-r--r--indra/llappearance/llviewervisualparam.cpp2
-rwxr-xr-x[-rw-r--r--]indra/llappearance/llwearable.cpp18
-rwxr-xr-x[-rw-r--r--]indra/llappearance/llwearable.h6
-rwxr-xr-x[-rw-r--r--]indra/llappearance/llwearabledata.cpp7
-rwxr-xr-xindra/llcharacter/llcharacter.cpp14
-rwxr-xr-xindra/llcharacter/llcharacter.h6
-rwxr-xr-xindra/llcharacter/lljoint.cpp42
-rwxr-xr-xindra/llcharacter/lljoint.h8
-rwxr-xr-xindra/llcharacter/llvisualparam.cpp18
-rwxr-xr-xindra/llcharacter/llvisualparam.h9
-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.cpp15
-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.hpp561
-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.txt22
-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.cpp367
-rwxr-xr-xindra/newview/llagent.h35
-rwxr-xr-xindra/newview/llagentwearables.cpp666
-rwxr-xr-xindra/newview/llagentwearables.h58
-rwxr-xr-xindra/newview/llagentwearablesfetch.cpp600
-rwxr-xr-xindra/newview/llagentwearablesfetch.h114
-rwxr-xr-xindra/newview/llaisapi.cpp866
-rwxr-xr-xindra/newview/llaisapi.h183
-rwxr-xr-xindra/newview/llappearancemgr.cpp1760
-rwxr-xr-xindra/newview/llappearancemgr.h97
-rwxr-xr-xindra/newview/llassetuploadqueue.cpp83
-rwxr-xr-xindra/newview/llassetuploadresponders.cpp128
-rwxr-xr-xindra/newview/llassetuploadresponders.h41
-rwxr-xr-xindra/newview/llbreastmotion.cpp3
-rwxr-xr-xindra/newview/llclassifiedstatsresponder.cpp13
-rwxr-xr-xindra/newview/llclassifiedstatsresponder.h8
-rwxr-xr-xindra/newview/llemote.cpp12
-rwxr-xr-xindra/newview/llestateinfomodel.cpp10
-rwxr-xr-xindra/newview/lleventpoll.cpp49
-rw-r--r--indra/newview/llfacebookconnect.cpp224
-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/llinventoryobserver.cpp84
-rwxr-xr-xindra/newview/llinventoryobserver.h38
-rwxr-xr-xindra/newview/lllocalbitmaps.cpp2
-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.cpp122
-rwxr-xr-xindra/newview/llpanelclassified.cpp10
-rwxr-xr-xindra/newview/llpaneleditwearable.cpp44
-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/llphysicsmotion.cpp8
-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/llscrollingpanelparam.cpp6
-rwxr-xr-xindra/newview/llscrollingpanelparambase.cpp2
-rwxr-xr-xindra/newview/llsidepanelappearance.cpp2
-rwxr-xr-xindra/newview/llspeakers.cpp13
-rwxr-xr-xindra/newview/llstartup.cpp69
-rw-r--r--indra/newview/lltexturefetch.cpp188
-rwxr-xr-xindra/newview/lltexturefetch.h9
-rwxr-xr-xindra/newview/lltextureview.cpp10
-rwxr-xr-xindra/newview/lltoolmorph.cpp22
-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
-rw-r--r--indra/newview/llviewerfoldertype.cpp6
-rwxr-xr-xindra/newview/llviewerinventory.cpp699
-rwxr-xr-xindra/newview/llviewerinventory.h82
-rwxr-xr-xindra/newview/llviewermedia.cpp120
-rwxr-xr-xindra/newview/llviewermenu.cpp1
-rwxr-xr-xindra/newview/llviewermessage.cpp9
-rwxr-xr-xindra/newview/llviewerobject.cpp24
-rwxr-xr-xindra/newview/llviewerobject.h1
-rwxr-xr-xindra/newview/llviewerobjectlist.cpp24
-rwxr-xr-xindra/newview/llviewerparcelmedia.cpp2
-rwxr-xr-xindra/newview/llviewerregion.cpp233
-rwxr-xr-xindra/newview/llviewerregion.h3
-rwxr-xr-xindra/newview/llviewerstats.cpp59
-rwxr-xr-xindra/newview/llviewerstats.h5
-rwxr-xr-xindra/newview/llviewertexlayer.cpp404
-rwxr-xr-x[-rw-r--r--]indra/newview/llviewertexlayer.h47
-rwxr-xr-xindra/newview/llviewertexture.cpp162
-rwxr-xr-xindra/newview/llviewertexture.h30
-rwxr-xr-x[-rw-r--r--]indra/newview/llviewerwearable.cpp50
-rwxr-xr-x[-rw-r--r--]indra/newview/llviewerwearable.h12
-rwxr-xr-xindra/newview/llviewerwindow.cpp4
-rwxr-xr-xindra/newview/llvoavatar.cpp595
-rwxr-xr-xindra/newview/llvoavatar.h23
-rwxr-xr-xindra/newview/llvoavatarself.cpp547
-rwxr-xr-xindra/newview/llvoavatarself.h31
-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
247 files changed, 9470 insertions, 8758 deletions
diff --git a/autobuild.xml b/autobuild.xml
index 8194b3d4eb..c213dc0d99 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>43826f8f0a5ce5bcdbfed9ea0b6f4ebb</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/283022/arch/Linux/installer/llappearanceutility_source-0.1-linux-20131025.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
diff --git a/build.sh b/build.sh
index 4875ef39f7..a0f9c730b0 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 e4b63dc7cb..e618a988b8 100755
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -42,6 +42,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..f10ae813fd 100644..100755
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -488,29 +488,9 @@ 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;
- bodySizeChanged();
}
}
@@ -1380,14 +1360,14 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
return TRUE;
}
-void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake )
+void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)
{
U32 param_name[3];
if( teToColorParams( te, param_name ) )
{
- setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake );
- setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake );
- setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake );
+ setVisualParamWeight( param_name[0], new_color.mV[VX]);
+ setVisualParamWeight( param_name[1], new_color.mV[VY]);
+ setVisualParamWeight( param_name[2], new_color.mV[VZ]);
}
}
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index bce2540258..1e898026c0 100644..100755
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -107,7 +107,6 @@ public:
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
virtual BOOL isValid() const;
- virtual BOOL isUsingServerBakes() const = 0;
virtual BOOL isUsingLocalAppearance() const = 0;
virtual BOOL isEditingAppearance() const = 0;
@@ -137,14 +136,13 @@ public:
typedef std::map<std::string, LLJoint*> joint_map_t;
joint_map_t mJointMap;
- void computeBodySize();
+ void computeBodySize();
protected:
static BOOL parseSkeletonFile(const std::string& filename);
virtual void buildCharacter();
virtual BOOL loadAvatar();
- virtual void bodySizeChanged() = 0;
BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
BOOL allocateCharacterJoints(U32 num);
@@ -225,7 +223,7 @@ public:
// Composites
//--------------------------------------------------------------------
public:
- virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0;
+ virtual void invalidateComposite(LLTexLayerSet* layerset) = 0;
/********************************************************************************
** **
@@ -256,7 +254,7 @@ protected:
// Clothing colors (convenience functions to access visual parameters)
//--------------------------------------------------------------------
public:
- void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake);
+ void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
@@ -265,7 +263,7 @@ public:
//--------------------------------------------------------------------
public:
LLColor4 getGlobalColor(const std::string& color_name ) const;
- virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0;
+ virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
protected:
LLTexGlobalColor* mTexSkinColor;
LLTexGlobalColor* mTexHairColor;
diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp
index 1f7e8b8652..83dbcfd6bf 100644..100755
--- a/indra/llappearance/lldriverparam.cpp
+++ b/indra/llappearance/lldriverparam.cpp
@@ -178,7 +178,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
mID = info->mID;
info->mDriverParam = this;
- setWeight(getDefaultWeight(), FALSE );
+ setWeight(getDefaultWeight());
return TRUE;
}
@@ -195,7 +195,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
return new_param;
}
-void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
+void LLDriverParam::setWeight(F32 weight)
{
F32 min_weight = getMinWeight();
F32 max_weight = getMaxWeight();
@@ -254,7 +254,7 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
driven_weight = driven_min;
}
- setDrivenWeight(driven,driven_weight,upload_bake);
+ setDrivenWeight(driven,driven_weight);
continue;
}
else
@@ -278,13 +278,13 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
driven_weight = driven_min;
}
- setDrivenWeight(driven,driven_weight,upload_bake);
+ setDrivenWeight(driven,driven_weight);
continue;
}
}
driven_weight = getDrivenWeight(driven, mCurWeight);
- setDrivenWeight(driven,driven_weight,upload_bake);
+ setDrivenWeight(driven,driven_weight);
}
}
@@ -430,9 +430,9 @@ const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
//-----------------------------------------------------------------------------
// setAnimationTarget()
//-----------------------------------------------------------------------------
-void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
+void LLDriverParam::setAnimationTarget( F32 target_value)
{
- LLVisualParam::setAnimationTarget(target_value, upload_bake);
+ LLVisualParam::setAnimationTarget(target_value);
for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
{
@@ -441,16 +441,16 @@ void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
// this isn't normally necessary, as driver params handle interpolation of their driven params
// but texture params need to know to assume their final value at beginning of interpolation
- driven->mParam->setAnimationTarget(driven_weight, upload_bake);
+ driven->mParam->setAnimationTarget(driven_weight);
}
}
//-----------------------------------------------------------------------------
// stopAnimating()
//-----------------------------------------------------------------------------
-void LLDriverParam::stopAnimating(BOOL upload_bake)
+void LLDriverParam::stopAnimating()
{
- LLVisualParam::stopAnimating(upload_bake);
+ LLVisualParam::stopAnimating();
for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
{
@@ -530,7 +530,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
if (wearable)
{
- wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
+ wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
}
}
}
@@ -593,7 +593,7 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight
return driven_weight;
}
-void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
+void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
{
bool use_self = false;
if(mWearablep &&
@@ -610,10 +610,10 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bo
if (use_self)
{
// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
- mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake );
+ mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
}
else
{
- driven->mParam->setWeight( driven_weight, upload_bake );
+ driven->mParam->setWeight( driven_weight);
}
}
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index 040c9cf5be..5a45c8f30d 100644..100755
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -110,9 +110,9 @@ public:
// LLVisualParam Virtual functions
/*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param.
- /*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
- /*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake );
- /*virtual*/ void stopAnimating(BOOL upload_bake);
+ /*virtual*/ void setWeight(F32 weight);
+ /*virtual*/ void setAnimationTarget( F32 target_value);
+ /*virtual*/ void stopAnimating();
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
/*virtual*/ void resetDrivenParams();
@@ -129,7 +129,7 @@ public:
protected:
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
- void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
+ void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index 93c2f15a53..84df3f1830 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -342,7 +342,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
return FALSE;
mInfo = info;
mID = info->mID;
- setWeight(getDefaultWeight(), FALSE );
+ setWeight(getDefaultWeight());
LLAvatarAppearance* avatarp = mMesh->getAvatar();
LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index 4ba16691c2..2a5866afe4 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -130,7 +130,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
return FALSE;
mInfo = info;
mID = info->mID;
- setWeight(getDefaultWeight(), FALSE );
+ setWeight(getDefaultWeight());
LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
@@ -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/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp
index f38b982104..432e2e9f49 100644..100755
--- a/indra/llappearance/lltexglobalcolor.cpp
+++ b/indra/llappearance/lltexglobalcolor.cpp
@@ -103,9 +103,9 @@ LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color)
return new_param;
}
-void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake)
+void LLTexParamGlobalColor::onGlobalColorChanged()
{
- mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake);
+ mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
}
//-----------------------------------------------------------------------------
diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h
index 2867479876..1b0c91b5ca 100644..100755
--- a/indra/llappearance/lltexglobalcolor.h
+++ b/indra/llappearance/lltexglobalcolor.h
@@ -75,7 +75,7 @@ public:
LLTexParamGlobalColor(LLTexGlobalColor *tex_color);
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
protected:
- /*virtual*/ void onGlobalColorChanged(bool upload_bake);
+ /*virtual*/ void onGlobalColorChanged();
private:
LLTexGlobalColor* mTexGlobalColor;
};
diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index a3a8616864..37d9c36918 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -1553,10 +1553,13 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
}
U32 cache_index = alpha_mask_crc.getCRC();
- U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL);
- if (!alpha_data)
+ U8* alpha_data = NULL;
+ // We believe we need to generate morph masks, do not assume that the cached version is accurate.
+ // We can get bad morph masks during login, on minimize, and occasional gl errors.
+ // We should only be doing this when we believe something has changed with respect to the user's appearance.
{
- // clear out a slot if we have filled our cache
+ LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << llendl;
+ // clear out a slot if we have filled our cache
S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;
while ((S32)mAlphaCache.size() >= max_cache_entries)
{
@@ -1776,13 +1779,11 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height)
{
U32 num_wearables = updateWearableCache();
- for (U32 i = 0; i < num_wearables; i++)
+ U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
{
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- layer->addAlphaMask(data, originX, originY, width, height);
- }
+ layer->addAlphaMask(data, originX, originY, width, height);
}
}
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp
index 6aae9a8cc1..9608e2d391 100644..100755
--- a/indra/llappearance/lltexlayerparams.cpp
+++ b/indra/llappearance/lltexlayerparams.cpp
@@ -160,7 +160,7 @@ BOOL LLTexLayerParamAlpha::getMultiplyBlend() const
return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend;
}
-void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
+void LLTexLayerParamAlpha::setWeight(F32 weight)
{
if (mIsAnimating || mTexLayer == NULL)
{
@@ -178,35 +178,35 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
if ((mAvatarAppearance->getSex() & getSex()) &&
(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
{
- mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
+ mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
mTexLayer->invalidateMorphMasks();
}
}
}
-void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake)
+void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
{
// do not animate dummy parameters
if (mIsDummy)
{
- setWeight(target_value, upload_bake);
+ setWeight(target_value);
return;
}
mTargetWeight = target_value;
- setWeight(target_value, upload_bake);
+ setWeight(target_value);
mIsAnimating = TRUE;
if (mNext)
{
- mNext->setAnimationTarget(target_value, upload_bake);
+ mNext->setAnimationTarget(target_value);
}
}
-void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake)
+void LLTexLayerParamAlpha::animate(F32 delta)
{
if (mNext)
{
- mNext->animate(delta, upload_bake);
+ mNext->animate(delta);
}
}
@@ -449,14 +449,14 @@ LLColor4 LLTexLayerParamColor::getNetColor() const
}
}
-void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
+
+void LLTexLayerParamColor::setWeight(F32 weight)
{
if (mIsAnimating)
{
return;
}
- const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
F32 min_weight = getMinWeight();
F32 max_weight = getMaxWeight();
F32 new_weight = llclamp(weight, min_weight, max_weight);
@@ -466,6 +466,8 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
{
mCurWeight = new_weight;
+ const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
+
if (info->mNumColors <= 0)
{
// This will happen when we set the default weight the first time.
@@ -474,10 +476,10 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
{
- onGlobalColorChanged(upload_bake);
+ onGlobalColorChanged();
if (mTexLayer)
{
- mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
+ mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
}
}
@@ -485,23 +487,23 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
}
}
-void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake)
+void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
{
// set value first then set interpolating flag to ignore further updates
mTargetWeight = target_value;
- setWeight(target_value, upload_bake);
+ setWeight(target_value);
mIsAnimating = TRUE;
if (mNext)
{
- mNext->setAnimationTarget(target_value, upload_bake);
+ mNext->setAnimationTarget(target_value);
}
}
-void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake)
+void LLTexLayerParamColor::animate(F32 delta)
{
if (mNext)
{
- mNext->animate(delta, upload_bake);
+ mNext->animate(delta);
}
}
diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h
index b38d28d3eb..e1a8c28265 100644..100755
--- a/indra/llappearance/lltexlayerparams.h
+++ b/indra/llappearance/lltexlayerparams.h
@@ -83,9 +83,9 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex avatar_sex ) {}
- /*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
- /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
- /*virtual*/ void animate(F32 delta, BOOL upload_bake);
+ /*virtual*/ void setWeight(F32 weight);
+ /*virtual*/ void setAnimationTarget(F32 target_value);
+ /*virtual*/ void animate(F32 delta);
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
@@ -174,9 +174,9 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex avatar_sex ) {}
- /*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
- /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
- /*virtual*/ void animate(F32 delta, BOOL upload_bake);
+ /*virtual*/ void setWeight(F32 weight);
+ /*virtual*/ void setAnimationTarget(F32 target_value);
+ /*virtual*/ void animate(F32 delta);
// LLViewerVisualParam Virtual functions
@@ -190,7 +190,7 @@ public:
// New functions
LLColor4 getNetColor() const;
protected:
- virtual void onGlobalColorChanged(bool upload_bake) {}
+ virtual void onGlobalColorChanged() {}
private:
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
} LL_ALIGN_POSTFIX(16);
diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp
index cc81bcf118..0d8d1dbeca 100644
--- a/indra/llappearance/llviewervisualparam.cpp
+++ b/indra/llappearance/llviewervisualparam.cpp
@@ -137,7 +137,7 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
return FALSE;
mInfo = info;
mID = info->mID;
- setWeight(getDefaultWeight(), FALSE );
+ setWeight(getDefaultWeight());
return TRUE;
}
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index d86a460511..525a782ba0 100644..100755
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -524,7 +524,7 @@ void LLWearable::revertValues()
LLVisualParam *param = getVisualParam(id);
if(param && !dynamic_cast<LLDriverParam*>(param) )
{
- setVisualParamWeight(id, value, TRUE);
+ setVisualParamWeight(id, value);
}
}
@@ -536,7 +536,7 @@ void LLWearable::revertValues()
LLVisualParam *param = getVisualParam(id);
if(param && dynamic_cast<LLDriverParam*>(param) )
{
- setVisualParamWeight(id, value, TRUE);
+ setVisualParamWeight(id, value);
}
}
@@ -646,12 +646,12 @@ void LLWearable::addVisualParam(LLVisualParam *param)
}
-void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake)
+void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
{
if( is_in_map(mVisualParamIndexMap, param_index ) )
{
LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
- wearable_param->setWeight(value, upload_bake);
+ wearable_param->setWeight(value);
}
else
{
@@ -692,14 +692,14 @@ void LLWearable::getVisualParams(visual_param_vec_t &list)
}
}
-void LLWearable::animateParams(F32 delta, BOOL upload_bake)
+void LLWearable::animateParams(F32 delta)
{
for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin();
iter != mVisualParamIndexMap.end();
++iter)
{
LLVisualParam *param = (LLVisualParam*) iter->second;
- param->animate(delta, upload_bake);
+ param->animate(delta);
}
}
@@ -717,14 +717,14 @@ LLColor4 LLWearable::getClothesColor(S32 te) const
return color;
}
-void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake )
+void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
{
U32 param_name[3];
if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
{
for( U8 index = 0; index < 3; index++ )
{
- setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake);
+ setVisualParamWeight(param_name[index], new_color.mV[index]);
}
}
}
@@ -743,7 +743,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
S32 param_id = param->getID();
F32 weight = getVisualParamWeight(param_id);
- avatarp->setVisualParamWeight( param_id, weight, FALSE );
+ avatarp->setVisualParamWeight( param_id, weight);
}
}
}
diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h
index 6f5a1e14e8..84509a60fd 100644..100755
--- a/indra/llappearance/llwearable.h
+++ b/indra/llappearance/llwearable.h
@@ -95,14 +95,14 @@ public:
void setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
void addVisualParam(LLVisualParam *param);
- void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake);
+ void setVisualParamWeight(S32 index, F32 value);
F32 getVisualParamWeight(S32 index) const;
LLVisualParam* getVisualParam(S32 index) const;
void getVisualParams(visual_param_vec_t &list);
- void animateParams(F32 delta, BOOL upload_bake);
+ void animateParams(F32 delta);
LLColor4 getClothesColor(S32 te) const;
- void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake );
+ void setClothesColor( S32 te, const LLColor4& new_color);
virtual void revertValues();
virtual void saveValues();
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
index 68fdcca782..d70bbf286a 100644..100755
--- a/indra/llappearance/llwearabledata.cpp
+++ b/indra/llappearance/llwearabledata.cpp
@@ -119,13 +119,6 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type,
void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed)
{
wearable->setUpdated();
- // FIXME DRANO avoid updating params via wearables when rendering server-baked appearance.
-#if 0
- if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance())
- {
- return;
- }
-#endif
if (!removed)
{
pullCrossWearableValues(wearable->getType());
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 85cf1cd3f5..2aebbc9274 100755
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -286,13 +286,13 @@ void LLCharacter::removeAnimationData(std::string name)
//-----------------------------------------------------------------------------
// setVisualParamWeight()
//-----------------------------------------------------------------------------
-BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, BOOL upload_bake)
+BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight)
{
S32 index = which_param->getID();
visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
if (index_iter != mVisualParamIndexMap.end())
{
- index_iter->second->setWeight(weight, upload_bake);
+ index_iter->second->setWeight(weight);
return TRUE;
}
return FALSE;
@@ -301,7 +301,7 @@ BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 wei
//-----------------------------------------------------------------------------
// setVisualParamWeight()
//-----------------------------------------------------------------------------
-BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake)
+BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
{
std::string tname(param_name);
LLStringUtil::toLower(tname);
@@ -309,7 +309,7 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL
visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
if (name_iter != mVisualParamNameMap.end())
{
- name_iter->second->setWeight(weight, upload_bake);
+ name_iter->second->setWeight(weight);
return TRUE;
}
llwarns << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << llendl;
@@ -319,12 +319,12 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL
//-----------------------------------------------------------------------------
// setVisualParamWeight()
//-----------------------------------------------------------------------------
-BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake)
+BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight)
{
visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
if (index_iter != mVisualParamIndexMap.end())
{
- index_iter->second->setWeight(weight, upload_bake);
+ index_iter->second->setWeight(weight);
return TRUE;
}
llwarns << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << llendl;
@@ -394,7 +394,7 @@ void LLCharacter::clearVisualParamWeights()
{
if (param->isTweakable())
{
- param->setWeight( param->getDefaultWeight(), FALSE );
+ param->setWeight( param->getDefaultWeight());
}
}
}
diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h
index 5740dbce77..ebc5d80a1f 100755
--- a/indra/llcharacter/llcharacter.h
+++ b/indra/llcharacter/llcharacter.h
@@ -190,9 +190,9 @@ public:
void addVisualParam(LLVisualParam *param);
void addSharedVisualParam(LLVisualParam *param);
- virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE );
- virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE );
- virtual BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE );
+ virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight);
+ virtual BOOL setVisualParamWeight(const char* param_name, F32 weight);
+ virtual BOOL setVisualParamWeight(S32 index, F32 weight);
// get visual param weight by param or name
F32 getVisualParamWeight(LLVisualParam *distortion);
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.cpp b/indra/llcharacter/llvisualparam.cpp
index f7cb0f76b7..624e16e2ca 100755
--- a/indra/llcharacter/llvisualparam.cpp
+++ b/indra/llcharacter/llvisualparam.cpp
@@ -220,7 +220,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node)
//-----------------------------------------------------------------------------
// setWeight()
//-----------------------------------------------------------------------------
-void LLVisualParam::setWeight(F32 weight, BOOL upload_bake)
+void LLVisualParam::setWeight(F32 weight)
{
if (mIsAnimating)
{
@@ -238,19 +238,19 @@ void LLVisualParam::setWeight(F32 weight, BOOL upload_bake)
if (mNext)
{
- mNext->setWeight(weight, upload_bake);
+ mNext->setWeight(weight);
}
}
//-----------------------------------------------------------------------------
// setAnimationTarget()
//-----------------------------------------------------------------------------
-void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)
+void LLVisualParam::setAnimationTarget(F32 target_value)
{
// don't animate dummy parameters
if (mIsDummy)
{
- setWeight(target_value, upload_bake);
+ setWeight(target_value);
mTargetWeight = mCurWeight;
return;
}
@@ -270,7 +270,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)
if (mNext)
{
- mNext->setAnimationTarget(target_value, upload_bake);
+ mNext->setAnimationTarget(target_value);
}
}
@@ -287,24 +287,24 @@ void LLVisualParam::setNextParam( LLVisualParam *next )
//-----------------------------------------------------------------------------
// animate()
//-----------------------------------------------------------------------------
-void LLVisualParam::animate( F32 delta, BOOL upload_bake )
+void LLVisualParam::animate( F32 delta)
{
if (mIsAnimating)
{
F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight;
- setWeight(new_weight, upload_bake);
+ setWeight(new_weight);
}
}
//-----------------------------------------------------------------------------
// stopAnimating()
//-----------------------------------------------------------------------------
-void LLVisualParam::stopAnimating(BOOL upload_bake)
+void LLVisualParam::stopAnimating()
{
if (mIsAnimating && isTweakable())
{
mIsAnimating = FALSE;
- setWeight(mTargetWeight, upload_bake);
+ setWeight(mTargetWeight);
}
}
diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h
index 60ea7a369a..6c3bf2901a 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
};
@@ -119,10 +120,10 @@ public:
//virtual BOOL parseData( LLXmlTreeNode *node ) = 0;
virtual void apply( ESex avatar_sex ) = 0;
// Default functions
- virtual void setWeight(F32 weight, BOOL upload_bake);
- virtual void setAnimationTarget( F32 target_value, BOOL upload_bake );
- virtual void animate(F32 delta, BOOL upload_bake);
- virtual void stopAnimating(BOOL upload_bake);
+ virtual void setWeight(F32 weight);
+ virtual void setAnimationTarget( F32 target_value);
+ virtual void animate(F32 delta);
+ virtual void stopAnimating();
virtual BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
virtual void resetDrivenParams();
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 8eb0c6249d..66995d8083 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -178,7 +178,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 207ed8e1e4..d8057364c4 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -44,7 +44,7 @@
#include "_httplibcurl.h"
#include "_httpinternal.h"
-#include "llhttpstatuscodes.h"
+#include "llhttpconstants.h"
#include "llproxy.h"
namespace
@@ -454,6 +454,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");
}
@@ -584,7 +585,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
@@ -595,8 +597,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
@@ -611,18 +614,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 900a699887..0f0876b467 100755
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -69,6 +69,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
@@ -118,11 +120,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;
@@ -138,11 +146,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";
@@ -168,8 +179,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;
@@ -1344,7 +1355,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,
@@ -1711,18 +1724,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/",
@@ -1744,23 +1793,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/",
@@ -1901,20 +1987,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/",
@@ -2061,20 +2190,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/",
@@ -2215,27 +2388,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/",
@@ -2368,10 +2587,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>");
@@ -2380,23 +2599,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/",
@@ -2538,9 +2810,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>");
@@ -2549,22 +2821,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 081f070866..e8c508dcbf 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"
@@ -100,7 +101,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;
}
}
@@ -110,7 +111,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;
}
}
@@ -135,6 +136,7 @@ std::string LLCurl::getVersionString()
//////////////////////////////////////////////////////////////////////////////
LLCurl::Responder::Responder()
+ : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)
{
}
@@ -144,22 +146,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()
{
}
@@ -168,44 +178,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;
@@ -289,7 +364,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;
}
@@ -314,10 +390,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;
@@ -381,9 +461,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)
@@ -393,14 +473,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;
}
@@ -437,9 +518,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)
@@ -527,8 +630,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)
@@ -807,7 +911,7 @@ S32 LLCurl::Multi::process()
++processed;
if (msg->msg == CURLMSG_DONE)
{
- U32 response = 0;
+ S32 response = 0;
Easy* easy = NULL ;
{
@@ -826,7 +930,7 @@ S32 LLCurl::Multi::process()
}
else
{
- response = 499;
+ response = HTTP_INTERNAL_ERROR;
//*TODO: change to llwarns
llerrs << "cleaned up curl request completed!" << llendl;
}
@@ -1125,13 +1229,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);
@@ -1158,7 +1262,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;
@@ -1186,7 +1290,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;
@@ -1558,6 +1662,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 90b3f2815d..14a8e241b8 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;
@@ -228,10 +262,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);
@@ -487,6 +522,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 11648717ad..5e87c3398d 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,
@@ -225,7 +228,7 @@ static void request(
{
if (responder)
{
- responder->completed(U32_MAX, "No pump", LLSD());
+ responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");
}
delete body_injector;
return;
@@ -237,90 +240,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));
@@ -342,9 +338,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, follow_redirects);
+ request(url,HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
}
void LLHTTPClient::head(
@@ -354,18 +350,18 @@ void LLHTTPClient::head(
const F32 timeout,
bool follow_redirects /* = true */)
{
- request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
+ request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
}
void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout,
bool follow_redirects /* = true */)
{
- request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
+ request(url, HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
}
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers,
const F32 timeout, bool follow_redirects /* = true */)
{
- request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
+ request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
}
void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout,
bool follow_redirects /* = true */)
@@ -408,7 +404,7 @@ public:
return content;
}
- std::string asString()
+ const std::string& asString()
{
return mBuffer;
}
@@ -437,7 +433,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
@@ -480,11 +476,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 :(
@@ -493,18 +489,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 )
{
@@ -513,11 +511,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;
@@ -547,12 +545,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(
@@ -562,7 +560,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(
@@ -572,7 +580,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(
@@ -583,7 +591,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(
@@ -593,7 +601,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(
@@ -604,7 +612,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
@@ -614,7 +622,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
@@ -626,8 +634,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 5de257a4f6..b18258fd7b 100755
--- a/indra/llmessage/llhttpclient.h
+++ b/indra/llmessage/llhttpclient.h
@@ -79,6 +79,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,
bool follow_redirects = true);
static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers,
@@ -118,7 +126,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
*
@@ -135,6 +143,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 683065357d..ae4c40cdb0 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,27 +130,8 @@ 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, bool follow_redirects /* = true */) :
+LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) :
mAction(action),
mFollowRedirects(follow_redirects)
{
@@ -158,7 +139,7 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redi
}
LLURLRequest::LLURLRequest(
- LLURLRequest::ERequestAction action,
+ EHTTPMethod action,
const std::string& url,
bool follow_redirects /* = true */) :
mAction(action),
@@ -183,12 +164,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);
}
@@ -275,7 +261,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);
@@ -503,21 +489,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);
@@ -528,13 +525,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;
@@ -647,7 +650,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 20d6e30d17..88fccd4bf6 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, bool follow_redirects = true);
+ LLURLRequest(EHTTPMethod action, bool follow_redirects = true);
/**
* @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, bool follow_redirects = true);
+ LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true);
/**
* @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;
bool mFollowRedirects;
LLURLRequestDetail* mDetail;
LLIOPipe::ptr_t mCompletionCallback;
@@ -316,7 +297,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,
@@ -369,15 +350,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..e9ce116bb3 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, bool follow_redirects)
{
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 acfb3c085a..66fbecef39 100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -610,6 +610,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 182c5cfd8a..162a22cde3 100755
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -1630,7 +1630,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 953689498f..9c6ff456f3 100755
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -310,7 +310,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 1fea6dea9f..5c9171f209 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
@@ -109,7 +110,6 @@ set(viewer_SOURCE_FILES
llagentpilot.cpp
llagentui.cpp
llagentwearables.cpp
- llagentwearablesfetch.cpp
llanimstatelabels.cpp
llappcorehttp.cpp
llappearancemgr.cpp
@@ -309,6 +309,7 @@ set(viewer_SOURCE_FILES
llhasheduniqueid.cpp
llhints.cpp
llhomelocationresponder.cpp
+ llhttpretrypolicy.cpp
llhudeffect.cpp
llhudeffectbeam.cpp
llhudeffectlookat.cpp
@@ -686,6 +687,7 @@ set(viewer_HEADER_FILES
ViewerInstall.cmake
groupchatlistener.h
llaccountingcostmanager.h
+ llaisapi.h
llagent.h
llagentaccess.h
llagentcamera.h
@@ -696,7 +698,6 @@ set(viewer_HEADER_FILES
llagentpilot.h
llagentui.h
llagentwearables.h
- llagentwearablesfetch.h
llanimstatelabels.h
llappcorehttp.h
llappearance.h
@@ -895,6 +896,7 @@ set(viewer_HEADER_FILES
llgroupmgr.h
llhasheduniqueid.h
llhints.h
+ llhttpretrypolicy.h
llhomelocationresponder.h
llhudeffect.h
llhudeffectbeam.h
@@ -2156,10 +2158,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(
@@ -2240,6 +2253,7 @@ if (LL_TESTS)
set(test_libs
${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${WINDOWS_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
@@ -2285,6 +2299,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 41aac583d7..8973cda667 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11532,6 +11532,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 49f77e6c34..06a6a10a5c 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -408,7 +408,7 @@ LLAgent::LLAgent() :
mNextFidgetTime(0.f),
mCurrentFidget(0),
mFirstLogin(FALSE),
- mGenderChosen(FALSE),
+ mOutfitChosen(FALSE),
mVoiceConnected(false),
@@ -812,29 +812,6 @@ void LLAgent::standUp()
}
-void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id)
-{
- llinfos << "called" << llendl;
-
-
- // Old-style appearance entering a server-bake region.
- if (isAgentAvatarValid() &&
- !gAgentAvatarp->isUsingServerBakes() &&
- (mRegionp->getCentralBakeVersion()>0))
- {
- llinfos << "update requested due to region transition" << llendl;
- LLAppearanceMgr::instance().requestServerAppearanceUpdate();
- }
- // new-style appearance entering a non-bake region,
- // need to check for existence of the baking service.
- else if (isAgentAvatarValid() &&
- gAgentAvatarp->isUsingServerBakes() &&
- mRegionp->getCentralBakeVersion()==0)
- {
- gAgentAvatarp->checkForUnsupportedServerBakeAppearance();
- }
-}
-
//-----------------------------------------------------------------------------
// setRegion()
//-----------------------------------------------------------------------------
@@ -930,19 +907,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
{
LLEnvManagerNew::instance().onRegionCrossing();
}
-
- // If the newly entered region is using server bakes, and our
- // current appearance is non-baked, request appearance update from
- // server.
- if (mRegionp->capabilitiesReceived())
- {
- handleServerBakeRegionTransition(mRegionp->getRegionID());
- }
- else
- {
- // Need to handle via callback after caps arrive.
- mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1));
- }
}
@@ -1890,7 +1854,7 @@ BOOL LLAgent::needsRenderAvatar()
return FALSE;
}
- return mShowAvatar && mGenderChosen;
+ return mShowAvatar && mOutfitChosen;
}
// TRUE if we need to render your own avatar's head.
@@ -2538,17 +2502,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;
@@ -2567,39 +2533,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())
{
@@ -2745,7 +2715,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
{
@@ -2755,7 +2725,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
@@ -3303,8 +3273,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"];
@@ -3373,8 +3342,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"));
}
}
};
@@ -3658,82 +3626,6 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
}
*/
-//static
-void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
-{
- gAgentQueryManager.mNumPendingQueries--;
- if (gAgentQueryManager.mNumPendingQueries == 0)
- {
- selfStopPhase("fetch_texture_cache_entries");
- }
-
- if (!isAgentAvatarValid() || gAgentAvatarp->isDead())
- {
- llwarns << "No avatar for user in cached texture update!" << llendl;
- return;
- }
-
- if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance())
- {
- // ignore baked textures when in customize mode
- return;
- }
-
- S32 query_id;
- mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id);
-
- S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData);
-
-
- S32 num_results = 0;
- for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++)
- {
- LLUUID texture_id;
- U8 texture_index;
-
- mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
- mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
-
-
- if ((S32)texture_index < TEX_NUM_INDICES )
- {
- const LLAvatarAppearanceDictionary::TextureEntry *texture_entry = LLAvatarAppearanceDictionary::instance().getTexture((ETextureIndex)texture_index);
- if (texture_entry)
- {
- EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex;
-
- if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id)
- {
- if (texture_id.notNull())
- {
- //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
- gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id);
- //gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
- gAgentQueryManager.mActiveCacheQueries[baked_index] = 0;
- num_results++;
- }
- else
- {
- // no cache of this bake. request upload.
- gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE);
- }
- }
- }
- }
- }
- llinfos << "Received cached texture response for " << num_results << " textures." << llendl;
- gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them");
-
- gAgentAvatarp->updateMeshTextures();
-
- if (gAgentQueryManager.mNumPendingQueries == 0)
- {
- // RN: not sure why composites are disabled at this point
- gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
- gAgent.sendAgentSetAppearance();
- }
-}
-
BOOL LLAgent::anyControlGrabbed() const
{
for (U32 i = 0; i < TOTAL_CONTROLS; i++)
@@ -4323,192 +4215,6 @@ void LLAgent::requestLeaveGodMode()
sendReliableMessage();
}
-// For debugging, trace agent state at times appearance message are sent out.
-void LLAgent::dumpSentAppearance(const std::string& dump_prefix)
-{
- std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");
-
- LLAPRFile outfile;
- std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
- outfile.open(fullpath, LL_APR_WB );
- apr_file_t* file = outfile.getFileHandle();
- if (!file)
- {
- return;
- }
- else
- {
- LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << llendl;
- }
-
- LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000);
- if (appearance_version_param)
- {
- F32 value = appearance_version_param->getWeight();
- dump_visual_param(file, appearance_version_param, value);
- }
- for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
- iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
- ++iter)
- {
- const ETextureIndex index = iter->first;
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
- if (texture_dict->mIsBakedTexture)
- {
- LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index);
- const LLUUID& uuid = entry->getID();
- apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str());
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// sendAgentSetAppearance()
-//-----------------------------------------------------------------------------
-void LLAgent::sendAgentSetAppearance()
-{
- if (gAgentQueryManager.mNumPendingQueries > 0)
- {
- return;
- }
-
- if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return;
-
- // At this point we have a complete appearance to send and are in a non-baking region.
- // DRANO FIXME
- //gAgentAvatarp->setIsUsingServerBakes(FALSE);
- S32 sb_count, host_count, both_count, neither_count;
- gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count);
- if (both_count != 0 || neither_count != 0)
- {
- llwarns << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << llendl;
- }
- if (sb_count != 0 && host_count == 0)
- {
- gAgentAvatarp->setIsUsingServerBakes(true);
- }
- else if (sb_count == 0 && host_count != 0)
- {
- gAgentAvatarp->setIsUsingServerBakes(false);
- }
- else if (sb_count + host_count > 0)
- {
- llwarns << "unclear baked texture state, not sending appearance" << llendl;
- return;
- }
-
-
- LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL;
- //dumpAvatarTEs( "sendAgentSetAppearance()" );
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_AgentSetAppearance);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
-
- // correct for the collision tolerance (to make it look like the
- // agent is actually walking on the ground/object)
- // NOTE -- when we start correcting all of the other Havok geometry
- // 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);
-
- // 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"
- mAppearanceSerialNum++;
- msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum );
-
- // is texture data current relative to wearables?
- // KLW - TAT this will probably need to check the local queue.
- BOOL textures_current = gAgentAvatarp->areTexturesCurrent();
-
- for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ )
- {
- const ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
-
- // if we're not wearing a skirt, we don't need the texture to be baked
- if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))
- {
- continue;
- }
-
- // IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures
- if (!gAgentAvatarp->isTextureDefined(texture_index, 0))
- {
- LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << llendl;
- textures_current = FALSE;
- break;
- }
- }
-
- // only update cache entries if we have all our baked textures
-
- // FIXME DRANO need additional check for not in appearance editing
- // mode, if still using local composites need to set using local
- // composites to false, and update mesh textures.
- if (textures_current)
- {
- bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
- std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance";
- if (enable_verbose_dumps)
- {
- dumpSentAppearance(dump_prefix);
- }
- LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL;
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
- {
- BOOL generate_valid_hash = TRUE;
- if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLAvatarAppearanceDefines::EBakedTextureIndex)baked_index))
- {
- generate_valid_hash = FALSE;
- LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL;
- }
-
- const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash);
- if (hash.notNull())
- {
- ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index);
- msg->nextBlockFast(_PREHASH_WearableData);
- msg->addUUIDFast(_PREHASH_CacheID, hash);
- msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index);
- }
- }
- msg->nextBlockFast(_PREHASH_ObjectData);
- gAgentAvatarp->sendAppearanceMessage( gMessageSystem );
- }
- else
- {
- // If the textures aren't baked, send NULL for texture IDs
- // This means the baked texture IDs on the server will be untouched.
- // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs
- msg->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0);
- }
-
-
- S32 transmitted_params = 0;
- for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam())
- {
- if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
- {
- msg->nextBlockFast(_PREHASH_VisualParam );
-
- // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence.
- const F32 param_value = param->getWeight();
- const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight());
- msg->addU8Fast(_PREHASH_ParamValue, new_weight );
- transmitted_params++;
- }
- }
-
-// llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
- sendReliableMessage();
-}
-
void LLAgent::sendAgentDataUpdateRequest()
{
gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest);
@@ -4651,23 +4357,6 @@ void LLAgent::renderAutoPilotTarget()
/********************************************************************************/
-LLAgentQueryManager gAgentQueryManager;
-
-LLAgentQueryManager::LLAgentQueryManager() :
- mWearablesCacheQueryID(0),
- mNumPendingQueries(0),
- mUpdateSerialNum(0)
-{
- for (U32 i = 0; i < BAKED_NUM_INDICES; i++)
- {
- mActiveCacheQueries[i] = 0;
- }
-}
-
-LLAgentQueryManager::~LLAgentQueryManager()
-{
-}
-
//-----------------------------------------------------------------------------
// LLTeleportRequest
//-----------------------------------------------------------------------------
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 7fac17d098..0095c280fb 100755
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -161,12 +161,13 @@ public:
// Gender
//--------------------------------------------------------------------
public:
- // On the very first login, gender isn't chosen until the user clicks
- // in a dialog. We don't render the avatar until they choose.
- BOOL isGenderChosen() const { return mGenderChosen; }
- void setGenderChosen(BOOL b) { mGenderChosen = b; }
+ // On the very first login, outfit needs to be chosen by some
+ // mechanism, usually by loading the requested initial outfit. We
+ // don't render the avatar until the choice is made.
+ BOOL isOutfitChosen() const { return mOutfitChosen; }
+ void setOutfitChosen(BOOL b) { mOutfitChosen = b; }
private:
- BOOL mGenderChosen;
+ BOOL mOutfitChosen;
/** Identity
** **
@@ -612,7 +613,6 @@ private:
void handleTeleportFinished();
void handleTeleportFailed();
- void handleServerBakeRegionTransition(const LLUUID& region_id);
//--------------------------------------------------------------------
// Teleport State
@@ -847,8 +847,6 @@ private:
public:
void sendMessage(); // Send message to this agent's region
void sendReliableMessage();
- void dumpSentAppearance(const std::string& dump_prefix);
- void sendAgentSetAppearance();
void sendAgentDataUpdateRequest();
void sendAgentUserInfoRequest();
// IM to Email and Online visibility
@@ -862,7 +860,6 @@ public:
static void processAgentGroupDataUpdate(LLMessageSystem *msg, void **);
static void processAgentDropGroup(LLMessageSystem *msg, void **);
static void processScriptControlChange(LLMessageSystem *msg, void **);
- static void processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data);
/** Messaging
** **
@@ -891,24 +888,4 @@ inline bool operator==(const LLGroupData &a, const LLGroupData &b)
return (a.mID == b.mID);
}
-class LLAgentQueryManager
-{
- friend class LLAgent;
- friend class LLAgentWearables;
-
-public:
- LLAgentQueryManager();
- virtual ~LLAgentQueryManager();
-
- BOOL hasNoPendingQueries() const { return getNumPendingQueries() == 0; }
- S32 getNumPendingQueries() const { return mNumPendingQueries; }
-private:
- S32 mNumPendingQueries;
- S32 mWearablesCacheQueryID;
- U32 mUpdateSerialNum;
- S32 mActiveCacheQueries[LLAvatarAppearanceDefines::BAKED_NUM_INDICES];
-};
-
-extern LLAgentQueryManager gAgentQueryManager;
-
#endif
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 1edbbe2a2e..e4004f108c 100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -30,7 +30,6 @@
#include "llaccordionctrltab.h"
#include "llagent.h"
#include "llagentcamera.h"
-#include "llagentwearablesfetch.h"
#include "llappearancemgr.h"
#include "llcallbacklist.h"
#include "llfloatersidepanelcontainer.h"
@@ -62,15 +61,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);
+}
///////////////////////////////////////////////////////////////////////////////
@@ -126,13 +125,6 @@ void LLAgentWearables::dump()
}
}
- llinfos << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << llendl;
- for (std::set<LLUUID>::iterator it = mItemsAwaitingWearableUpdate.begin();
- it != mItemsAwaitingWearableUpdate.end();
- ++it)
- {
- llinfos << (*it).asString() << llendl;
- }
}
struct LLAgentDumper
@@ -180,24 +172,11 @@ void LLAgentWearables::initClass()
}
void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
-{
+{
llassert(avatar);
- avatar->outputRezTiming("Sending wearables request");
- sendAgentWearablesRequest();
setAvatarAppearance(avatar);
}
-// wearables
-LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
-{
- llinfos << "destructor - all done?" << llendl;
- gAgentWearables.createStandardWearablesAllDone();
-}
-
-LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
-{
- gAgentWearables.sendAgentWearablesUpdate();
-}
/**
* @brief Construct a callback for dealing with the wearables.
@@ -209,7 +188,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,42 +200,24 @@ 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)
- {
- llinfos << "callback fired, inv_item " << inv_item.asString() << llendl;
- }
-
if (inv_item.isNull())
return;
gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable);
- if (mTodo & CALL_UPDATE)
- {
- gAgentWearables.sendAgentWearablesUpdate();
- }
- if (mTodo & CALL_RECOVERDONE)
- {
- LLAppearanceMgr::instance().addCOFItemLink(inv_item,false);
- gAgentWearables.recoverMissingWearableDone();
- }
/*
* Do this for every one in the loop
*/
- if (mTodo & CALL_CREATESTANDARDDONE)
- {
- LLAppearanceMgr::instance().addCOFItemLink(inv_item,false);
- gAgentWearables.createStandardWearablesDone(mType, mIndex);
- }
if (mTodo & CALL_MAKENEWOUTFITDONE)
{
gAgentWearables.makeNewOutfitDone(mType, mIndex);
}
if (mTodo & CALL_WEARITEM)
{
- LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription);
+ LLAppearanceMgr::instance().addCOFItemLink(inv_item,
+ new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription);
}
}
@@ -303,81 +264,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy
gInventory.notifyObservers();
}
-void LLAgentWearables::sendAgentWearablesUpdate()
-{
- // First make sure that we have inventory items for each wearable
- for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
- {
- for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index)
- {
- LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index);
- if (wearable)
- {
- if (wearable->getItemID().isNull())
- {
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- LLPointer<LLRefCount>(NULL),
- (LLWearableType::EType)type,
- index,
- wearable,
- addWearableToAgentInventoryCallback::CALL_NONE);
- addWearableToAgentInventory(cb, wearable);
- }
- else
- {
- gInventory.addChangedMask(LLInventoryObserver::LABEL,
- wearable->getItemID());
- }
- }
- }
- }
-
- // Then make sure the inventory is in sync with the avatar.
- gInventory.notifyObservers();
-
- // Send the AgentIsNowWearing
- gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
- lldebugs << "sendAgentWearablesUpdate()" << llendl;
- // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables.
- for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
- {
- gMessageSystem->nextBlockFast(_PREHASH_WearableData);
-
- U8 type_u8 = (U8)type;
- gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8);
-
- LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0);
- if (wearable)
- {
- //llinfos << "Sending wearable " << wearable->getName() << llendl;
- LLUUID item_id = wearable->getItemID();
- const LLViewerInventoryItem *item = gInventory.getItem(item_id);
- if (item && item->getIsLinkType())
- {
- // Get the itemID that this item points to. i.e. make sure
- // we are storing baseitems, not their links, in the database.
- item_id = item->getLinkedUUID();
- }
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
- }
- else
- {
- //llinfos << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << llendl;
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
- }
-
- lldebugs << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl;
- }
- gAgent.sendReliableMessage();
-}
-
-void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update,
+void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index,
const std::string new_name)
{
LLViewerWearable* old_wearable = getViewerWearable(type, index);
@@ -418,23 +305,14 @@ 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;
- if (send_update)
- {
- todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
- }
+ U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;
LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
+ new AddWearableToAgentInventoryCallback(
LLPointer<LLRefCount>(NULL),
type,
index,
@@ -444,12 +322,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32
return;
}
- gAgentAvatarp->wearableUpdated( type, TRUE );
-
- if (send_update)
- {
- sendAgentWearablesUpdate();
- }
+ gAgentAvatarp->wearableUpdated(type);
}
}
@@ -483,12 +356,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;
@@ -525,8 +398,6 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3
{
wearable->revertValues();
}
-
- gAgent.sendAgentSetAppearance();
}
void LLAgentWearables::saveAllWearables()
@@ -539,9 +410,8 @@ void LLAgentWearables::saveAllWearables()
for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
{
for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
- saveWearable((LLWearableType::EType)i, j, FALSE);
+ saveWearable((LLWearableType::EType)i, j);
}
- sendAgentWearablesUpdate();
}
// Called when the user changes the name of a wearable inventory item that is currently being worn.
@@ -570,7 +440,6 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&
old_wearable->setName(old_name);
setWearable((LLWearableType::EType)i,j,new_wearable);
- sendAgentWearablesUpdate();
break;
}
}
@@ -691,22 +560,13 @@ LLViewerWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i
return NULL;
}
-void LLAgentWearables::sendAgentWearablesRequest()
-{
- gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gAgent.sendReliableMessage();
-}
-
LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/)
{
return dynamic_cast<LLViewerWearable*> (getWearable(type, index));
}
const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) const
- {
+{
return dynamic_cast<const LLViewerWearable*> (getWearable(type, index));
}
@@ -714,49 +574,38 @@ 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);
-}
+ gAgentAvatarp->wearableUpdated(wearable->getType());
+ }
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);
+ }
checkWearableAgainstInventory(viewer_wearable);
-}
-}
-
-BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const
-{
- return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end();
-}
-
-U32 LLAgentWearables::itemUpdatePendingCount() const
-{
- return mItemsAwaitingWearableUpdate.size();
+ }
}
const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const
@@ -782,157 +631,6 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const
return getWearableFromItemID(item_id) != NULL;
}
-// MULTI-WEARABLE: DEPRECATED (see backwards compatibility)
-// static
-// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume
-// that viewers have a Current Outfit Folder and won't need this message, and thus
-// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted
-void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data)
-{
- // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates
- // that may result from AgentWearablesRequest having been sent more than once.
- if (mInitialWearablesUpdateReceived)
- return;
-
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->startPhase("process_initial_wearables_update");
- gAgentAvatarp->outputRezTiming("Received initial wearables update");
- }
-
- // notify subscribers that wearables started loading. See EXT-7777
- // *TODO: find more proper place to not be called from deprecated method.
- // Seems such place is found: LLInitialWearablesFetch::processContents()
- gAgentWearables.notifyLoadingStarted();
-
- mInitialWearablesUpdateReceived = true;
-
- LLUUID agent_id;
- gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
-
- if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID()))
- {
- gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum);
-
- const S32 NUM_BODY_PARTS = 4;
- S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
- if (num_wearables < NUM_BODY_PARTS)
- {
- // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin).
- // The fact that they don't have any here (only a dummy is sent) implies that either:
- // 1. This account existed before we had wearables
- // 2. The database has gotten messed up
- // 3. This is the account's first login (i.e. the wearables haven't been generated yet).
- return;
- }
-
- // Get the UUID of the current outfit folder (will be created if it doesn't exist)
- const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
- LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id);
-
- //lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
- // Add wearables
- // MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future.
- gAgentWearables.mItemsAwaitingWearableUpdate.clear();
- for (S32 i=0; i < num_wearables; i++)
- {
- // Parse initial wearables data from message system
- U8 type_u8 = 0;
- gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
- if (type_u8 >= LLWearableType::WT_COUNT)
- {
- continue;
- }
- const LLWearableType::EType type = (LLWearableType::EType) type_u8;
-
- LLUUID item_id;
- gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i);
-
- LLUUID asset_id;
- gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i);
- if (asset_id.isNull())
- {
- LLViewerWearable::removeFromAvatar(type, FALSE);
- }
- else
- {
- LLAssetType::EType asset_type = LLWearableType::getAssetType(type);
- if (asset_type == LLAssetType::AT_NONE)
- {
- continue;
- }
-
- // MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions
-
- // Store initial wearables data until we know whether we have the current outfit folder or need to use the data.
- LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id);
- outfit->add(wearable_data);
- }
-
- lldebugs << " " << LLWearableType::getTypeLabel(type) << llendl;
- }
-
- // Get the complete information on the items in the inventory and set up an observer
- // that will trigger when the complete information is fetched.
- outfit->startFetch();
- if(outfit->isFinished())
- {
- // everything is already here - call done.
- outfit->done();
- }
- else
- {
- // it's all on it's way - add an observer, and the inventory
- // will call done for us when everything is here.
- gInventory.addObserver(outfit);
- }
-
- }
-}
-
-// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
-// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that
-// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.)
-void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index)
-{
- // 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;
- LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
-
- setWearable(type,index,new_wearable);
- //new_wearable->writeToAvatar(TRUE);
-
- // Add a new one in the lost and found folder.
- // (We used to overwrite the "not found" one, but that could potentially
- // destory content.) JC
- const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
- LLPointer<LLInventoryCallback> cb =
- new addWearableToAgentInventoryCallback(
- LLPointer<LLRefCount>(NULL),
- type,
- index,
- new_wearable,
- addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
- addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE);
-}
-
-void LLAgentWearables::recoverMissingWearableDone()
-{
- // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
- updateWearablesLoaded();
- if (areWearablesLoaded())
- {
- // Make sure that the server's idea of the avatar's wearables actually match the wearables.
- gAgent.sendAgentSetAppearance();
- }
- else
- {
- gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null);
- gInventory.notifyObservers();
- }
-}
-
void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index)
{
LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index);
@@ -956,17 +654,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 +713,7 @@ public:
}
private:
- LLInventoryModel::item_array_t mItemsToLink;
+ LLInventoryObject::const_object_list_t mItemsToLink;
std::vector<LLViewerWearable*> mWearablesAwaitingItems;
};
@@ -1067,28 +765,38 @@ void LLAgentWearables::createStandardWearables()
}
}
-void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index)
+// We no longer need this message in the current viewer, but send
+// it for now to maintain compatibility with release viewers. Can
+// remove this function once the SH-3455 changesets are universally deployed.
+void LLAgentWearables::sendDummyAgentWearablesUpdate()
{
- llinfos << "type " << type << " index " << index << llendl;
+ LL_DEBUGS("Avatar") << "sendAgentWearablesUpdate()" << llendl;
- if (!isAgentAvatarValid()) return;
- gAgentAvatarp->updateVisualParams();
-}
+ // Send the AgentIsNowWearing
+ gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
+
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-void LLAgentWearables::createStandardWearablesAllDone()
-{
- // ... because sendAgentWearablesUpdate will notify inventory
- // observers.
- llinfos << "all done?" << llendl;
+ // Send 4 standardized nonsense item ids (same as returned by the modified sim, not that it especially matters).
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(1));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("db5a4e5f-9da3-44c8-992d-1181c5795498"));
- mWearablesLoaded = TRUE;
- checkWearablesLoaded();
- notifyLoadingFinished();
-
- updateServer();
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(2));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("6969c7cc-f72f-4a76-a19b-c293cce8ce4f"));
+
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(3));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("7999702b-b291-48f9-8903-c91dfb828408"));
- // Treat this as the first texture entry message, if none received yet
- gAgentAvatarp->onFirstTEMessageReceived();
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(4));
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("566cb59e-ef60-41d7-bfa6-e0f293fbea40"));
+
+ gAgent.sendReliableMessage();
}
void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
@@ -1204,11 +912,10 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
for (S32 i=max_entry; i>=0; i--)
{
LLViewerWearable* old_wearable = getViewerWearable(type,i);
- //queryWearableCache(); // moved below
if (old_wearable)
{
popWearable(old_wearable);
- old_wearable->removeFromAvatar(TRUE);
+ old_wearable->removeFromAvatar();
}
}
clearWearableType(type);
@@ -1216,48 +923,99 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
else
{
LLViewerWearable* old_wearable = getViewerWearable(type, index);
- //queryWearableCache(); // moved below
if (old_wearable)
{
popWearable(old_wearable);
- old_wearable->removeFromAvatar(TRUE);
+ old_wearable->removeFromAvatar();
}
}
- queryWearableCache();
-
- // Update the server
- updateServer();
gInventory.notifyObservers();
}
// 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];
@@ -1304,14 +1062,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
// Start rendering & update the server
mWearablesLoaded = TRUE;
- checkWearablesLoaded();
+
notifyLoadingFinished();
- queryWearableCache();
- updateServer();
gAgentAvatarp->dumpAvatarTEs("setWearableOutfit");
- lldebugs << "setWearableOutfit() end" << llendl;
+ LL_DEBUGS("Avatar") << "setWearableOutfit() end" << llendl;
}
@@ -1428,81 +1184,8 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWeara
llinfos << "Replaced current element 0 for type " << type
<< " size is now " << getWearableCount(type) << llendl;
}
-
- //llinfos << "LLVOAvatar::setWearableItem()" << llendl;
- queryWearableCache();
- //new_wearable->writeToAvatar(TRUE);
-
- updateServer();
-}
-
-void LLAgentWearables::queryWearableCache()
-{
- if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()))
- {
- return;
- }
-
- // Look up affected baked textures.
- // If they exist:
- // disallow updates for affected layersets (until dataserver responds with cache request.)
- // If cache miss, turn updates back on and invalidate composite.
- // If cache hit, modify baked texture entries.
- //
- // Cache requests contain list of hashes for each baked texture entry.
- // Response is list of valid baked texture assets. (same message)
-
- gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID);
-
- S32 num_queries = 0;
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
- {
- LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index);
- if (hash_id.notNull())
- {
- num_queries++;
- // *NOTE: make sure at least one request gets packed
-
- ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
-
- //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
- gMessageSystem->nextBlockFast(_PREHASH_WearableData);
- gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id);
- gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index);
- }
-
- gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID;
- }
- //VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout
- if(gAgent.getRegion())
- {
- if (isAgentAvatarValid())
- {
- selfStartPhase("fetch_texture_cache_entries");
- gAgentAvatarp->outputRezTiming("Fetching textures from cache");
- }
-
- LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL;
- gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
- gAgentQueryManager.mNumPendingQueries++;
- gAgentQueryManager.mWearablesCacheQueryID++;
- }
}
-// 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);
- }
- }
-
// User has picked "remove from avatar" from a menu.
// static
void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index)
@@ -1671,17 +1354,6 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
}
}
-void LLAgentWearables::checkWearablesLoaded() const
-{
-#ifdef SHOW_ASSERT
- U32 item_pend_count = itemUpdatePendingCount();
- if (mWearablesLoaded)
- {
- llassert(item_pend_count==0);
- }
-#endif
-}
-
// Returns false if the given wearable is already topmost/bottommost
// (depending on closer_to_body parameter).
bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const
@@ -1698,20 +1370,9 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod
BOOL LLAgentWearables::areWearablesLoaded() const
{
- checkWearablesLoaded();
return mWearablesLoaded;
}
-// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate
-void LLAgentWearables::updateWearablesLoaded()
-{
- mWearablesLoaded = (itemUpdatePendingCount()==0);
- if (mWearablesLoaded)
- {
- notifyLoadingFinished();
- }
-}
-
bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const
{
if (!wearable) return false;
@@ -1721,7 +1382,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co
return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES))
&& (getWearableCount(type) <= 1) );
}
-void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)
+void LLAgentWearables::animateAllWearableParams(F32 delta)
{
for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type )
{
@@ -1731,7 +1392,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)
llassert(wearable);
if (wearable)
{
- wearable->animateParams(delta, upload_bake);
+ wearable->animateParams(delta);
}
}
}
@@ -1854,30 +1515,6 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id)
}
}
-void LLAgentWearables::updateServer()
-{
- sendAgentWearablesUpdate();
- 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 +1533,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..a93b6d9241 100755
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -42,7 +42,6 @@
class LLInventoryItem;
class LLVOAvatarSelf;
class LLViewerWearable;
-class LLInitialWearablesFetch;
class LLViewerObject;
class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData
@@ -51,7 +50,6 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
// Constructors / destructors / Initializers
//--------------------------------------------------------------------
public:
- friend class LLInitialWearablesFetch;
LLAgentWearables();
virtual ~LLAgentWearables();
@@ -62,9 +60,6 @@ public:
// LLInitClass interface
static void initClass();
-protected:
- void createStandardWearablesDone(S32 type, U32 index/* = 0*/);
- void createStandardWearablesAllDone();
//--------------------------------------------------------------------
// Queries
@@ -77,6 +72,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;
@@ -84,7 +80,7 @@ public:
// Note: False for shape, skin, eyes, and hair, unless you have MORE than 1.
bool canWearableBeRemoved(const LLViewerWearable* wearable) const;
- void animateAllWearableParams(F32 delta, BOOL upload_bake);
+ void animateAllWearableParams(F32 delta);
//--------------------------------------------------------------------
// Accessors
@@ -107,7 +103,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);
@@ -151,31 +147,10 @@ private:
void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
protected:
static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response);
-
- //--------------------------------------------------------------------
- // Server Communication
- //--------------------------------------------------------------------
-public:
- // Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant)
- static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data);
-
-protected:
- /*virtual*/ void invalidateBakedTextureHash(LLMD5& hash) const;
- void sendAgentWearablesUpdate();
- void sendAgentWearablesRequest();
- void queryWearableCache();
- void updateServer();
- static void onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata);
//--------------------------------------------------------------------
// 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);
@@ -184,11 +159,16 @@ private:
//--------------------------------------------------------------------
public:
void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found);
- void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE,
+ void saveWearable(const LLWearableType::EType type, const U32 index,
const std::string new_name = "");
void saveAllWearables();
void revertWearable(const LLWearableType::EType type, const U32 index);
+ // We no longer need this message in the current viewer, but send
+ // it for now to maintain compatibility with release viewers. Can
+ // remove this function once the SH-3455 changesets are universally deployed.
+ void sendDummyAgentWearablesUpdate();
+
//--------------------------------------------------------------------
// Static UI hooks
//--------------------------------------------------------------------
@@ -202,9 +182,6 @@ public:
static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array);
static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array);
- BOOL itemUpdatePending(const LLUUID& item_id) const;
- U32 itemUpdatePendingCount() const;
-
//--------------------------------------------------------------------
// Signals
//--------------------------------------------------------------------
@@ -231,29 +208,18 @@ private:
private:
static BOOL mInitialWearablesUpdateReceived;
BOOL mWearablesLoaded;
- std::set<LLUUID> mItemsAwaitingWearableUpdate;
/**
* True if agent's outfit is being changed now.
*/
BOOL mCOFChangeInProgress;
+ LLTimer mCOFChangeTimer;
//--------------------------------------------------------------------------------
// Support classes
//--------------------------------------------------------------------------------
private:
- class createStandardWearablesAllDoneCallback : public LLRefCount
- {
- protected:
- ~createStandardWearablesAllDoneCallback();
- };
- class sendAgentWearablesUpdateCallback : public LLRefCount
- {
- protected:
- ~sendAgentWearablesUpdateCallback();
- };
-
- class addWearableToAgentInventoryCallback : public LLInventoryCallback
+ class AddWearableToAgentInventoryCallback : public LLInventoryCallback
{
public:
enum ETodo
@@ -266,7 +232,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
deleted file mode 100755
index 8b6b6db525..0000000000
--- a/indra/newview/llagentwearablesfetch.cpp
+++ /dev/null
@@ -1,600 +0,0 @@
-/**
- * @file llagentwearablesfetch.cpp
- * @brief LLAgentWearblesFetch class implementation
- *
- * $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$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llagentwearablesfetch.h"
-
-#include "llagent.h"
-#include "llagentwearables.h"
-#include "llappearancemgr.h"
-#include "llinventoryfunctions.h"
-#include "llstartup.h"
-#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)
-{
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->startPhase("initial_wearables_fetch");
- gAgentAvatarp->outputRezTiming("Initial wearables fetch started");
- }
-}
-
-LLInitialWearablesFetch::~LLInitialWearablesFetch()
-{
-}
-
-// virtual
-void LLInitialWearablesFetch::done()
-{
- // Delay processing the actual results of this so it's not handled within
- // gInventory.notifyObservers. The results will be handled in the next
- // idle tick instead.
- gInventory.removeObserver(this);
- doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this));
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->stopPhase("initial_wearables_fetch");
- gAgentAvatarp->outputRezTiming("Initial wearables fetch done");
- }
-}
-
-void LLInitialWearablesFetch::add(InitialWearableData &data)
-
-{
- mAgentInitialWearables.push_back(data);
-}
-
-void LLInitialWearablesFetch::processContents()
-{
- if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted.
- {
- delete this;
- return ;
- }
-
- // Fetch the wearable items from the Current Outfit Folder
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t wearable_array;
- LLFindWearables is_wearable;
- llassert_always(mComplete.size() != 0);
- gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array,
- LLInventoryModel::EXCLUDE_TRASH, is_wearable);
-
- LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
- if (wearable_array.count() > 0)
- {
- gAgentWearables.notifyLoadingStarted();
- LLAppearanceMgr::instance().updateAppearanceFromCOF();
- }
- else
- {
- // if we're constructing the COF from the wearables message, we don't have a proper outfit link
- LLAppearanceMgr::instance().setOutfitDirty(true);
- processWearablesMessage();
- }
- delete this;
-}
-
-class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver
-{
-public:
- LLFetchAndLinkObserver(uuid_vec_t& ids):
- LLInventoryFetchItemsObserver(ids)
- {
- }
- ~LLFetchAndLinkObserver()
- {
- }
- virtual void done()
- {
- gInventory.removeObserver(this);
-
- // Link to all fetched items in COF.
- LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
- for (uuid_vec_t::iterator it = mIDs.begin();
- it != mIDs.end();
- ++it)
- {
- LLUUID id = *it;
- LLViewerInventoryItem *item = gInventory.getItem(*it);
- if (!item)
- {
- llwarns << "fetch failed!" << llendl;
- continue;
- }
-
- link_inventory_item(gAgent.getID(),
- item->getLinkedUUID(),
- LLAppearanceMgr::instance().getCOF(),
- item->getName(),
- item->getDescription(),
- LLAssetType::AT_LINK,
- link_waiter);
- }
- }
-};
-
-void LLInitialWearablesFetch::processWearablesMessage()
-{
- if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead.
- {
- const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF();
- uuid_vec_t ids;
- for (U8 i = 0; i < mAgentInitialWearables.size(); ++i)
- {
- // Populate the current outfit folder with links to the wearables passed in the message
- InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback.
-
- if (wearable_data->mAssetID.notNull())
- {
- ids.push_back(wearable_data->mItemID);
- }
- else
- {
- llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
- << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
- delete wearable_data;
- }
- }
-
- // Add all current attachments to the requested items as well.
- if (isAgentAvatarValid())
- {
- for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (!attachment) continue;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- LLViewerObject* attached_object = (*attachment_iter);
- if (!attached_object) continue;
- const LLUUID& item_id = attached_object->getAttachmentItemID();
- if (item_id.isNull()) continue;
- ids.push_back(item_id);
- }
- }
- }
-
- // Need to fetch the inventory items for ids, then create links to them after they arrive.
- LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids);
- fetcher->startFetch();
- // If no items to be fetched, done will never be triggered.
- // TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition.
- if (fetcher->isFinished())
- {
- fetcher->done();
- }
- else
- {
- gInventory.addObserver(fetcher);
- }
- }
- else
- {
- LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL;
- }
-}
-
-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
deleted file mode 100755
index bedc445c0e..0000000000
--- a/indra/newview/llagentwearablesfetch.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * @file llagentwearablesinitialfetch.h
- * @brief LLAgentWearablesInitialFetch class header file
- *
- * $LicenseInfo:firstyear=2000&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_LLAGENTWEARABLESINITIALFETCH_H
-#define LL_LLAGENTWEARABLESINITIALFETCH_H
-
-#include "llinventoryobserver.h"
-#include "llwearabletype.h"
-#include "lluuid.h"
-
-//--------------------------------------------------------------------
-// InitialWearablesFetch
-//
-// This grabs contents from the COF and processes them.
-// The processing is handled in idle(), i.e. outside of done(),
-// to avoid gInventory.notifyObservers recursion.
-//--------------------------------------------------------------------
-class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver
-{
- LOG_CLASS(LLInitialWearablesFetch);
-
-public:
- LLInitialWearablesFetch(const LLUUID& cof_id);
- ~LLInitialWearablesFetch();
- virtual void done();
-
- struct InitialWearableData
- {
- LLWearableType::EType mType;
- LLUUID mItemID;
- LLUUID mAssetID;
- InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) :
- mType(type),
- mItemID(itemID),
- mAssetID(assetID)
- {}
- };
-
- void add(InitialWearableData &data);
-
-protected:
- void processWearablesMessage();
- void processContents();
-
-private:
- typedef std::vector<InitialWearableData> initial_wearable_data_vec_t;
- 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..14978662f6
--- /dev/null
+++ b/indra/newview/llaisapi.cpp
@@ -0,0 +1,866 @@
+/**
+ * @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("categories") &&
+ embedded.has("links") &&
+ embedded.has("items"))
+ {
+ mCatDescendentsKnown[category_id] = embedded["categories"].size();
+ mCatDescendentsKnown[category_id] += embedded["links"].size();
+ mCatDescendentsKnown[category_id] += embedded["items"].size();
+ }
+}
+
+void AISUpdate::parseEmbedded(const LLSD& embedded)
+{
+ if (embedded.has("links")) // _embedded in a category
+ {
+ parseEmbeddedLinks(embedded["links"]);
+ }
+ if (embedded.has("items")) // _embedded in a category
+ {
+ parseEmbeddedItems(embedded["items"]);
+ }
+ if (embedded.has("item")) // _embedded in a link
+ {
+ parseEmbeddedItem(embedded["item"]);
+ }
+ if (embedded.has("categories")) // _embedded in a category
+ {
+ parseEmbeddedCategories(embedded["categories"]);
+ }
+ if (embedded.has("category")) // _embedded in a link
+ {
+ parseEmbeddedCategory(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::parseEmbeddedItem(const LLSD& item)
+{
+ // a single item (_embedded in a link)
+ if (item.has("item_id"))
+ {
+ if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
+ {
+ parseItem(item);
+ }
+ }
+}
+
+void AISUpdate::parseEmbeddedItems(const LLSD& items)
+{
+ // a map of items (_embedded in a category)
+ 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::parseEmbeddedCategory(const LLSD& category)
+{
+ // a single category (_embedded in a link)
+ if (category.has("category_id"))
+ {
+ if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
+ {
+ parseCategory(category);
+ }
+ }
+}
+
+void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
+{
+ // a map of categories (_embedded in a category)
+ 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..5a2ec94af9
--- /dev/null
+++ b/indra/newview/llaisapi.h
@@ -0,0 +1,183 @@
+/**
+ * @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& items);
+ void parseEmbeddedCategories(const LLSD& categories);
+ void parseEmbeddedItem(const LLSD& item);
+ void parseEmbeddedCategory(const LLSD& category);
+ 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..43ba66f8c5 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);
+ addCOFItemLink(item, 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();
- }
- }
-}
-
-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;
+ LLViewerInventoryItem *copy_item = new LLViewerInventoryItem;
+ copy_item->copyViewerItem(vitem);
+ copy_item->setDescription(description);
+ link_inventory_object(getCOF(), copy_item, cb);
}
- 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);
- }
- return;
}
LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id)
@@ -2514,6 +2590,12 @@ LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& i
return result;
}
+bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id)
+{
+ LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id);
+ return links.size() > 0;
+}
+
void LLAppearanceMgr::removeAllClothesFromAvatar()
{
// Fetch worn clothes (i.e. the ones in COF).
@@ -2524,8 +2606,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 +2650,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 +2665,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 +2683,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 +2722,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 +2736,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 +2756,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 +2861,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 +2868,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 +2882,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 +2911,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 +2972,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 +2985,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;
+
+ mInFlightCounter++;
+ mInFlightTimer.setTimerExpirySec(60.0);
+ LLHTTPClient::post(url, body, this);
+ llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
+ gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
+}
- void debugCOF(const LLSD& content)
+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 +3417,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 +3435,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 +3473,7 @@ public:
}
}
+private:
LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
};
@@ -3337,6 +3506,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 +3525,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 +3625,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 +3673,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);
@@ -3474,7 +3692,7 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b
bool result = false;
if (result = gAgentWearables.moveWearable(item, closer_to_body))
{
- gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE);
+ gAgentAvatarp->wearableUpdated(item->getWearableType());
}
setOutfitDirty(true);
@@ -3536,7 +3754,8 @@ LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false),
mOutfitLocked(false),
- mIsInUpdateAppearanceFromCOF(false)
+ mIsInUpdateAppearanceFromCOF(false),
+ mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)
{
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
@@ -3586,7 +3805,11 @@ 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.
+ if (!isLinkedInCOF(item_id))
+ {
+ LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy();
+ LLAppearanceMgr::addCOFItemLink(item_id, cb); // Add COF link for item.
+ }
}
else
{
@@ -3610,22 +3833,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 +3864,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
@@ -3794,7 +4004,7 @@ public:
LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
- gAgent.setGenderChosen(TRUE);
+ gAgent.setOutfitChosen(TRUE);
}
// release avatar picker keyboard focus
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 46252afbde..2a882fd977 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,17 @@ 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);
+ bool isLinkedInCOF(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 +163,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 +182,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 +194,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 +235,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 +275,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..457ee6916d 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);
}
@@ -445,58 +450,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);
}
-LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type,
- LLBakedUploadData * baked_upload_data) :
- LLAssetUploadResponder(post_data, vfile_id, asset_type),
- mBakedUploadData(baked_upload_data)
-{
-}
-
-LLSendTexLayerResponder::~LLSendTexLayerResponder()
-{
- // mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below
- if (mBakedUploadData)
- { // ...but delete it in the case where uploadComplete() is never called
- delete mBakedUploadData;
- mBakedUploadData = NULL;
- }
-}
-
-
-// Baked texture upload completed
-void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
-{
- LLUUID item_id = mPostData["item_id"];
-
- std::string result = content["state"];
- LLUUID new_id = content["new_asset"];
-
- llinfos << "result: " << result << " new_id: " << new_id << llendl;
- if (result == "complete"
- && mBakedUploadData != NULL)
- { // Invoke
- LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE);
- mBakedUploadData = NULL; // deleted in onTextureUploadComplete()
- }
- else
- { // Invoke the original callback with an error result
- LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
- mBakedUploadData = NULL; // deleted in onTextureUploadComplete()
- }
-}
-
-void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
-{
- llinfos << "LLSendTexLayerResponder error [status:"
- << statusNum << "]: " << content << llendl;
-
- // Invoke the original callback with an error result
- LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
- mBakedUploadData = NULL; // deleted in onTextureUploadComplete()
-}
-
LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
const LLSD& post_data,
const LLUUID& vfile_id,
@@ -1009,19 +962,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 +978,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 +1001,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 +1045,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..7fbebc7481 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(
@@ -109,24 +116,6 @@ private:
Impl* mImpl;
};
-struct LLBakedUploadData;
-class LLSendTexLayerResponder : public LLAssetUploadResponder
-{
- LOG_CLASS(LLSendTexLayerResponder);
-public:
- LLSendTexLayerResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type,
- LLBakedUploadData * baked_upload_data);
-
- ~LLSendTexLayerResponder();
-
- virtual void uploadComplete(const LLSD& content);
- virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content);
-
- LLBakedUploadData * mBakedUploadData;
-};
-
class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder
{
public:
diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp
index 9a8cd5ceae..3a88bab3b3 100755
--- a/indra/newview/llbreastmotion.cpp
+++ b/indra/newview/llbreastmotion.cpp
@@ -340,8 +340,7 @@ BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask)
if (mBreastParamsDriven[i])
{
mCharacter->setVisualParamWeight(mBreastParamsDriven[i],
- new_local_pt[i],
- FALSE);
+ new_local_pt[i]);
}
}
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/llemote.cpp b/indra/newview/llemote.cpp
index 510ff69acf..b9ef297c00 100755
--- a/indra/newview/llemote.cpp
+++ b/indra/newview/llemote.cpp
@@ -79,13 +79,13 @@ BOOL LLEmote::onActivate()
LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );
if( default_param )
{
- default_param->setWeight( default_param->getMaxWeight(), FALSE );
+ default_param->setWeight( default_param->getMaxWeight());
}
mParam = mCharacter->getVisualParam(mName.c_str());
if (mParam)
{
- mParam->setWeight(0.f, FALSE);
+ mParam->setWeight(0.f);
mCharacter->updateVisualParams();
}
@@ -101,7 +101,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)
if( mParam )
{
F32 weight = mParam->getMinWeight() + mPose.getWeight() * (mParam->getMaxWeight() - mParam->getMinWeight());
- mParam->setWeight(weight, FALSE);
+ mParam->setWeight(weight);
// Cross fade against the default parameter
LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );
@@ -110,7 +110,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)
F32 default_param_weight = default_param->getMinWeight() +
(1.f - mPose.getWeight()) * ( default_param->getMaxWeight() - default_param->getMinWeight() );
- default_param->setWeight( default_param_weight, FALSE );
+ default_param->setWeight( default_param_weight);
}
mCharacter->updateVisualParams();
@@ -127,13 +127,13 @@ void LLEmote::onDeactivate()
{
if( mParam )
{
- mParam->setWeight( mParam->getDefaultWeight(), FALSE );
+ mParam->setWeight( mParam->getDefaultWeight());
}
LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );
if( default_param )
{
- default_param->setWeight( default_param->getMaxWeight(), FALSE );
+ default_param->setWeight( default_param->getMaxWeight());
}
mCharacter->updateVisualParams();
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..2f7f98ec7b 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;
}
@@ -260,7 +261,7 @@ namespace
}
// was llinfos but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
- lldebugs << "LLEventPollResponder::completed <" << mCount << "> " << events.size() << "events (id "
+ lldebugs << "LLEventPollResponder::httpSuccess <" << mCount << "> " << events.size() << "events (id "
<< LLSDXMLStreamer(mAcknowledge) << ")" << llendl;
LLSD::array_const_iterator i = events.beginArray();
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
index 611d18d6d6..ffcf3c076a 100644
--- a/indra/newview/llfacebookconnect.cpp
+++ b/indra/newview/llfacebookconnect.cpp
@@ -110,28 +110,36 @@ public:
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
}
- virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ /* virtual */ void httpSuccess()
{
- if (isGoodStatus(status))
+ LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
+ }
+
+ /* virtual */ void httpFailure()
+ {
+ if ( HTTP_FOUND == getStatus() )
{
- LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL;
-
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
+ const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse()
+ << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+ }
+ else
+ {
+ LLFacebookConnect::instance().openFacebookWeb(location);
+ }
}
- else if (status != 302)
+ else
{
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
- log_facebook_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description"));
+ LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
+ const LLSD& content = getContent();
+ log_facebook_connect_error("Connect", getStatus(), getReason(),
+ content.get("error_code"), content.get("error_description"));
}
}
-
- void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- if (status == 302)
- {
- LLFacebookConnect::instance().openFacebookWeb(content["location"]);
- }
- }
};
///////////////////////////////////////////////////////////////////////////////
@@ -145,34 +153,42 @@ public:
{
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING);
}
-
- virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+
+ /* virtual */ void httpSuccess()
{
- if (isGoodStatus(status))
+ toast_user_for_success();
+ LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED);
+ }
+
+ /* virtual */ void httpFailure()
+ {
+ if ( HTTP_FOUND == getStatus() )
{
- toast_user_for_success();
- LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL;
-
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED);
+ const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse()
+ << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+ }
+ else
+ {
+ LLFacebookConnect::instance().openFacebookWeb(location);
+ }
}
- else if (status == 404)
+ else if ( HTTP_NOT_FOUND == getStatus() )
{
LLFacebookConnect::instance().connectToFacebook();
}
else
{
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED);
- log_facebook_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description"));
+ LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED);
+ const LLSD& content = getContent();
+ log_facebook_connect_error("Share", getStatus(), getReason(),
+ content.get("error_code"), content.get("error_description"));
}
}
-
- void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- if (status == 302)
- {
- LLFacebookConnect::instance().openFacebookWeb(content["location"]);
- }
- }
};
///////////////////////////////////////////////////////////////////////////////
@@ -196,24 +212,27 @@ public:
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
}
- virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ /* virtual */ void httpSuccess()
{
- if (isGoodStatus(status))
- {
- LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL;
- setUserDisconnected();
+ LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL;
+ setUserDisconnected();
+ }
- }
+ /* virtual */ void httpFailure()
+ {
//User not found so already disconnected
- else if(status == 404)
+ if ( HTTP_NOT_FOUND == getStatus() )
{
- LL_DEBUGS("FacebookConnect") << "Already disconnected. content: " << content << LL_ENDL;
+ LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;
setUserDisconnected();
}
else
{
+ LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED);
- log_facebook_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description"));
+ const LLSD& content = getContent();
+ log_facebook_connect_error("Disconnect", getStatus(), getReason(),
+ content.get("error_code"), content.get("error_description"));
}
}
};
@@ -229,34 +248,35 @@ public:
{
LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
}
-
- virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+
+ /* virtual */ void httpSuccess()
+ {
+ LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
+ }
+
+ /* virtual */ void httpFailure()
{
- if (isGoodStatus(status))
+ // show the facebook login page if not connected yet
+ if ( HTTP_NOT_FOUND == getStatus() )
{
- LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL;
-
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
+ LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL;
+ if (mAutoConnect)
+ {
+ LLFacebookConnect::instance().connectToFacebook();
+ }
+ else
+ {
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
+ }
}
else
{
- // show the facebook login page if not connected yet
- if (status == 404)
- {
- if (mAutoConnect)
- {
- LLFacebookConnect::instance().connectToFacebook();
- }
- else
- {
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
- }
- }
- else
- {
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED);
- log_facebook_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description"));
- }
+ LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED);
+ const LLSD& content = getContent();
+ log_facebook_connect_error("Connected", getStatus(), getReason(),
+ content.get("error_code"), content.get("error_description"));
}
}
@@ -271,25 +291,34 @@ class LLFacebookInfoResponder : public LLHTTPClient::Responder
LOG_CLASS(LLFacebookInfoResponder);
public:
- virtual void completed(U32 status, const std::string& reason, const LLSD& info)
+ /* virtual */ void httpSuccess()
{
- if (isGoodStatus(status))
- {
- llinfos << "Facebook: Info received" << llendl;
- LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << info << LL_ENDL;
- LLFacebookConnect::instance().storeInfo(info);
- }
- else
- {
- log_facebook_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description"));
- }
+ LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL;
+ LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().storeInfo(getContent());
}
- void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ /* virtual */ void httpFailure()
{
- if (status == 302)
+ if ( HTTP_FOUND == getStatus() )
{
- LLFacebookConnect::instance().openFacebookWeb(content["location"]);
+ const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse()
+ << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+ }
+ else
+ {
+ LLFacebookConnect::instance().openFacebookWeb(location);
+ }
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
+ const LLSD& content = getContent();
+ log_facebook_connect_error("Info", getStatus(), getReason(),
+ content.get("error_code"), content.get("error_description"));
}
}
};
@@ -300,27 +329,36 @@ class LLFacebookFriendsResponder : public LLHTTPClient::Responder
{
LOG_CLASS(LLFacebookFriendsResponder);
public:
+
+ /* virtual */ void httpSuccess()
+ {
+ LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL;
+ LLFacebookConnect::instance().storeContent(getContent());
+ }
- virtual void completed(U32 status, const std::string& reason, const LLSD& content)
+ /* virtual */ void httpFailure()
{
- if (isGoodStatus(status))
+ if ( HTTP_FOUND == getStatus() )
{
- LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. content: " << content << LL_ENDL;
- LLFacebookConnect::instance().storeContent(content);
+ const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse()
+ << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
+ }
+ else
+ {
+ LLFacebookConnect::instance().openFacebookWeb(location);
+ }
}
else
{
- log_facebook_connect_error("Friends", status, reason, content.get("error_code"), content.get("error_description"));
+ LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
+ const LLSD& content = getContent();
+ log_facebook_connect_error("Friends", getStatus(), getReason(),
+ content.get("error_code"), content.get("error_description"));
}
}
-
- void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- if (status == 302)
- {
- LLFacebookConnect::instance().openFacebookWeb(content["location"]);
- }
- }
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index c47618e1ec..ae4d4d5ef6 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"
@@ -610,6 +611,7 @@ bool LLFeatureManager::parseGPUTable(std::string filename)
// responder saves table into file
class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
{
+ LOG_CLASS(LLHTTPFeatureTableResponder);
public:
LLHTTPFeatureTableResponder(std::string filename) :
@@ -618,11 +620,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
@@ -641,7 +642,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 c151b51c23..1f6a0b6052 100755
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -1072,9 +1072,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;
@@ -1082,13 +1082,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)");
}
@@ -1126,7 +1126,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:
@@ -1151,6 +1151,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 19cec55837..f70258e644 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -5856,7 +5856,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));
@@ -5932,7 +5932,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 66bf49331b..eb0a201e69 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 9d703d2752..3e3ac7eb90 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 "llfacebookconnect.h"
#include "lllayoutstack.h"
#include "llpluginclassmedia.h"
@@ -240,9 +241,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);
@@ -484,7 +485,7 @@ void LLFloaterWebContent::onEnterAddress()
LLStringUtil::trim(url);
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 9ffbd1a675..9ba0a184a5 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 80ef506272..3877f9f040 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/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 9db175ec2e..6042ab996d 100755
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -465,38 +465,6 @@ void LLInventoryFetchComboObserver::startFetch()
mFetchDescendents->startFetch();
}
-void LLInventoryExistenceObserver::watchItem(const LLUUID& id)
-{
- if (id.notNull())
- {
- mMIA.push_back(id);
- }
-}
-
-void LLInventoryExistenceObserver::changed(U32 mask)
-{
- // scan through the incomplete items and move or erase them as
- // appropriate.
- if (!mMIA.empty())
- {
- for (uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); )
- {
- LLViewerInventoryItem* item = gInventory.getItem(*it);
- if (!item)
- {
- ++it;
- continue;
- }
- mExist.push_back(*it);
- it = mMIA.erase(it);
- }
- if (mMIA.empty())
- {
- done();
- }
- }
-}
-
void LLInventoryAddItemByAssetObserver::changed(U32 mask)
{
if(!(mask & LLInventoryObserver::ADD))
@@ -633,58 +601,6 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask)
}
}
-
-LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) :
- mTransactionID(transaction_id)
-{
-}
-
-void LLInventoryTransactionObserver::changed(U32 mask)
-{
- if (mask & LLInventoryObserver::ADD)
- {
- // This could be it - see if we are processing a bulk update
- LLMessageSystem* msg = gMessageSystem;
- if (msg->getMessageName()
- && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory")))
- {
- // we have a match for the message - now check the
- // transaction id.
- LLUUID id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id);
- if (id == mTransactionID)
- {
- // woo hoo, we found it
- uuid_vec_t folders;
- uuid_vec_t items;
- S32 count;
- count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
- S32 i;
- for (i = 0; i < count; ++i)
- {
- msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i);
- if (id.notNull())
- {
- folders.push_back(id);
- }
- }
- count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
- for (i = 0; i < count; ++i)
- {
- msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i);
- if (id.notNull())
- {
- items.push_back(id);
- }
- }
-
- // call the derived class the implements this method.
- done(folders, items);
- }
- }
- }
-}
-
void LLInventoryCategoriesObserver::changed(U32 mask)
{
if (!mCategoryMap.size())
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index aa1eae84d7..73288242eb 100755
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -152,25 +152,6 @@ protected:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInventoryExistenceObserver
-//
-// Used as a base class for doing something when all the
-// observed item ids exist in the inventory somewhere.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLInventoryExistenceObserver : public LLInventoryObserver
-{
-public:
- LLInventoryExistenceObserver() {}
- /*virtual*/ void changed(U32 mask);
-
- void watchItem(const LLUUID& id);
-protected:
- virtual void done() = 0;
- uuid_vec_t mExist;
- uuid_vec_t mMIA;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryMovedObserver
//
// This class is used as a base class for doing something when all the
@@ -241,25 +222,6 @@ protected:
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInventoryTransactionObserver
-//
-// Base class for doing something when an inventory transaction completes.
-// NOTE: This class is not quite complete. Avoid using unless you fix up its
-// functionality gaps.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-class LLInventoryTransactionObserver : public LLInventoryObserver
-{
-public:
- LLInventoryTransactionObserver(const LLTransactionID& transaction_id);
- /*virtual*/ void changed(U32 mask);
-
-protected:
- virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0;
-
- LLTransactionID mTransactionID;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryCompletionObserver
//
// Base class for doing something when when all observed items are locally
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 2d9385390b..88fe389c55 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -540,7 +540,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp
{
U32 index = gAgentWearables.getWearableIndex(wearable);
gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
- gAgentAvatarp->wearableUpdated(type, FALSE);
+ gAgentAvatarp->wearableUpdated(type);
/* telling the manager to rebake once update cycle is fully done */
LLLocalBitmapMgr::setNeedsRebake();
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 2e02805c02..ff4d96eb54 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;
@@ -299,14 +300,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 LLMeshDecompositionResponder : public LLCurl::Responder
{
+ LOG_CLASS(LLMeshDecompositionResponder);
public:
LLUUID mMeshID;
U32 mRequestedBytes;
@@ -331,14 +332,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 LLMeshPhysicsShapeResponder : public LLCurl::Responder
{
+ LOG_CLASS(LLMeshPhysicsShapeResponder);
public:
LLUUID mMeshID;
U32 mRequestedBytes;
@@ -363,8 +364,7 @@ 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);
};
@@ -420,6 +420,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;
@@ -443,21 +444,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();
@@ -470,13 +470,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());
}
}
}
@@ -485,6 +486,7 @@ public:
class LLWholeModelUploadResponder: public LLCurl::Responder
{
+ LOG_CLASS(LLWholeModelUploadResponder);
LLMeshUploadThread* mThread;
LLSD mModelData;
LLHandle<LLWholeModelUploadObserver> mObserverHandle;
@@ -509,11 +511,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");
@@ -525,7 +526,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";
@@ -538,9 +539,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)
{
@@ -829,7 +830,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())
@@ -911,7 +912,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())
@@ -992,7 +993,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())
@@ -1073,7 +1074,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())
@@ -1148,7 +1149,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())
@@ -1919,10 +1920,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
@@ -1933,9 +1934,10 @@ 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)
@@ -1948,8 +1950,8 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
}
else
{
+ llwarns << "Unhandled status " << dumpResponse() << llendl;
llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
- llwarns << "Unhandled status " << status << llendl;
}
return;
}
@@ -1983,10 +1985,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
@@ -1997,9 +1999,10 @@ 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)
@@ -2012,8 +2015,8 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason
}
else
{
+ llwarns << "Unhandled status " << dumpResponse() << llendl;
llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
- llwarns << "Unhandled status " << status << llendl;
}
return;
}
@@ -2047,10 +2050,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 )
@@ -2060,9 +2063,10 @@ 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)
@@ -2075,8 +2079,8 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r
}
else
{
+ llwarns << "Unhandled status " << dumpResponse() << llendl;
llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
- llwarns << "Unhandled status " << status << llendl;
}
return;
}
@@ -2110,10 +2114,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
@@ -2124,9 +2128,10 @@ 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)
@@ -2139,8 +2144,8 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re
}
else
{
+ llwarns << "Unhandled status " << dumpResponse() << llendl;
llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
- llwarns << "Unhandled status " << status << llendl;
}
return;
}
@@ -2174,10 +2179,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
@@ -2186,6 +2191,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
@@ -2199,8 +2205,6 @@ 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 == HTTP_NOT_FOUND || status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_REQUEST_TIME_OUT || status == HTTP_INTERNAL_ERROR);
-
if (status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_REQUEST_TIME_OUT || status == HTTP_INTERNAL_ERROR)
{ //retry
llwarns << "Timeout or service unavailable, retrying." << llendl;
@@ -2213,7 +2217,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
}
else
{
- llwarns << "Unhandled status: " << status << llendl;
+ llwarns << "Unhandled status " << dumpResponse() << llendl;
}
}
@@ -2235,9 +2239,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..d1864c2c4b 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -943,11 +943,11 @@ void LLPanelEditWearable::onCommitSexChange()
LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index);
if (wearable)
{
- wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE);
+ wearable->setVisualParamWeight(param->getID(), is_new_sex_male);
}
- param->setWeight( is_new_sex_male, FALSE );
+ param->setWeight( is_new_sex_male);
- gAgentAvatarp->updateSexDependentLayerSets( FALSE );
+ gAgentAvatarp->updateSexDependentLayerSets();
gAgentAvatarp->updateVisualParams();
@@ -982,7 +982,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
U32 index = gAgentWearables.getWearableIndex(getWearable());
gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
LLVisualParamHint::requestHintUpdates();
- gAgentAvatarp->wearableUpdated(type, FALSE);
+ gAgentAvatarp->wearableUpdated(type);
}
}
else
@@ -1006,9 +1006,9 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)
const LLColor4& new_color = LLColor4(ctrl->getValue());
if( old_color != new_color )
{
- getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE);
+ getWearable()->setClothesColor(entry->mTextureIndex, new_color);
LLVisualParamHint::requestHintUpdates();
- gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType());
}
}
else
@@ -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, new_name);
}
@@ -1120,7 +1122,7 @@ void LLPanelEditWearable::revertChanges()
mNameEditor->setText(mWearableItem->getName());
updatePanelPickerControls(mWearablePtr->getType());
updateTypeSpecificControls(mWearablePtr->getType());
- gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE);
+ gAgentAvatarp->wearableUpdated(mWearablePtr->getType());
}
void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BOOL disable_camera_switch)
@@ -1582,7 +1584,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
U32 index = gAgentWearables.getWearableIndex(getWearable());
gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
- gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType());
}
else
{
@@ -1599,7 +1601,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
U32 index = gAgentWearables.getWearableIndex(getWearable());
gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
- gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
+ gAgentAvatarp->wearableUpdated(getWearable()->getType());
}
updatePanelPickerControls(getWearable()->getType());
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/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index 18b85cc9c3..8746f58f55 100755
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -668,9 +668,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)
if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
(driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
{
- mCharacter->setVisualParamWeight(driver_param,
- 0,
- FALSE);
+ mCharacter->setVisualParamWeight(driver_param, 0);
}
S32 num_driven = driver_param->getDrivenParamsCount();
for (S32 i = 0; i < num_driven; ++i)
@@ -770,7 +768,5 @@ void LLPhysicsMotion::setParamValue(const LLViewerVisualParam *param,
// Scale from [0,1] to [value_min_local,value_max_local]
const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled;
- mCharacter->setVisualParamWeight(param,
- new_value_local,
- FALSE);
+ mCharacter->setVisualParamWeight(param, new_value_local);
}
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/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp
index a7e24b86b1..bfa453a0ae 100755
--- a/indra/newview/llscrollingpanelparam.cpp
+++ b/indra/newview/llscrollingpanelparam.cpp
@@ -266,7 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )
if (slider->getMinValue() < new_percent
&& new_percent < slider->getMaxValue())
{
- mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE);
+ mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight);
mWearable->writeToAvatar(gAgentAvatarp);
gAgentAvatarp->updateVisualParams();
@@ -299,7 +299,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )
if (slider->getMinValue() < new_percent
&& new_percent < slider->getMaxValue())
{
- self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE);
+ self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);
self->mWearable->writeToAvatar(gAgentAvatarp);
slider->setValue( self->weightToPercent( new_weight ) );
}
@@ -333,7 +333,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )
if (slider->getMinValue() < new_percent
&& new_percent < slider->getMaxValue())
{
- self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE);
+ self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);
self->mWearable->writeToAvatar(gAgentAvatarp);
slider->setValue( self->weightToPercent( new_weight ) );
}
diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp
index 8e083ddb6c..fe7a362723 100755
--- a/indra/newview/llscrollingpanelparambase.cpp
+++ b/indra/newview/llscrollingpanelparambase.cpp
@@ -93,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata)
F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );
if (current_weight != new_weight )
{
- self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE );
+ self->mWearable->setVisualParamWeight( param->getID(), new_weight);
self->mWearable->writeToAvatar(gAgentAvatarp);
gAgentAvatarp->updateVisualParams();
}
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..61d0855119 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();
@@ -2018,7 +2020,7 @@ bool idle_startup()
{
display_startup();
F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY;
-
+
// We now have an inventory skeleton, so if this is a user's first
// login, we can start setting up their clothing and avatar
// appearance. This helps to avoid the generic "Ruth" avatar in
@@ -2027,20 +2029,43 @@ bool idle_startup()
&& !sInitialOutfit.empty() // registration set up an outfit
&& !sInitialOutfitGender.empty() // and a gender
&& isAgentAvatarValid() // can't wear clothes without object
- && !gAgent.isGenderChosen() ) // nothing already loading
+ && !gAgent.isOutfitChosen()) // nothing already loading
{
// Start loading the wearables, textures, gestures
LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender );
}
+ // If not first login, we need to fetch COF contents and
+ // compute appearance from that.
+ if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen())
+ {
+ gAgentWearables.notifyLoadingStarted();
+ callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(),
+ boost::bind(&LLAppearanceMgr::updateAppearanceFromCOF,
+ LLAppearanceMgr::getInstance(), true, true, no_op));
+ LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
+ gAgent.setOutfitChosen(TRUE);
+ gAgentWearables.sendDummyAgentWearablesUpdate();
+ }
display_startup();
// wait precache-delay and for agent's avatar or a lot longer.
- if(((timeout_frac > 1.f) && isAgentAvatarValid())
- || (timeout_frac > 3.f))
+ if ((timeout_frac > 1.f) && isAgentAvatarValid())
{
LLStartUp::setStartupState( STATE_WEARABLES_WAIT );
}
+ else if (timeout_frac > 10.f)
+ {
+ // If we exceed the wait above while isAgentAvatarValid is
+ // not true yet, we will change startup state and
+ // eventually (once avatar does get created) wind up at
+ // the gender chooser. This should occur only in very
+ // unusual circumstances, so set the timeout fairly high
+ // to minimize mistaken hits here.
+ llwarns << "Wait for valid avatar state exceeded "
+ << timeout.getElapsedTimeF32() << " will invoke gender chooser" << llendl;
+ LLStartUp::setStartupState( STATE_WEARABLES_WAIT );
+ }
else
{
update_texture_fetch();
@@ -2060,11 +2085,11 @@ bool idle_startup()
const F32 wearables_time = wearables_timer.getElapsedTimeF32();
const F32 MAX_WEARABLES_TIME = 10.f;
- if (!gAgent.isGenderChosen() && isAgentAvatarValid())
+ if (!gAgent.isOutfitChosen() && isAgentAvatarValid())
{
- // No point in waiting for clothing, we don't even
- // know what gender we are. Pop a dialog to ask and
- // proceed to draw the world. JC
+ // No point in waiting for clothing, we don't even know
+ // what outfit we want. Pop up a gender chooser dialog to
+ // ask and proceed to draw the world. JC
//
// *NOTE: We might hit this case even if we have an
// initial outfit, but if the load hasn't started
@@ -2078,9 +2103,9 @@ bool idle_startup()
display_startup();
- if (wearables_time > MAX_WEARABLES_TIME)
+ if (gAgent.isOutfitChosen() && (wearables_time > MAX_WEARABLES_TIME))
{
- LLNotificationsUtil::add("ClothingLoading");
+ llwarns << "wearables_time " << wearables_time << "exceeded max wait of " << MAX_WEARABLES_TIME << llendl;
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG);
LLStartUp::setStartupState( STATE_CLEANUP );
return TRUE;
@@ -2092,7 +2117,7 @@ bool idle_startup()
if (isAgentAvatarValid()
&& gAgentAvatarp->isFullyLoaded())
{
- //llinfos << "avatar fully loaded" << llendl;
+ LL_DEBUGS("Avatar") << "avatar fully loaded" << llendl;
LLStartUp::setStartupState( STATE_CLEANUP );
return TRUE;
}
@@ -2103,7 +2128,7 @@ bool idle_startup()
if ( gAgentWearables.areWearablesLoaded() )
{
// We have our clothing, proceed.
- //llinfos << "wearables loaded" << llendl;
+ LL_DEBUGS("Avatar") << "wearables loaded" << llendl;
LLStartUp::setStartupState( STATE_CLEANUP );
return TRUE;
}
@@ -2368,8 +2393,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)
msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
- msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse);
- msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);
msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);
msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties);
@@ -2443,9 +2466,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)
// msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,
// LLFloaterRate::processReputationIndividualReply);
- msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate,
- LLAgentWearables::processAgentInitialWearablesUpdate );
-
msg->setHandlerFunc("ScriptControlChange",
LLAgent::processScriptControlChange );
@@ -2602,9 +2622,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
lldebugs << "initial outfit category id: " << cat_id << llendl;
}
- // This is really misnamed -- it means we have started loading
- // an outfit/shape that will give the avatar a gender eventually. JC
- gAgent.setGenderChosen(TRUE);
+ gAgent.setOutfitChosen(TRUE);
+ gAgentWearables.sendDummyAgentWearablesUpdate();
}
//static
@@ -2617,10 +2636,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);
}
@@ -3365,7 +3384,11 @@ bool process_login_success_response()
flag = login_flags["gendered"].asString();
if(flag == "Y")
{
- gAgent.setGenderChosen(TRUE);
+ // We don't care about this flag anymore; now base whether
+ // outfit is chosen on COF contents, initial outfit
+ // requested and available, etc.
+
+ //gAgent.setGenderChosen(TRUE);
}
bool pacific_daylight_time = 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/lltextureview.cpp b/indra/newview/lltextureview.cpp
index e80136b286..dea1c6c1b2 100755
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -431,15 +431,7 @@ void LLAvatarTexBar::draw()
if (!layerset_buffer) continue;
LLColor4 text_color = LLColor4::white;
-
- if (layerset_buffer->uploadNeeded())
- {
- text_color = LLColor4::red;
- }
- if (layerset_buffer->uploadInProgress())
- {
- text_color = LLColor4::magenta;
- }
+
std::string text = layerset_buffer->dumpTextureInfo();
LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num,
text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 148e5a015b..2d458db36b 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);
+ mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight);
+ gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight);
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();
@@ -238,7 +246,13 @@ BOOL LLVisualParamHint::render()
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
}
gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
- mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE);
+ mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
+ 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 100644
--- 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..b6a5534815 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,392 @@ 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 and/or shadow_id with transaction_id (hash_id)
+ if (updates.has("asset_id"))
+ {
+ updates.erase("asset_id");
+ updates["hash_id"] = update_item->getTransactionID();
+ }
+ if (updates.has("shadow_id"))
+ {
+ updates.erase("shadow_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 +1726,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 +2208,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 13483790ed..139e3c3a2d 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);
}
}
@@ -2648,16 +2642,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/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ac2940fcfc..2b1c106932 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7818,6 +7818,7 @@ void handle_buy_currency_test(void*)
LLFloaterReg::showInstance("buy_currency_html", LLSD(url));
}
+// SUNSHINE CLEANUP - is only the request update at the end needed now?
void handle_rebake_textures(void*)
{
if (!isAgentAvatarValid()) return;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ab9ea5618e..167c33f3ff 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3984,6 +3984,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
@@ -4099,10 +4101,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL );
- // set the appearance on teleport since the new sim does not
- // know what you look like.
- gAgent.sendAgentSetAppearance();
-
if (isAgentAvatarValid())
{
// Chat the "back" SLURL. (DEV-4907)
@@ -4238,6 +4236,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 7151a0d6ed..10b05c9af4 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -57,6 +57,7 @@
#include "llaudiosourcevo.h"
#include "llagent.h"
#include "llagentcamera.h"
+#include "llagentwearables.h"
#include "llbbox.h"
#include "llbox.h"
#include "llcylinder.h"
@@ -140,6 +141,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
{
gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp);
gAgentAvatarp->initInstance();
+ gAgentWearables.setAvatarObject(gAgentAvatarp);
}
else
{
@@ -5281,6 +5283,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 b035473c74..1a73dc48e6 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -412,6 +412,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 b4e287c446..7cac4ee891 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 460f9084d9..b8300ac5eb 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"
@@ -76,6 +77,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.
@@ -88,6 +94,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)
@@ -144,7 +152,7 @@ public:
CapabilityMap mCapabilities;
CapabilityMap mSecondCapabilitiesTracker;
-
+
LLEventPoll* mEventPoll;
S32 mSeedCapMaxAttempts;
@@ -205,24 +213,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
{
@@ -235,11 +249,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;
@@ -258,11 +278,6 @@ public:
}
}
- static BaseCapabilitiesComplete* build( U64 region_handle, S32 id )
- {
- return new BaseCapabilitiesComplete(region_handle, id);
- }
-
private:
U64 mRegionHandle;
S32 mID;
@@ -279,19 +294,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)
{
@@ -301,32 +329,46 @@ public:
if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )
{
- llinfos << "BaseCapabilitiesCompleteTracker " << "sim " << regionp->getName()
- << " sent duplicate seed caps that differs in size - most likely content. "
- << (S32) regionp->getRegionImpl()->mCapabilities.size() << " vs " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size()
- << 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;
};
@@ -346,7 +388,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
mSimAccess( SIM_ACCESS_MIN ),
mBillableFactor(1.0),
mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT),
- mCentralBakeVersion(0),
+ mCentralBakeVersion(1),
mClassID(0),
mCPURatio(0),
mColoName("unknown"),
@@ -1577,7 +1619,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);
}
@@ -1599,12 +1645,13 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
//capabilityNames.append("FacebookRedirect");
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");
@@ -1618,7 +1665,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");
@@ -1629,7 +1676,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");
@@ -1659,7 +1705,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("ViewerMetrics");
capabilityNames.append("ViewerStartAuction");
capabilityNames.append("ViewerStats");
-
+
// Please add new capabilities alphabetically to reduce
// merge conflicts.
}
@@ -1667,8 +1713,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();
@@ -1741,31 +1789,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)
@@ -1775,7 +1829,7 @@ private:
LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
}
}
-
+
std::string mRetryURL;
U64 mRegionHandle;
S32 mAttempt;
@@ -1812,7 +1866,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)
@@ -1824,7 +1887,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);
@@ -1836,6 +1899,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;
@@ -1863,16 +1942,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)
@@ -1955,7 +2025,21 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const
return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") &&
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;
+}
void LLViewerRegion::resetMaterialsCapThrottle()
{
F32 requests_per_sec = 1.0f; // original default;
@@ -2000,3 +2084,4 @@ U32 LLViewerRegion::getMaxMaterialsPerTransaction() const
}
+
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 8f8bfa23c1..17ee524853 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -50,6 +50,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;
@@ -243,6 +245,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..f0c4d4ef3d 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..f20ab48fab 100755
--- a/indra/newview/llviewertexlayer.cpp
+++ b/indra/newview/llviewertexlayer.cpp
@@ -37,7 +37,6 @@
#include "llglslshader.h"
#include "llvoavatarself.h"
#include "pipeline.h"
-#include "llassetuploadresponders.h"
#include "llviewercontrol.h"
static const S32 BAKE_UPLOAD_ATTEMPTS = 7;
@@ -46,22 +45,6 @@ static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power o
// runway consolidate
extern std::string self_av_string();
-
-//-----------------------------------------------------------------------------
-// LLBakedUploadData()
-//-----------------------------------------------------------------------------
-LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar,
- LLViewerTexLayerSet* layerset,
- const LLUUID& id,
- bool highest_res) :
- mAvatar(avatar),
- mTexLayerSet(layerset),
- mID(id),
- mStartTime(LLFrameTimer::getTotalTime()), // Record starting time
- mIsHighestRes(highest_res)
-{
-}
-
//-----------------------------------------------------------------------------
// LLViewerTexLayerSetBuffer
// The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one.
@@ -75,15 +58,10 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner,
// ORDER_LAST => must render these after the hints are created.
LLTexLayerSetBuffer(owner),
LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ),
- mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates
- mNeedsUpload(FALSE),
- mNumLowresUploads(0),
- mUploadFailCount(0),
mNeedsUpdate(TRUE),
mNumLowresUpdates(0)
{
LLViewerTexLayerSetBuffer::sGLByteCount += getSize();
- mNeedsUploadTimer.start();
mNeedsUpdateTimer.start();
}
@@ -126,33 +104,6 @@ void LLViewerTexLayerSetBuffer::requestUpdate()
restartUpdateTimer();
mNeedsUpdate = TRUE;
mNumLowresUpdates = 0;
- // If we're in the middle of uploading a baked texture, we don't care about it any more.
- // When it's downloaded, ignore it.
- mUploadID.setNull();
-}
-
-void LLViewerTexLayerSetBuffer::requestUpload()
-{
- conditionalRestartUploadTimer();
- mNeedsUpload = TRUE;
- mNumLowresUploads = 0;
- mUploadPending = TRUE;
-}
-
-void LLViewerTexLayerSetBuffer::conditionalRestartUploadTimer()
-{
- // If we requested a new upload but haven't even uploaded
- // a low res version of our last upload request, then
- // keep the timer ticking instead of resetting it.
- if (mNeedsUpload && (mNumLowresUploads == 0))
- {
- mNeedsUploadTimer.unpause();
- }
- else
- {
- mNeedsUploadTimer.reset();
- mNeedsUploadTimer.start();
- }
}
void LLViewerTexLayerSetBuffer::restartUpdateTimer()
@@ -161,25 +112,16 @@ void LLViewerTexLayerSetBuffer::restartUpdateTimer()
mNeedsUpdateTimer.start();
}
-void LLViewerTexLayerSetBuffer::cancelUpload()
-{
- mNeedsUpload = FALSE;
- mUploadPending = FALSE;
- mNeedsUploadTimer.pause();
- mUploadRetryTimer.reset();
-}
-
// virtual
BOOL LLViewerTexLayerSetBuffer::needsRender()
{
llassert(mTexLayerSet->getAvatarAppearance() == gAgentAvatarp);
if (!isAgentAvatarValid()) return FALSE;
- const BOOL upload_now = mNeedsUpload && isReadyToUpload();
const BOOL update_now = mNeedsUpdate && isReadyToUpdate();
- // Don't render if we don't want to (or aren't ready to) upload or update.
- if (!(update_now || upload_now))
+ // Don't render if we don't want to (or aren't ready to) update.
+ if (!update_now)
{
return FALSE;
}
@@ -190,11 +132,10 @@ BOOL LLViewerTexLayerSetBuffer::needsRender()
return FALSE;
}
- // Don't render if we are trying to create a shirt texture but aren't wearing a skirt.
+ // Don't render if we are trying to create a skirt texture but aren't wearing a skirt.
if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED &&
!gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))
{
- cancelUpload();
return FALSE;
}
@@ -222,36 +163,7 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success)
// virtual
void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success)
{
- // do we need to upload, and do we have sufficient data to create an uploadable composite?
- // TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero?
- const BOOL upload_now = mNeedsUpload && isReadyToUpload();
const BOOL update_now = mNeedsUpdate && isReadyToUpdate();
-
- if(upload_now)
- {
- if (!success)
- {
- llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << llendl;
- mUploadPending = FALSE;
- }
- else
- {
- LLViewerTexLayerSet* layer_set = getViewerTexLayerSet();
- if (layer_set->isVisible())
- {
- layer_set->getAvatar()->debugBakedTextureUpload(layer_set->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish.
- doUpload();
- }
- else
- {
- mUploadPending = FALSE;
- mNeedsUpload = FALSE;
- mNeedsUploadTimer.pause();
- layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE);
- }
- }
- }
-
if (update_now)
{
doUpdate();
@@ -267,60 +179,6 @@ BOOL LLViewerTexLayerSetBuffer::isInitialized(void) const
return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated();
}
-BOOL LLViewerTexLayerSetBuffer::uploadPending() const
-{
- return mUploadPending;
-}
-
-BOOL LLViewerTexLayerSetBuffer::uploadNeeded() const
-{
- return mNeedsUpload;
-}
-
-BOOL LLViewerTexLayerSetBuffer::uploadInProgress() const
-{
- return !mUploadID.isNull();
-}
-
-BOOL LLViewerTexLayerSetBuffer::isReadyToUpload() const
-{
- if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries.
- if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) return FALSE; // Don't upload if avatar is being edited.
-
- BOOL ready = FALSE;
- if (getViewerTexLayerSet()->isLocalTextureDataFinal())
- {
- // If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry)
- if (mUploadFailCount == 0)
- {
- ready = TRUE;
- }
- else
- {
- ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1));
- }
- }
- else
- {
- // Upload if we've hit a timeout. Upload is a pretty expensive process so we need to make sure
- // we aren't doing uploads too frequently.
- const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout");
- if (texture_timeout != 0)
- {
- // The timeout period increases exponentially between every lowres upload in order to prevent
- // spamming the server with frequent uploads.
- const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads);
-
- // If we hit our timeout and have textures available at even lower resolution, then upload.
- const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold;
- const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable();
- ready = has_lower_lod && is_upload_textures_timeout;
- }
- }
-
- return ready;
-}
-
BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const
{
// If we requested an update and have the final LOD ready, then update.
@@ -358,159 +216,6 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate()
return result;
}
-// Create the baked texture, send it out to the server, then wait for it to come
-// back so we can switch to using it.
-void LLViewerTexLayerSetBuffer::doUpload()
-{
- LLViewerTexLayerSet* layer_set = getViewerTexLayerSet();
- LL_DEBUGS("Avatar") << "Uploading baked " << layer_set->getBodyRegionName() << llendl;
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_BAKES);
-
- // Don't need caches since we're baked now. (note: we won't *really* be baked
- // until this image is sent to the server and the Avatar Appearance message is received.)
- layer_set->deleteCaches();
-
- // Get the COLOR information from our texture
- U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ];
- glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data );
- stop_glerror();
-
- // Get the MASK information from our texture
- LLGLSUIDefault gls_ui;
- LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 );
- U8* baked_mask_data = baked_mask_image->getData();
- layer_set->gatherMorphMaskAlpha(baked_mask_data,
- mOrigin.mX, mOrigin.mY,
- mFullWidth, mFullHeight);
-
-
- // Create the baked image from our color and mask information
- const S32 baked_image_components = 5; // red green blue [bump] clothing
- LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components );
- U8* baked_image_data = baked_image->getData();
- S32 i = 0;
- for (S32 u=0; u < mFullWidth; u++)
- {
- for (S32 v=0; v < mFullHeight; v++)
- {
- baked_image_data[5*i + 0] = baked_color_data[4*i + 0];
- baked_image_data[5*i + 1] = baked_color_data[4*i + 1];
- baked_image_data[5*i + 2] = baked_color_data[4*i + 2];
- baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes.
- baked_image_data[5*i + 4] = baked_mask_data[i];
- i++;
- }
- }
-
- LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C;
- const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask)
- if (compressedImage->encode(baked_image, comment_text))
- {
- LLTransactionID tid;
- tid.generate();
- const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
- if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(),
- gVFS, asset_id, LLAssetType::AT_TEXTURE))
- {
- // Read back the file and validate.
- BOOL valid = FALSE;
- LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
- S32 file_size = 0;
- LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE);
- file_size = file.getSize();
- U8* data = integrity_test->allocateData(file_size);
- file.read(data, file_size);
- if (data)
- {
- valid = integrity_test->validate(data, file_size); // integrity_test will delete 'data'
- }
- else
- {
- integrity_test->setLastError("Unable to read entire file");
- }
-
- if (valid)
- {
- const bool highest_lod = layer_set->isLocalTextureDataFinal();
- // Baked_upload_data is owned by the responder and deleted after the request completes.
- LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp,
- layer_set,
- asset_id,
- highest_lod);
- // upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit.
- mUploadID = asset_id;
-
- // Upload the image
- const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture");
- if(!url.empty()
- && !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method
- && (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing.
- {
- LLSD body = LLSD::emptyMap();
- // The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete()
- LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data));
- llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl;
- }
- else
- {
- gAssetStorage->storeAssetData(tid,
- LLAssetType::AT_TEXTURE,
- LLViewerTexLayerSetBuffer::onTextureUploadComplete,
- baked_upload_data,
- TRUE, // temp_file
- TRUE, // is_priority
- TRUE); // store_local
- llinfos << "Baked texture upload via Asset Store." << llendl;
- }
-
- if (highest_lod)
- {
- // Sending the final LOD for the baked texture. All done, pause
- // the upload timer so we know how long it took.
- mNeedsUpload = FALSE;
- mNeedsUploadTimer.pause();
- }
- else
- {
- // Sending a lower level LOD for the baked texture. Restart the upload timer.
- mNumLowresUploads++;
- mNeedsUploadTimer.unpause();
- mNeedsUploadTimer.reset();
- }
-
- // Print out notification that we uploaded this texture.
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- const std::string lod_str = highest_lod ? "HighRes" : "LowRes";
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)layer_set->getAvatar()->debugGetExistenceTimeElapsedF32());
- args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32());
- args["BODYREGION"] = layer_set->getBodyRegionName();
- args["RESOLUTION"] = lod_str;
- LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args);
- LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << layer_set->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL;
- }
- }
- else
- {
- // The read back and validate operation failed. Remove the uploaded file.
- mUploadPending = FALSE;
- LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE);
- file.remove();
- llinfos << "Unable to create baked upload file (reason: corrupted)." << llendl;
- }
- }
- }
- else
- {
- // The VFS write file operation failed.
- mUploadPending = FALSE;
- llinfos << "Unable to create baked upload file (reason: failed to write file)" << llendl;
- }
-
- delete [] baked_color_data;
-}
-
// Mostly bookkeeping; don't need to actually "do" anything since
// render() will actually do the update.
void LLViewerTexLayerSetBuffer::doUpdate()
@@ -547,82 +252,6 @@ void LLViewerTexLayerSetBuffer::doUpdate()
}
}
-// static
-void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid,
- void* userdata,
- S32 result,
- LLExtStat ext_status) // StoreAssetData callback (not fixed)
-{
- LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata;
-
- if (isAgentAvatarValid() &&
- !gAgentAvatarp->isDead() &&
- (baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures.
- (baked_upload_data->mTexLayerSet->hasComposite()))
- {
- LLViewerTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getViewerComposite();
- S32 failures = layerset_buffer->mUploadFailCount;
- layerset_buffer->mUploadFailCount = 0;
-
- if (layerset_buffer->mUploadID.isNull())
- {
- // The upload got canceled, we should be in the
- // process of baking a new texture so request an
- // upload with the new data
-
- // BAP: does this really belong in this callback, as
- // opposed to where the cancellation takes place?
- // suspect this does nothing.
- layerset_buffer->requestUpload();
- }
- else if (baked_upload_data->mID == layerset_buffer->mUploadID)
- {
- // This is the upload we're currently waiting for.
- layerset_buffer->mUploadID.setNull();
- const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName());
- const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res ";
- if (result >= 0)
- {
- layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later
- LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet());
- // Update baked texture info with the new UUID
- U64 now = LLFrameTimer::getTotalTime(); // Record starting time
- llinfos << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << llendl;
- gAgentAvatarp->setNewBakedTexture(baked_te, uuid);
- }
- else
- {
- ++failures;
- S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes
- llwarns << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << llendl;
- if (failures < max_attempts)
- {
- layerset_buffer->mUploadFailCount = failures;
- layerset_buffer->mUploadRetryTimer.start();
- layerset_buffer->requestUpload();
- }
- }
- }
- else
- {
- llinfos << "Received baked texture out of date, ignored." << llendl;
- }
-
- gAgentAvatarp->dirtyMesh();
- }
- else
- {
- // Baked texture failed to upload (in which case since we
- // didn't set the new baked texture, it means that they'll try
- // and rebake it at some point in the future (after login?)),
- // or this response to upload is out of date, in which case a
- // current response should be on the way or already processed.
- llwarns << "Baked upload failed" << llendl;
- }
-
- delete baked_upload_data;
-}
-
//-----------------------------------------------------------------------------
// LLViewerTexLayerSet
// An ordered set of texture layers that get composited into a single texture.
@@ -664,20 +293,6 @@ void LLViewerTexLayerSet::requestUpdate()
}
}
-void LLViewerTexLayerSet::requestUpload()
-{
- createComposite();
- getViewerComposite()->requestUpload();
-}
-
-void LLViewerTexLayerSet::cancelUpload()
-{
- if(mComposite)
- {
- getViewerComposite()->cancelUpload();
- }
-}
-
void LLViewerTexLayerSet::updateComposite()
{
createComposite();
@@ -730,19 +345,12 @@ const std::string LLViewerTexLayerSetBuffer::dumpTextureInfo() const
{
if (!isAgentAvatarValid()) return "";
- const BOOL is_high_res = !mNeedsUpload;
- const U32 num_low_res = mNumLowresUploads;
- const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32();
+ const BOOL is_high_res = TRUE;
+ const U32 num_low_res = 0;
const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(getViewerTexLayerSet());
- std::string status = "CREATING ";
- if (!uploadNeeded()) status = "DONE ";
- if (uploadInProgress()) status = "UPLOADING";
-
- std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s",
- status.c_str(),
+ std::string text = llformat("[HiRes:%d LoRes:%d] %s",
is_high_res, num_low_res,
- upload_time,
local_texture_info.c_str());
return text;
}
diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h
index 959c883da8..027ae255ec 100644..100755
--- a/indra/newview/llviewertexlayer.h
+++ b/indra/newview/llviewertexlayer.h
@@ -47,8 +47,6 @@ public:
virtual ~LLViewerTexLayerSet();
/*virtual*/void requestUpdate();
- void requestUpload();
- void cancelUpload();
BOOL isLocalTextureDataAvailable() const;
BOOL isLocalTextureDataFinal() const;
void updateComposite();
@@ -116,31 +114,6 @@ protected:
virtual BOOL render() { return renderTexLayerSet(); }
//--------------------------------------------------------------------
- // Uploads
- //--------------------------------------------------------------------
-public:
- void requestUpload();
- void cancelUpload();
- BOOL uploadNeeded() const; // We need to upload a new texture
- BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result
- BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point
- static void onTextureUploadComplete(const LLUUID& uuid,
- void* userdata,
- S32 result, LLExtStat ext_status);
-protected:
- BOOL isReadyToUpload() const;
- void doUpload(); // Does a read back and upload.
- void conditionalRestartUploadTimer();
-private:
- BOOL mNeedsUpload; // Whether we need to send our baked textures to the server
- U32 mNumLowresUploads; // Number of times we've sent a lowres version of our baked textures to the server
- BOOL mUploadPending; // Whether we have received back the new baked textures
- LLUUID mUploadID; // The current upload process (null if none).
- LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested and performed.
- S32 mUploadFailCount; // Number of consecutive upload failures
- LLFrameTimer mUploadRetryTimer; // Tracks time since last upload failure.
-
- //--------------------------------------------------------------------
// Updates
//--------------------------------------------------------------------
public:
@@ -156,25 +129,5 @@ private:
LLFrameTimer mNeedsUpdateTimer; // Tracks time since update was requested and performed.
};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// LLBakedUploadData
-//
-// Used by LLTexLayerSetBuffer for a callback.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-struct LLBakedUploadData
-{
- LLBakedUploadData(const LLVOAvatarSelf* avatar,
- LLViewerTexLayerSet* layerset,
- const LLUUID& id,
- bool highest_res);
- ~LLBakedUploadData() {}
- const LLUUID mID;
- const LLVOAvatarSelf* mAvatar; // note: backlink only; don't LLPointer
- LLViewerTexLayerSet* mTexLayerSet;
- const U64 mStartTime; // for measuring baked texture upload time
- const bool mIsHighestRes; // whether this is a "final" bake, or intermediate low res
-};
-
#endif // LL_VIEWER_TEXLAYER_H
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 84f66c359f..f22074a8d6 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
//----------------------------------------------------------------------------------------------
@@ -943,7 +964,7 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type,
mFTType = f_type;
if (mFTType == FTT_HOST_BAKE)
{
- mCanUseHTTP = false;
+ llwarns << "Unsupported fetch type " << mFTType << llendl;
}
generateGLTexture() ;
}
@@ -968,6 +989,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
{
mOrigWidth = 0;
mOrigHeight = 0;
+ mHasAux = FALSE;
mNeedsAux = FALSE;
mRequestedDiscardLevel = -1;
mRequestedDownloadPriority = 0.f;
@@ -1024,7 +1046,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
mLastReferencedSavedRawImageTime = 0.0f ;
mKeptSavedRawImageTime = 0.f ;
mLastCallBackActiveTime = 0.f;
-
+ mForceCallbackFetch = FALSE;
mInDebug = FALSE;
mFTType = FTT_UNKNOWN;
@@ -1799,9 +1821,14 @@ 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 (mAuxRawImage.notNull())
+ {
+ mHasAux = TRUE;
+ sAuxCount++;
+ }
if (finished)
{
mIsFetching = FALSE;
@@ -1862,20 +1889,34 @@ bool LLViewerFetchedTexture::updateFetch()
if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL))
{
// We finished but received no data
- if (current_discard < 0)
+ if (getDiscardLevel() < 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;
}
else
{
//llwarns << mID << ": Setting min discard to " << current_discard << llendl;
- mMinDiscardLevel = current_discard;
- desired_discard = current_discard;
+ if(current_discard >= 0)
+ {
+ mMinDiscardLevel = current_discard;
+ desired_discard = current_discard;
+ }
+ else
+ {
+ S32 dis_level = getDiscardLevel();
+ mMinDiscardLevel = dis_level;
+ desired_discard = dis_level;
+ }
}
destroyRawImage();
}
@@ -2046,29 +2087,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,
@@ -2111,10 +2166,19 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
}
if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)
{
- // We need aux data, but we've already loaded the image, and it didn't have any
- llwarns << "No aux data available for callback for image:" << getID() << llendl;
+ if(mHasAux)
+ {
+ //trigger a refetch
+ forceToRefetchTexture();
+ }
+ else
+ {
+ // We need aux data, but we've already loaded the image, and it didn't have any
+ llwarns << "No aux data available for callback for image:" << getID() << llendl;
+ }
}
mLastCallBackActiveTime = sCurrentTime ;
+ mLastReferencedSavedRawImageTime = sCurrentTime;
}
void LLViewerFetchedTexture::clearCallbackEntryList()
@@ -2227,6 +2291,7 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry:
}
mPauseLoadedCallBacks = FALSE ;
mLastCallBackActiveTime = sCurrentTime ;
+ mForceCallbackFetch = TRUE;
if(need_raw)
{
mSaveRawImage = TRUE ;
@@ -2267,6 +2332,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s
bool LLViewerFetchedTexture::doLoadedCallbacks()
{
static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds
+ static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds
if (mNeedsCreateTexture)
{
@@ -2471,6 +2537,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
}
}
+ // Done with any raw image data at this point (will be re-created if we still have callbacks)
+ destroyRawImage();
+
//
// If we have no callbacks, take us off of the image callback list.
//
@@ -2478,10 +2547,13 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
{
gTextureList.mCallbackList.erase(this);
}
+ else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching)
+ {
+ //wait for long enough but no fetching request issued, force one.
+ forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f);
+ mForceCallbackFetch = FALSE; //fire once.
+ }
- // Done with any raw image data at this point (will be re-created if we still have callbacks)
- destroyRawImage();
-
return res;
}
@@ -2563,7 +2635,7 @@ bool LLViewerFetchedTexture::needsToSaveRawImage()
void LLViewerFetchedTexture::destroyRawImage()
{
- if (mAuxRawImage.notNull())
+ if (mAuxRawImage.notNull() && !needsToSaveRawImage())
{
sAuxCount--;
mAuxRawImage = NULL;
@@ -2719,6 +2791,24 @@ void LLViewerFetchedTexture::saveRawImage()
mLastReferencedSavedRawImageTime = sCurrentTime ;
}
+//force to refetch the texture to the discard level
+void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time)
+{
+ if(mForceToSaveRawImage)
+ {
+ desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel);
+ kept_time = llmax(kept_time, mKeptSavedRawImageTime);
+ }
+
+ //trigger a new fetch.
+ mForceToSaveRawImage = TRUE ;
+ mDesiredSavedRawDiscardLevel = desired_discard ;
+ mKeptSavedRawImageTime = kept_time ;
+ mLastReferencedSavedRawImageTime = sCurrentTime ;
+ mSavedRawImage = NULL ;
+ mSavedRawDiscardLevel = -1 ;
+}
+
void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time)
{
mKeptSavedRawImageTime = kept_time ;
@@ -2766,6 +2856,12 @@ void LLViewerFetchedTexture::destroySavedRawImage()
mDesiredSavedRawDiscardLevel = -1 ;
mLastReferencedSavedRawImageTime = 0.0f ;
mKeptSavedRawImageTime = 0.f ;
+
+ if(mAuxRawImage.notNull())
+ {
+ sAuxCount--;
+ mAuxRawImage = NULL;
+ }
}
LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 10101a4b9b..7e45fcaf4b 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
@@ -383,6 +388,7 @@ public:
BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;}
BOOL isRawImageValid()const { return mIsRawImageValid ; }
void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ;
+ void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);
/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
void destroySavedRawImage() ;
LLImageRaw* getSavedRawImage() ;
@@ -402,16 +408,22 @@ 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;
BOOL mInFastCacheList;
+ BOOL mForceCallbackFetch;
protected:
std::string mLocalFileName;
@@ -439,12 +451,14 @@ protected:
S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have
S8 mNeedsAux; // We need to decode the auxiliary channels
+ S8 mHasAux; // We have aux channels
S8 mDecodingAux; // Are we decoding high components
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..143eab133d 100644..100755
--- 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();
@@ -264,7 +266,7 @@ void LLViewerWearable::setParamsToDefaults()
{
if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) )
{
- setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE);
+ setVisualParamWeight(param->getID(),param->getDefaultWeight());
}
}
}
@@ -320,16 +322,6 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)
if (!viewer_avatar->isValid()) return;
-#if 0
- // FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables.
- // Ideally would avoid calling this func in the first place.
- if (viewer_avatar->isUsingServerBakes() &&
- !viewer_avatar->isUsingLocalAppearance())
- {
- return;
- }
-#endif
-
ESex old_sex = avatarp->getSex();
LLWearable::writeToAvatar(avatarp);
@@ -359,19 +351,14 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)
ESex new_sex = avatarp->getSex();
if( old_sex != new_sex )
{
- viewer_avatar->updateSexDependentLayerSets( FALSE );
+ viewer_avatar->updateSexDependentLayerSets();
}
-
-// if( upload_bake )
-// {
-// gAgent.sendAgentSetAppearance();
-// }
}
// Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values.
// static
-void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake )
+void LLViewerWearable::removeFromAvatar( LLWearableType::EType type)
{
if (!isAgentAvatarValid()) return;
@@ -390,7 +377,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload
if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) )
{
S32 param_id = param->getID();
- gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake );
+ gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight());
}
}
@@ -400,12 +387,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload
}
gAgentAvatarp->updateVisualParams();
- gAgentAvatarp->wearableUpdated(type, FALSE);
-
-// if( upload_bake )
-// {
-// gAgent.sendAgentSetAppearance();
-// }
+ gAgentAvatarp->wearableUpdated(type);
}
// Does not copy mAssetID.
@@ -478,13 +460,6 @@ void LLViewerWearable::setItemID(const LLUUID& item_id)
void LLViewerWearable::revertValues()
{
-#if 0
- // DRANO avoid overwrite when not in local appearance
- if (isAgentAvatarValid() && gAgentAvatarp->isUsingServerBakes() && !gAgentAvatarp->isUsingLocalAppearance())
- {
- return;
- }
-#endif
LLWearable::revertValues();
@@ -522,13 +497,6 @@ void LLViewerWearable::refreshName()
}
}
-// virtual
-void LLViewerWearable::addToBakedTextureHash(LLMD5& hash) const
-{
- LLUUID asset_id = getAssetID();
- hash.update((const unsigned char*)asset_id.mData, UUID_BYTES);
-}
-
struct LLWearableSaveData
{
LLWearableType::EType mType;
diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h
index 65566f23a5..fb92bca5cc 100644..100755
--- a/indra/newview/llviewerwearable.h
+++ b/indra/newview/llviewerwearable.h
@@ -61,13 +61,15 @@ public:
BOOL isOldVersion() const;
/*virtual*/ void writeToAvatar(LLAvatarAppearance *avatarp);
- void removeFromAvatar( BOOL upload_bake ) { LLViewerWearable::removeFromAvatar( mType, upload_bake ); }
- static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake );
+ void removeFromAvatar() { LLViewerWearable::removeFromAvatar( mType); }
+ static void removeFromAvatar( LLWearableType::EType type);
/*virtual*/ EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
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;
@@ -88,14 +90,14 @@ public:
// the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem,
// not the wearable asset itself.
void refreshName();
-
- // Update the baked texture hash.
- /*virtual*/void addToBakedTextureHash(LLMD5& hash) const;
+ /*virtual*/void addToBakedTextureHash(LLMD5& hash) const {}
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 ff7642a773..78768fdbc8 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2015,7 +2015,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)
@@ -2023,7 +2023,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 fe035a0a7f..1e22593ead 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -107,7 +107,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
@@ -711,7 +711,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mLastRezzedStatus(-1),
mIsEditingAppearance(FALSE),
mUseLocalAppearance(FALSE),
- mUseServerBakes(FALSE), // FIXME DRANO consider using boost::optional, defaulting to unknown.
mLastUpdateRequestCOFVersion(-1),
mLastUpdateReceivedCOFVersion(-1)
{
@@ -721,7 +720,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job
mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
- lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl;
+ LL_DEBUGS("Avatar") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl;
mPelvisp = NULL;
@@ -813,18 +812,18 @@ 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;
+
+ LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());
mAttachmentPoints.clear();
@@ -836,7 +835,7 @@ LLVOAvatar::~LLVOAvatar()
getPhases().clearPhases();
- lldebugs << "LLVOAvatar Destructor end" << llendl;
+ LL_DEBUGS("Avatar") << "LLVOAvatar Destructor end" << llendl;
}
void LLVOAvatar::markDead()
@@ -1078,7 +1077,7 @@ void LLVOAvatar::restoreGL()
gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++)
{
- gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i), FALSE);
+ gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i));
}
gAgentAvatarp->updateMeshTextures();
}
@@ -1207,7 +1206,7 @@ void LLVOAvatar::initInstance(void)
registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create );
registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create );
}
-
+
LLAvatarAppearance::initInstance();
// preload specific motions here
@@ -1245,6 +1244,7 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet()
const LLVector3 LLVOAvatar::getRenderPosition() const
{
+
if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
{
return getPositionAgent();
@@ -1267,6 +1267,8 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
{
return getPosition() * mDrawable->getParent()->getRenderMatrix();
}
+
+
}
void LLVOAvatar::updateDrawable(BOOL force_damped)
@@ -1302,6 +1304,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)
@@ -1554,7 +1558,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
return hit;
}
-
+
LLVOAvatar* LLVOAvatar::asAvatar()
{
return this;
@@ -1889,22 +1893,21 @@ 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;
- 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;
- LLHost host = getObjectHost();
- result = LLViewerTextureManager::getFetchedTexture(
- uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
+ const std::string url = getImageURL(te,uuid);
+ if (url.empty())
+ {
+ llwarns << "unable to determine URL for te " << te << " uuid " << uuid << llendl;
+ return NULL;
+ }
+ LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << llendl;
+ result = LLViewerTextureManager::getFetchedTextureFromUrl(
+ url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
+ if (result->isMissingAsset())
+ {
+ result->setIsMissingAsset(false);
+ }
}
-}
return result;
}
@@ -2132,8 +2135,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
if ( mLipSyncActive )
{
- if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE);
- if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE);
+ if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight());
+ if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight());
mLipSyncActive = false;
LLCharacter::updateVisualParams();
@@ -2156,7 +2159,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 )
@@ -2296,14 +2299,10 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()
{
if (param->isTweakable())
{
- param->stopAnimating(FALSE);
+ param->stopAnimating();
}
}
updateVisualParams();
- if (isSelf())
- {
- gAgent.sendAgentSetAppearance();
- }
}
else
{
@@ -2319,7 +2318,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()
{
if (param->isTweakable())
{
- param->animate(morph_amt, FALSE);
+ param->animate(morph_amt);
}
}
}
@@ -2372,7 +2371,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
F32 ooh_weight = mOohMorph->getMinWeight()
+ ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight());
- mOohMorph->setWeight( ooh_weight, FALSE );
+ mOohMorph->setWeight( ooh_weight);
}
if( mAahMorph )
@@ -2380,7 +2379,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
F32 aah_weight = mAahMorph->getMinWeight()
+ aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight());
- mAahMorph->setWeight( aah_weight, FALSE );
+ mAahMorph->setWeight( aah_weight);
}
mLipSyncActive = true;
@@ -2897,6 +2896,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);
@@ -3076,7 +3077,7 @@ void LLVOAvatar::forceUpdateVisualMuteSettings()
// called on both your avatar and other avatars
//------------------------------------------------------------------------
BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
-{
+{
// clear debug text
mDebugText.clear();
@@ -3093,7 +3094,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
isSelf() ? (all_local_downloaded ? "L" : "l") : "-",
all_baked_downloaded ? "B" : "b",
mUseLocalAppearance, mIsEditingAppearance,
- mUseServerBakes, central_bake_version);
+ 1, central_bake_version);
std::string origin_string = bakedTextureOriginInfo();
debug_line += " [" + origin_string + "]";
S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion();
@@ -3592,6 +3593,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//mesh vertices need to be reskinned
mNeedsSkin = TRUE;
+
+
+
return TRUE;
}
//-----------------------------------------------------------------------------
@@ -3625,9 +3629,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;
@@ -3637,18 +3641,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;
@@ -4072,7 +4074,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;
@@ -4082,7 +4084,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
}
}
-
+
return num_indices;
}
@@ -4201,34 +4203,6 @@ bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const
return allTexturesCompletelyDownloaded(baked_ids);
}
-void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL.
- S32 &host_count, // host-based bake, has host.
- S32 &both_count, // error - both host and URL set.
- S32 &neither_count) // error - neither set.
-{
- sb_count = host_count = both_count = neither_count = 0;
-
- std::set<LLUUID> baked_ids;
- collectBakedTextureUUIDs(baked_ids);
- for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it)
- {
- LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
- bool has_url = false, has_host = false;
- if (!imagep->getUrl().empty())
- {
- has_url = true;
- }
- if (imagep->getTargetHost().isOk())
- {
- has_host = true;
- }
- if (has_url && !has_host) sb_count++;
- else if (has_host && !has_url) host_count++;
- else if (has_host && has_url) both_count++;
- else if (!has_host && !has_url) neither_count++;
- }
-}
-
std::string LLVOAvatar::bakedTextureOriginInfo()
{
std::string result;
@@ -4469,19 +4443,6 @@ void LLVOAvatar::updateTextures()
{
const S32 boost_level = getAvatarBakedBoostLevel();
imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE);
- // Spam if this is a baked texture, not set to default image, without valid host info
- if (isIndexBakedTexture((ETextureIndex)texture_index)
- && imagep->getID() != IMG_DEFAULT_AVATAR
- && imagep->getID() != IMG_INVISIBLE
- && !isUsingServerBakes()
- && !imagep->getTargetHost().isOk())
- {
- LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture "
- << imagep->getID() << " for avatar "
- << (isSelf() ? "<myself>" : getID().asString())
- << " on host " << getRegion()->getHost() << llendl;
- }
-
addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );
}
}
@@ -4501,7 +4462,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
@@ -4564,11 +4525,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);
@@ -4613,22 +4574,19 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid)
{
llassert(isIndexBakedTexture(ETextureIndex(te)));
std::string url = "";
- if (isUsingServerBakes())
+ const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL();
+ if (appearance_service_url.empty())
{
- const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL();
- if (appearance_service_url.empty())
- {
- // Probably a server-side issue if we get here:
- llwarns << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << llendl;
- return url;
- }
+ // Probably a server-side issue if we get here:
+ llwarns << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << llendl;
+ return url;
+ }
- const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
- if (texture_entry != NULL)
- {
- url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString();
- //llinfos << "baked texture url: " << url << llendl;
- }
+ const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
+ if (texture_entry != NULL)
+ {
+ url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString();
+ //llinfos << "baked texture url: " << url << llendl;
}
return url;
}
@@ -5012,70 +4970,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()
@@ -5199,9 +5126,9 @@ BOOL LLVOAvatar::loadSkeletonNode ()
{
if (!LLAvatarAppearance::loadSkeletonNode())
{
- return FALSE;
- }
-
+ return FALSE;
+ }
+
// ATTACHMENTS
{
LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
@@ -5230,7 +5157,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()
{
attachment->setOriginalPosition(info->mPosition);
}
-
+
if (info->mHasRotation)
{
LLQuaternion rotation;
@@ -5300,7 +5227,6 @@ void LLVOAvatar::updateVisualParams()
dirtyMesh();
updateHeadOffset();
}
-
//-----------------------------------------------------------------------------
// isActive()
//-----------------------------------------------------------------------------
@@ -5457,11 +5383,11 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
//-----------------------------------------------------------------------------
// updateSexDependentLayerSets()
//-----------------------------------------------------------------------------
-void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake )
+void LLVOAvatar::updateSexDependentLayerSets()
{
- invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet);
+ invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet);
+ invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);
}
//-----------------------------------------------------------------------------
@@ -5641,6 +5567,7 @@ void LLVOAvatar::lazyAttach()
void LLVOAvatar::resetHUDAttachments()
{
+
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -5693,10 +5620,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() )
@@ -5714,6 +5641,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
{
+
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -5724,6 +5652,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
{
mVisualComplexityStale = TRUE;
cleanupAttachedMesh( viewer_object );
+
attachment->removeObject(viewer_object);
lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;
return TRUE;
@@ -5921,28 +5850,26 @@ 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 )
+void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset)
{
}
@@ -5951,18 +5878,18 @@ void LLVOAvatar::invalidateAll()
}
// virtual
-void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake )
+void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
{
if (global_color == mTexSkinColor)
{
- invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet);
+ invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet);
+ invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);
}
else if (global_color == mTexHairColor)
{
- invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet);
+ invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet);
// ! BACKWARDS COMPATIBILITY !
// Fix for dealing with avatars from viewers that don't bake hair.
@@ -5975,7 +5902,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL
{
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setColor( color );
}
}
@@ -5984,7 +5911,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL
else if (global_color == mTexEyeColor)
{
// llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl;
- invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet);
}
updateMeshTextures();
}
@@ -6043,9 +5970,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)
{
@@ -6054,16 +5981,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;
}
}
@@ -6075,9 +6002,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)
{
@@ -6085,15 +6015,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)
{
@@ -6122,7 +6055,7 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
void LLVOAvatar::logPendingPhases()
{
if (!isAgentAvatarValid())
- {
+ {
return;
}
@@ -6138,14 +6071,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)
{
@@ -6156,14 +6089,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;
@@ -6172,15 +6105,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_using_server_bakes"] = true;
record["is_self"] = isSelf();
-
+
if (isAgentAvatarValid())
{
gAgentAvatarp->addMetricsTimerRecord(record);
@@ -6388,28 +6321,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])
@@ -6423,6 +6356,8 @@ void LLVOAvatar::updateMeshTextures()
// we'll consider it loaded and use it (rather than
// doing compositing).
useBakedTexture( baked_img->getID() );
+ mLoadedCallbacksPaused |= !isVisible();
+ checkTextureLoading();
}
else
{
@@ -6435,6 +6370,10 @@ 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;
+ checkTextureLoading();
}
}
else if (layerset && isUsingLocalAppearance())
@@ -6453,7 +6392,7 @@ void LLVOAvatar::updateMeshTextures()
if (mesh)
{
mesh->setLayerSet( layerset );
- }
+ }
}
}
else
@@ -6475,7 +6414,7 @@ void LLVOAvatar::updateMeshTextures()
{
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setColor( color );
mesh->setTexture( hair_img );
}
@@ -6563,18 +6502,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)
{
@@ -6785,6 +6723,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;
}
}
@@ -6852,12 +6793,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;
@@ -6867,9 +6808,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;
@@ -6884,7 +6825,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();
}
@@ -6903,7 +6845,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)
{
@@ -6920,7 +6862,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
@@ -6938,7 +6880,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();
}
@@ -6959,7 +6902,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;
@@ -7000,19 +6944,18 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
{
llwarns << "inconsistent appearance_version settings - field: " <<
contents.mAppearanceVersion << ", param: " << contents.mParamAppearanceVersion << llendl;
- return false;
}
- if (contents.mParamAppearanceVersion >= 0) // use visual param if available.
+ if (contents.mParamAppearanceVersion > 0) // use visual param if available.
{
appearance_version = contents.mParamAppearanceVersion;
}
- if (contents.mAppearanceVersion >= 0)
+ else if (contents.mAppearanceVersion > 0)
{
appearance_version = contents.mAppearanceVersion;
}
- if (appearance_version < 0) // still not set, go with 0.
+ else // still not set, go with 1.
{
- appearance_version = 0;
+ appearance_version = 1;
}
LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
<< " param: " << contents.mParamAppearanceVersion
@@ -7026,7 +6969,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"))
@@ -7050,24 +6993,21 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
llwarns << "bad appearance version info, discarding" << llendl;
return;
}
+ llassert(appearance_version > 0);
+ if (appearance_version > 1)
+ {
+ llwarns << "unsupported appearance version " << appearance_version << ", discarding appearance message" << llendl;
+ return;
+ }
+
S32 this_update_cof_version = contents.mCOFVersion;
S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion;
- // Only now that we have result of appearance_version can we decide whether to bail out.
if( isSelf() )
{
LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version
<< " last_update_request_cof_version " << last_update_request_cof_version
<< " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << llendl;
-
- if (getRegion() && (getRegion()->getCentralBakeVersion()==0))
- {
- llwarns << avString() << "Received AvatarAppearance message for self in non-server-bake region" << llendl;
- }
- if( mFirstTEMessageReceived && (appearance_version == 0))
- {
- return;
- }
}
else
{
@@ -7076,7 +7016,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// Check for stale update.
if (isSelf()
- && (appearance_version>0)
&& (this_update_cof_version < last_update_request_cof_version))
{
llwarns << "Stale appearance update, wanted version " << last_update_request_cof_version
@@ -7090,6 +7029,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
return;
}
+ // SUNSHINE CLEANUP - is this case OK now?
S32 num_params = contents.mParamWeights.size();
if (num_params <= 1)
{
@@ -7101,10 +7041,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
return;
}
+ // No backsies zone - if we get here, the message should be valid and usable, will be processed.
+
+ // Note:
+ // RequestAgentUpdateAppearanceResponder::onRequestRequested()
+ // assumes that cof version is only updated with server-bake
+ // appearance messages.
mLastUpdateReceivedCOFVersion = this_update_cof_version;
- setIsUsingServerBakes(appearance_version > 0);
-
applyParsedTEMessage(contents.mTEContents);
// prevent the overwriting of valid baked textures with invalid baked textures
@@ -7114,9 +7058,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT
&& baked_index != BAKED_SKIRT)
{
+ LL_DEBUGS("Avatar") << avString() << " 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() << " baked_index " << (S32) baked_index << " using texture id "
+ << getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << llendl;
+ }
}
// runway - was
@@ -7142,32 +7092,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);
}
+ else
+ {
+ //LL_DEBUGS("Avatar") << std::setprecision(5) << " param target " << i << " " << param->getWeight() << " -> " << newWeight << llendl;
+ interp_params = TRUE;
+ param->setAnimationTarget(newWeight);
+ }
+ }
}
- 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)
@@ -7179,7 +7135,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
ESex new_sex = getSex();
if( old_sex != new_sex )
{
- updateSexDependentLayerSets( FALSE );
+ updateSexDependentLayerSets();
}
}
@@ -7217,7 +7173,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
updateMeshTextures();
-
//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");
}
@@ -7400,7 +7355,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;
@@ -7416,12 +7371,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 );
- }
+ }
}
}
@@ -7445,7 +7400,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
{
LLAvatarJointMesh* mesh = (*iter);
if (mesh)
- {
+ {
mesh->setColor( LLColor4::white );
}
}
@@ -7464,7 +7419,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;
@@ -7473,6 +7428,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);
@@ -7481,10 +7445,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");
}
@@ -7510,36 +7470,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.
@@ -7551,6 +7511,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 )
@@ -7562,6 +7523,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" );
@@ -7684,43 +7646,8 @@ void LLVOAvatar::startAppearanceAnimation()
}
// 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
-{
-#if 1
- // Sanity check - visual param for appearance version should match mUseServerBakes
- LLVisualParam* appearance_version_param = getVisualParam(11000);
- llassert(appearance_version_param);
- 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 931e65b3ea..b838bec7dc 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -142,8 +142,6 @@ public:
bool allTexturesCompletelyDownloaded(std::set<LLUUID>& ids) const;
bool allLocalTexturesCompletelyDownloaded() const;
bool allBakedTexturesCompletelyDownloaded() const;
- void bakedTextureOriginCounts(S32 &sb_count, S32 &host_count,
- S32 &both_count, S32 &neither_count);
std::string bakedTextureOriginInfo();
void collectLocalTextureUUIDs(std::set<LLUUID>& ids) const;
void collectBakedTextureUUIDs(std::set<LLUUID>& ids) const;
@@ -199,9 +197,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 +206,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
@@ -441,7 +437,7 @@ public:
// Global colors
//--------------------------------------------------------------------
public:
- /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake);
+ /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color);
//--------------------------------------------------------------------
// Visibility
@@ -601,7 +597,7 @@ protected:
// Composites
//--------------------------------------------------------------------
public:
- virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result);
+ virtual void invalidateComposite(LLTexLayerSet* layerset);
virtual void invalidateAll();
virtual void setCompositeUpdatesEnabled(bool b) {}
virtual void setCompositeUpdatesEnabled(U32 index, bool b) {}
@@ -638,7 +634,7 @@ private:
public:
void debugColorizeSubMeshes(U32 i, const LLColor4& color);
virtual void updateMeshTextures();
- void updateSexDependentLayerSets(BOOL upload_bake);
+ void updateSexDependentLayerSets();
virtual void dirtyMesh(); // Dirty the avatar mesh
void updateMeshData();
protected:
@@ -671,7 +667,6 @@ public:
void processAvatarAppearance(LLMessageSystem* mesgsys);
void hideSkirt();
void startAppearanceAnimation();
- /*virtual*/ void bodySizeChanged();
//--------------------------------------------------------------------
// Appearance morphing
@@ -684,12 +679,6 @@ public:
// editing or when waiting for a subsequent server rebake.
/*virtual*/ BOOL isUsingLocalAppearance() const { return mUseLocalAppearance; }
- // True if this avatar should fetch its baked textures via the new
- // appearance mechanism.
- BOOL isUsingServerBakes() const;
- void setIsUsingServerBakes(BOOL newval);
-
-
// True if we are currently in appearance editing mode. Often but
// not always the same as isUsingLocalAppearance().
/*virtual*/ BOOL isEditingAppearance() const { return mIsEditingAppearance; }
@@ -702,7 +691,6 @@ private:
F32 mLastAppearanceBlendTime;
BOOL mIsEditingAppearance; // flag for if we're actively in appearance editing mode
BOOL mUseLocalAppearance; // flag for if we're using a local composite
- BOOL mUseServerBakes; // flag for if baked textures should be fetched from baking service (false if they're temporary uploads)
//--------------------------------------------------------------------
// Visibility
@@ -1028,10 +1016,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 9ce99444d9..4c0b3b1235 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -161,8 +161,6 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
mRegionCrossingCount(0),
mInitialBakesLoaded(false)
{
- gAgentWearables.setAvatarObject(this);
-
mMotionController.mIsSelf = TRUE;
lldebugs << "Marking avatar as self " << id << llendl;
@@ -188,15 +186,6 @@ bool update_avatar_rez_metrics()
return false;
}
-bool check_for_unsupported_baked_appearance()
-{
- if (!isAgentAvatarValid())
- return true;
-
- gAgentAvatarp->checkForUnsupportedServerBakeAppearance();
- return false;
-}
-
void LLVOAvatarSelf::initInstance()
{
BOOL status = TRUE;
@@ -233,7 +222,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 +617,7 @@ LLVOAvatarSelf::~LLVOAvatarSelf()
** **
*********************************************************************************/
-//virtual
+// virtual
BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent)
{
// update screen joint size
@@ -644,55 +659,42 @@ 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 )
+BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight)
{
if (!which_param)
{
return FALSE;
}
LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID());
- return setParamWeight(param,weight,upload_bake);
+ return setParamWeight(param,weight);
}
// virtual
-BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake )
+BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight)
{
if (!param_name)
{
return FALSE;
}
LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name);
- return setParamWeight(param,weight,upload_bake);
+ return setParamWeight(param,weight);
}
// virtual
-BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake )
+BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight)
{
LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index);
- return setParamWeight(param,weight,upload_bake);
+ return setParamWeight(param,weight);
}
-BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake )
+BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight)
{
if (!param)
{
return FALSE;
}
-#if 0
- // FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables.
- if (isUsingServerBakes() && !isUsingLocalAppearance())
- {
- return FALSE;
- }
-#endif
-
if (param->getCrossWearable())
{
LLWearableType::EType type = (LLWearableType::EType)param->getWearableType();
@@ -702,12 +704,12 @@ BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight
LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count);
if (wearable)
{
- wearable->setVisualParamWeight(param->getID(), weight, upload_bake);
+ wearable->setVisualParamWeight(param->getID(), weight);
}
}
}
- return LLCharacter::setVisualParamWeight(param,weight,upload_bake);
+ return LLCharacter::setVisualParamWeight(param,weight);
}
/*virtual*/
@@ -720,7 +722,7 @@ void LLVOAvatarSelf::updateVisualParams()
void LLVOAvatarSelf::idleUpdateAppearanceAnimation()
{
// Animate all top-level wearable visual parameters
- gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE);
+ gAgentWearables.animateAllWearableParams(calcMorphAmount());
// apply wearable visual params to avatar
for (U32 type = 0; type < LLWearableType::WT_COUNT; type++)
@@ -762,54 +764,6 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)
}
}
-//virtual
-U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys,
- void **user_data,
- U32 block_num,
- const EObjectUpdateType update_type,
- LLDataPacker *dp)
-{
- U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp);
-
-#if 0
- // DRANO - it's not clear this does anything useful. If we wait
- // until an appearance message has been received, we already have
- // the texture ids. If we don't wait, we don't yet know where to
- // look for baked textures, because we haven't received the
- // appearance version data from the appearance message. This looks
- // like an old optimization that's incompatible with server-side
- // texture baking.
-
- // FIXME DRANO - skipping in the case of !mFirstAppearanceMessageReceived prevents us from trying to
- // load textures before we know where they come from (ie, from baking service or not);
- // unknown impact on performance.
- if (mInitialBakesLoaded == false && retval == 0x0 && mFirstAppearanceMessageReceived)
- {
- // call update textures to force the images to be created
- updateMeshTextures();
-
- // unpack the texture UUIDs to the texture slots
- retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, (S32) block_num);
-
- // need to trigger a few operations to get the avatar to use the new bakes
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- const LLAvatarAppearanceDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex;
- LLUUID texture_id = getTEImage(te)->getID();
- setNewBakedTexture(te, texture_id);
- mInitialBakeIDs[i] = texture_id;
- }
-
- onFirstTEMessageReceived();
-
- mInitialBakesLoaded = true;
- }
-#endif
-
- return retval;
-}
-
-
void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index)
{
if (te >= TEX_NUM_INDICES)
@@ -861,15 +815,11 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
{
LLViewerTexLayerSet *layerset = getTexLayerSet(i);
layerset->setUpdatesEnabled(TRUE);
- invalidateComposite(layerset, FALSE);
+ invalidateComposite(layerset);
}
updateMeshTextures();
- if (getRegion() && !getRegion()->getCentralBakeVersion())
- {
- requestLayerSetUploads();
}
}
-}
//virtual
void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
@@ -1042,7 +992,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
// forces an update to any baked textures relevant to type.
// will force an upload of the resulting bake if the second parameter is TRUE
//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_result )
+void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type)
{
for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();
baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end();
@@ -1064,20 +1014,13 @@ void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_re
if (layerset)
{
layerset->setUpdatesEnabled(true);
- invalidateComposite(layerset, upload_result);
+ invalidateComposite(layerset);
}
break;
}
}
}
}
-
- // Physics type has no associated baked textures, but change of params needs to be sent to
- // other avatars.
- if (type == LLWearableType::WT_PHYSICS)
- {
- gAgent.sendAgentSetAppearance();
- }
}
//-----------------------------------------------------------------------------
@@ -1310,7 +1253,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();
@@ -1489,15 +1432,6 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const
return TRUE;
}
-BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const
-{
- const LLViewerTexLayerSet *layerset = getLayerSet(index);
- if (!layerset) return FALSE;
- const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite();
- if (!layerset_buffer) return FALSE;
- return !layerset_buffer->uploadNeeded();
-}
-
BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const
{
LLUUID id;
@@ -1555,49 +1489,12 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t
return isTextureVisible(type,index);
}
-
-//-----------------------------------------------------------------------------
-// requestLayerSetUploads()
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::requestLayerSetUploads()
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- requestLayerSetUpload((EBakedTextureIndex)i);
- }
-}
-
-void LLVOAvatarSelf::requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i)
-{
- ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex;
- const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index));
- LLViewerTexLayerSet *layerset = getLayerSet(i);
- if (!layer_baked && layerset)
- {
- layerset->requestUpload();
- }
-}
-
bool LLVOAvatarSelf::areTexturesCurrent() const
{
- return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded();
+ return gAgentWearables.areWearablesLoaded();
}
-// virtual
-bool LLVOAvatarSelf::hasPendingBakedUploads() const
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- LLViewerTexLayerSet* layerset = getTexLayerSet(i);
- if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending())
- {
- return true;
- }
- }
- return false;
-}
-
-void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )
+void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset)
{
LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset);
if( !layer_set || !layer_set->getUpdatesEnabled() )
@@ -1608,16 +1505,6 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_r
layer_set->requestUpdate();
layer_set->invalidateMorphMasks();
-
- if( upload_result && (getRegion() && !getRegion()->getCentralBakeVersion()))
- {
- llassert(isSelf());
-
- ETextureIndex baked_te = getBakedTE( layer_set );
- setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) );
- layer_set->requestUpload();
- updateMeshTextures();
- }
}
void LLVOAvatarSelf::invalidateAll()
@@ -1625,7 +1512,7 @@ void LLVOAvatarSelf::invalidateAll()
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
LLViewerTexLayerSet *layerset = getTexLayerSet(i);
- invalidateComposite(layerset, TRUE);
+ invalidateComposite(layerset);
}
//mDebugSelfLoadTimer.reset();
}
@@ -1799,11 +1686,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);
@@ -2220,27 +2107,9 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const
return text;
}
-
-#if 0
-// Dump avatar metrics data.
-LLSD LLVOAvatarSelf::metricsData()
-{
- // runway - add region info
- LLSD result;
- result["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
- result["timers"]["debug_existence"] = mDebugExistenceTimer.getElapsedTimeF32();
- result["timers"]["ruth_debug"] = mRuthDebugTimer.getElapsedTimeF32();
- result["timers"]["ruth"] = mRuthTimer.getElapsedTimeF32();
- result["timers"]["invisible"] = mInvisibleTimer.getElapsedTimeF32();
- result["timers"]["fully_loaded"] = mFullyLoadedTimer.getElapsedTimeF32();
- result["startup"] = LLStartUp::getPhases().dumpPhases();
-
- return result;
-}
-#endif
-
class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder
{
+ LOG_CLASS(ViewerAppearanceChangeMetricsResponder);
public:
ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,
volatile const S32 & live_sequence,
@@ -2251,32 +2120,25 @@ public:
{
}
- virtual void completed(U32 status,
- const std::string& reason,
- const LLSD& content)
+private:
+ /* virtual */ void httpSuccess()
{
- gPendingMetricsUploads--; // if we add retry, this should be moved to the isGoodStatus case.
- if (isGoodStatus(status))
- {
- LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
- result(content);
- }
- else
- {
- LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL;
- errorWithContent(status,reason,content);
- }
- }
+ LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
- // virtual
- void result(const LLSD & content)
- {
+ gPendingMetricsUploads--;
if (mLiveSequence == mExpectedSequence)
{
mReportingStarted = true;
}
}
+ /* virtual */ void httpFailure()
+ {
+ // if we add retry, this should be removed from the httpFailure case
+ LL_WARNS("Avatar") << dumpResponse() << LL_ENDL;
+ gPendingMetricsUploads--;
+ }
+
private:
S32 mExpectedSequence;
volatile const S32 & mLiveSequence;
@@ -2359,11 +2221,10 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,
void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
{
- // gAgentAvatarp->stopAllPhases();
static volatile bool reporting_started(false);
static volatile S32 report_sequence(0);
- LLSD msg; // = metricsData();
+ LLSD msg;
msg["message"] = "ViewerAppearanceChangeMetrics";
msg["session_id"] = gAgentSessionID;
msg["agent_id"] = gAgentID;
@@ -2423,63 +2284,6 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
}
}
-class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder
-{
-public:
- CheckAgentAppearanceServiceResponder()
- {
- }
-
- virtual ~CheckAgentAppearanceServiceResponder()
- {
- }
-
- /* virtual */ void result(const LLSD& content)
- {
- LL_DEBUGS("Avatar") << "status OK" << llendl;
- }
-
- // Error
- /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content)
- {
- if (isAgentAvatarValid())
- {
- LL_DEBUGS("Avatar") << "failed, will rebake [status:"
- << status << "]: " << content << llendl;
- forceAppearanceUpdate();
- }
- }
-
- static void forceAppearanceUpdate()
- {
- // Trying to rebake immediately after crossing region boundary
- // seems to be failure prone; adding a delay factor. Yes, this
- // fix is ad-hoc and not guaranteed to work in all cases.
- doAfterInterval(boost::bind(&LLVOAvatarSelf::forceBakeAllTextures,
- gAgentAvatarp.get(), true), 5.0);
- }
-};
-
-void LLVOAvatarSelf::checkForUnsupportedServerBakeAppearance()
-{
- // Need to check only if we have a server baked appearance and are
- // in a non-baking region.
- if (!gAgentAvatarp->isUsingServerBakes())
- return;
- if (!gAgent.getRegion() || gAgent.getRegion()->getCentralBakeVersion()!=0)
- return;
-
- // if baked image service is unknown, need to refresh.
- if (LLAppearanceMgr::instance().getAppearanceServiceURL().empty())
- {
- CheckAgentAppearanceServiceResponder::forceAppearanceUpdate();
- }
- // query baked image service to check status.
- std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED,
- getTE(TEX_HEAD_BAKED)->getID());
- LLHTTPClient::head(image_url, new CheckAgentAppearanceServiceResponder);
-}
-
const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
{
if (canGrabBakedTexture(baked_index))
@@ -2580,25 +2384,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
@@ -2636,82 +2440,6 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset )
return TEX_HEAD_BAKED;
}
-
-void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid)
-{
- ETextureIndex index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(i);
- setNewBakedTexture(index, uuid);
-}
-
-
-//-----------------------------------------------------------------------------
-// setNewBakedTexture()
-// A new baked texture has been successfully uploaded and we can start using it now.
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
-{
- // Baked textures live on other sims.
- LLHost target_host = getObjectHost();
- setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) );
- updateMeshTextures();
- dirtyMesh();
-
- LLVOAvatar::cullAvatarsByPixelArea();
-
- /* switch(te)
- case TEX_HEAD_BAKED:
- llinfos << "New baked texture: HEAD" << llendl; */
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te);
- if (texture_dict->mIsBakedTexture)
- {
- debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish.
- llinfos << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<llendl;
- }
- else
- {
- llwarns << "New baked texture: unknown te " << te << llendl;
- }
-
- // dumpAvatarTEs( "setNewBakedTexture() send" );
- // RN: throttle uploads
- if (!hasPendingBakedUploads())
- {
- gAgent.sendAgentSetAppearance();
-
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32());
- if (isAllLocalTextureDataFinal())
- {
- LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args);
- LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32()
- << "sec ]"
- << avString()
- << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32()
- << " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32()
- << " Notification " << "AvatarRezSelfBakedDoneNotification"
- << llendl;
- }
- else
- {
- args["STATUS"] = debugDumpAllLocalTextureDataInfo();
- LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args);
- LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32()
- << "sec ]"
- << avString()
- << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32()
- << " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32()
- << " Notification " << "AvatarRezSelfBakedUpdateNotification"
- << llendl;
- }
- }
-
- outputRezDiagnostics();
- }
-}
-
// FIXME: This is not called consistently. Something may be broken.
void LLVOAvatarSelf::outputRezDiagnostics() const
{
@@ -2787,89 +2515,7 @@ void LLVOAvatarSelf::reportAvatarRezTime() const
// TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow.
}
-//-----------------------------------------------------------------------------
-// setCachedBakedTexture()
-// A baked texture id was received from a cache query, make it active
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid )
-{
- setTETexture( te, uuid );
-
- /* switch(te)
- case TEX_HEAD_BAKED:
- if( mHeadLayerSet )
- mHeadLayerSet->cancelUpload(); */
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- LLViewerTexLayerSet *layerset = getTexLayerSet(i);
- if ( mBakedTextureDatas[i].mTextureIndex == te && layerset)
- {
- if (mInitialBakeIDs[i] != LLUUID::null)
- {
- if (mInitialBakeIDs[i] == uuid)
- {
- llinfos << "baked texture correctly loaded at login! " << i << llendl;
- }
- else
- {
- llwarns << "baked texture does not match id loaded at login!" << i << llendl;
- }
- mInitialBakeIDs[i] = LLUUID::null;
- }
- layerset->cancelUpload();
- }
- }
-}
-
-// static
-void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**)
-{
- LLUUID texture_id;
- msg->getUUID("TextureData", "TextureID", texture_id);
- if (!isAgentAvatarValid()) return;
-
- // If this is a texture corresponding to one of our baked entries,
- // just rebake that layer set.
- BOOL found = FALSE;
-
- /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] =
- TEX_HEAD_BAKED,
- TEX_UPPER_BAKED, */
- for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
- iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
- ++iter)
- {
- const ETextureIndex index = iter->first;
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
- if (texture_dict->mIsBakedTexture)
- {
- if (texture_id == gAgentAvatarp->getTEImage(index)->getID())
- {
- LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index);
- if (layer_set)
- {
- llinfos << "TAT: rebake - matched entry " << (S32)index << llendl;
- gAgentAvatarp->invalidateComposite(layer_set, TRUE);
- found = TRUE;
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES);
- }
- }
- }
- }
-
- // If texture not found, rebake all entries.
- if (!found)
- {
- gAgentAvatarp->forceBakeAllTextures();
- }
- else
- {
- // Not sure if this is necessary, but forceBakeAllTextures() does it.
- gAgentAvatarp->updateMeshTextures();
- }
-}
-
-
+// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures()
void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)
{
llinfos << "TAT: forced full rebake. " << llendl;
@@ -2883,10 +2529,9 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)
if (slam_for_debug)
{
layer_set->setUpdatesEnabled(TRUE);
- layer_set->cancelUpload();
}
- invalidateComposite(layer_set, TRUE);
+ invalidateComposite(layer_set);
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES);
}
else
@@ -2921,17 +2566,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 +2600,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();
}
@@ -2981,12 +2631,6 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)
if (isAgentAvatarValid())
{
gAgentAvatarp->mIsEditingAppearance = false;
- if (gAgentAvatarp->getRegion() && !gAgentAvatarp->getRegion()->getCentralBakeVersion())
- {
- // FIXME DRANO - move to sendAgentSetAppearance, make conditional on upload complete.
- gAgentAvatarp->mUseLocalAppearance = false;
- }
-
gAgentAvatarp->invalidateAll();
if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch)
@@ -2994,8 +2638,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..0eb80d1fad 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -32,6 +32,7 @@
#include "llvoavatar.h"
struct LocalTextureData;
+class LLInventoryCallback;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -96,21 +97,15 @@ public:
void resetJointPositions( void );
- /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE );
- /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE );
- /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE );
+ /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight);
+ /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight);
+ /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight);
/*virtual*/ void updateVisualParams();
/*virtual*/ void idleUpdateAppearanceAnimation();
- /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys,
- void **user_data,
- U32 block_num,
- const EObjectUpdateType update_type,
- LLDataPacker *dp);
-
private:
// helper function. Passed in param is assumed to be in avatar's parameter list.
- BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE );
+ BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight);
@@ -138,6 +133,7 @@ public:
public:
/*virtual*/ BOOL updateCharacter(LLAgent &agent);
/*virtual*/ void idleUpdateTractorBeam();
+ bool checkStuckAppearance();
//--------------------------------------------------------------------
// Loading state
@@ -194,12 +190,10 @@ public:
// Loading status
//--------------------------------------------------------------------
public:
- /*virtual*/ bool hasPendingBakedUploads() const;
S32 getLocalDiscardLevel(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;
bool areTexturesCurrent() const;
BOOL isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const;
BOOL isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const;
- BOOL isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const;
// If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index
/*virtual*/ BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;
/*virtual*/ BOOL isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const;
@@ -234,11 +228,8 @@ private:
//--------------------------------------------------------------------
public:
LLAvatarAppearanceDefines::ETextureIndex getBakedTE(const LLViewerTexLayerSet* layerset ) const;
- void setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid);
- void setNewBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid);
- void setCachedBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid);
+ // SUNSHINE CLEANUP - dead? or update to just call request appearance update?
void forceBakeAllTextures(bool slam_for_debug = false);
- static void processRebakeAvatarTextures(LLMessageSystem* msg, void**);
protected:
/*virtual*/ void removeMissingBakedTextures();
@@ -246,8 +237,6 @@ protected:
// Layers
//--------------------------------------------------------------------
public:
- void requestLayerSetUploads();
- void requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i);
void requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i);
LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const;
@@ -257,7 +246,7 @@ public:
// Composites
//--------------------------------------------------------------------
public:
- /* virtual */ void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result);
+ /* virtual */ void invalidateComposite(LLTexLayerSet* layerset);
/* virtual */ void invalidateAll();
/* virtual */ void setCompositeUpdatesEnabled(bool b); // only works for self
/* virtual */ void setCompositeUpdatesEnabled(U32 index, bool b);
@@ -300,7 +289,7 @@ protected:
**/
public:
- void wearableUpdated(LLWearableType::EType type, BOOL upload_result);
+ void wearableUpdated(LLWearableType::EType type);
protected:
U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const;
@@ -341,6 +330,7 @@ private:
public:
static void onCustomizeStart(bool disable_camera_switch = false);
static void onCustomizeEnd(bool disable_camera_switch = false);
+ LLPointer<LLInventoryCallback> mEndCustomizeCallback;
//--------------------------------------------------------------------
// Visibility
@@ -402,7 +392,6 @@ public:
const std::string debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer
const std::string debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD
void sendViewerAppearanceChangeMetrics(); // send data associated with completing a change.
- void checkForUnsupportedServerBakeAppearance();
private:
LLFrameTimer mDebugSelfLoadTimer;
F32 mDebugTimeWearablesLoaded;
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 ff73aa5354..1e02237f6b 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 d9efd23b43..5fdd2894a6 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;
@@ -4460,6 +4460,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);
@@ -4541,18 +4546,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();
@@ -4560,43 +4559,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)
{
@@ -4952,7 +4950,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 69255af179..3bdbb05beb 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;
}
@@ -158,33 +155,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)
- {
- }
};
///////////////////////////////////////////////////////////////////////////////
@@ -203,7 +203,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);
}
@@ -227,8 +227,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 e7c89db069..d4dcb96519 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -10192,5 +10192,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 8ce56326d8..5e73dbb981 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, bool) {}
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 dc8ff2f644..8da4f88905 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -130,12 +130,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;
@@ -162,8 +163,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;