summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/00-COMPILE-LINK-RUN.txt2
-rwxr-xr-xindra/cmake/CARes.cmake21
-rwxr-xr-xindra/cmake/CMakeLists.txt3
-rwxr-xr-xindra/cmake/FindCARes.cmake48
-rw-r--r--indra/cmake/LLAddBuildTest.cmake7
-rw-r--r--indra/cmake/LLAppearance.cmake12
-rw-r--r--indra/cmake/LLAppearanceUtility.cmake2
-rwxr-xr-xindra/cmake/LLCoreHttp.cmake7
-rwxr-xr-xindra/cmake/LLMessage.cmake2
-rwxr-xr-xindra/linux_crash_logger/CMakeLists.txt11
-rw-r--r--indra/llappearance/CMakeLists.txt5
-rwxr-xr-xindra/llcommon/CMakeLists.txt10
-rwxr-xr-xindra/llcommon/fix_macros.h4
-rwxr-xr-xindra/llcommon/linden_common.h1
-rwxr-xr-xindra/llcommon/llcoros.cpp99
-rwxr-xr-xindra/llcommon/llcoros.h125
-rwxr-xr-xindra/llcommon/llerror.h1
-rwxr-xr-xindra/llcommon/lleventcoro.cpp208
-rwxr-xr-xindra/llcommon/lleventcoro.h317
-rwxr-xr-xindra/llcommon/llprocess.cpp6
-rwxr-xr-xindra/llcommon/llrefcount.h9
-rw-r--r--indra/llcommon/llsdjson.cpp126
-rw-r--r--indra/llcommon/llsdjson.h77
-rwxr-xr-xindra/llcommon/llstring.h2
-rwxr-xr-xindra/llcommon/tests/lleventcoro_test.cpp724
-rwxr-xr-xindra/llcorehttp/CMakeLists.txt10
-rwxr-xr-xindra/llcorehttp/_httpinternal.h5
-rwxr-xr-xindra/llcorehttp/_httplibcurl.cpp2
-rwxr-xr-xindra/llcorehttp/_httpoprequest.cpp281
-rwxr-xr-xindra/llcorehttp/_httpoprequest.h74
-rwxr-xr-xindra/llcorehttp/_httppolicyglobal.cpp30
-rwxr-xr-xindra/llcorehttp/_httppolicyglobal.h3
-rwxr-xr-xindra/llcorehttp/_httpservice.cpp80
-rwxr-xr-xindra/llcorehttp/_httpservice.h9
-rwxr-xr-xindra/llcorehttp/_refcounted.h30
-rwxr-xr-xindra/llcorehttp/bufferarray.h4
-rwxr-xr-xindra/llcorehttp/examples/http_texture_load.cpp18
-rwxr-xr-xindra/llcorehttp/httpcommon.cpp207
-rwxr-xr-xindra/llcorehttp/httpcommon.h165
-rwxr-xr-xindra/llcorehttp/httphandler.h9
-rwxr-xr-xindra/llcorehttp/httpheaders.cpp21
-rwxr-xr-xindra/llcorehttp/httpheaders.h20
-rwxr-xr-xindra/llcorehttp/httpoptions.cpp48
-rwxr-xr-xindra/llcorehttp/httpoptions.h97
-rwxr-xr-xindra/llcorehttp/httprequest.cpp150
-rwxr-xr-xindra/llcorehttp/httprequest.h120
-rwxr-xr-xindra/llcorehttp/httpresponse.cpp28
-rwxr-xr-xindra/llcorehttp/httpresponse.h52
-rwxr-xr-xindra/llcorehttp/llhttpconstants.cpp (renamed from indra/llmessage/llhttpconstants.cpp)91
-rwxr-xr-xindra/llcorehttp/llhttpconstants.h (renamed from indra/llmessage/llhttpconstants.h)7
-rwxr-xr-xindra/llcorehttp/tests/test_httpheaders.hpp27
-rwxr-xr-xindra/llcorehttp/tests/test_httprequest.hpp328
-rwxr-xr-xindra/llcorehttp/tests/test_httpstatus.hpp126
-rwxr-xr-xindra/llcrashlogger/CMakeLists.txt2
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.cpp139
-rwxr-xr-xindra/llcrashlogger/llcrashlogger.h10
-rwxr-xr-xindra/llinventory/CMakeLists.txt3
-rwxr-xr-xindra/llmessage/CMakeLists.txt70
-rwxr-xr-xindra/llmessage/llares.cpp839
-rwxr-xr-xindra/llmessage/llares.h583
-rwxr-xr-xindra/llmessage/llareslistener.cpp104
-rwxr-xr-xindra/llmessage/llareslistener.h53
-rwxr-xr-xindra/llmessage/llassetstorage.cpp3
-rwxr-xr-xindra/llmessage/llassetstorage.h1
-rwxr-xr-xindra/llmessage/llavatarnamecache.cpp274
-rwxr-xr-xindra/llmessage/llavatarnamecache.h5
-rwxr-xr-xindra/llmessage/llcachename.cpp2
-rw-r--r--indra/llmessage/llcoproceduremanager.cpp405
-rw-r--r--indra/llmessage/llcoproceduremanager.h98
-rw-r--r--indra/llmessage/llcorehttputil.cpp1237
-rw-r--r--indra/llmessage/llcorehttputil.h580
-rwxr-xr-xindra/llmessage/llcurl.cpp2038
-rwxr-xr-xindra/llmessage/llcurl.h556
-rw-r--r--indra/llmessage/llexperiencecache.cpp1335
-rw-r--r--indra/llmessage/llexperiencecache.h188
-rwxr-xr-xindra/llmessage/llhost.cpp2
-rwxr-xr-xindra/llmessage/llhost.h9
-rwxr-xr-xindra/llmessage/llhttpassetstorage.cpp1454
-rwxr-xr-xindra/llmessage/llhttpassetstorage.h159
-rwxr-xr-xindra/llmessage/llhttpclient.cpp673
-rwxr-xr-xindra/llmessage/llhttpclient.h201
-rwxr-xr-xindra/llmessage/llhttpclientadapter.cpp73
-rwxr-xr-xindra/llmessage/llhttpclientadapter.h51
-rwxr-xr-xindra/llmessage/llhttpclientinterface.h45
-rw-r--r--indra/llmessage/llhttpsdhandler.cpp105
-rw-r--r--indra/llmessage/llhttpsdhandler.h72
-rwxr-xr-xindra/llmessage/llhttpsender.cpp94
-rwxr-xr-xindra/llmessage/llhttpsender.h59
-rwxr-xr-xindra/llmessage/llproxy.cpp23
-rwxr-xr-xindra/llmessage/llproxy.h16
-rwxr-xr-xindra/llmessage/llsdmessage.cpp168
-rwxr-xr-xindra/llmessage/llsdmessage.h168
-rwxr-xr-xindra/llmessage/llsdrpcclient.cpp245
-rwxr-xr-xindra/llmessage/llsdrpcclient.h323
-rwxr-xr-xindra/llmessage/llsdrpcserver.cpp339
-rwxr-xr-xindra/llmessage/llsdrpcserver.h360
-rwxr-xr-xindra/llmessage/lltrustedmessageservice.cpp1
-rwxr-xr-xindra/llmessage/llurlrequest.cpp783
-rwxr-xr-xindra/llmessage/llurlrequest.h357
-rwxr-xr-xindra/llmessage/message.cpp128
-rwxr-xr-xindra/llmessage/message.h6
-rwxr-xr-xindra/llmessage/tests/llhttpclientadapter_test.cpp221
-rwxr-xr-xindra/llmessage/tests/llsdmessage_test.cpp130
-rwxr-xr-xindra/llmessage/tests/lltesthttpclientadapter.cpp61
-rwxr-xr-xindra/llmessage/tests/lltesthttpclientadapter.h57
-rwxr-xr-xindra/llprimitive/CMakeLists.txt4
-rwxr-xr-xindra/llui/CMakeLists.txt13
-rwxr-xr-xindra/llui/llurlentry.cpp8
-rwxr-xr-xindra/llui/tests/llurlentry_stub.cpp2
-rwxr-xr-xindra/llui/tests/llurlentry_test.cpp22
-rwxr-xr-xindra/mac_crash_logger/CMakeLists.txt6
-rwxr-xr-xindra/newview/CMakeLists.txt65
-rwxr-xr-xindra/newview/app_settings/settings.xml29
-rwxr-xr-xindra/newview/llaccountingcostmanager.cpp256
-rwxr-xr-xindra/newview/llaccountingcostmanager.h15
-rwxr-xr-xindra/newview/llagent.cpp302
-rwxr-xr-xindra/newview/llagent.h32
-rwxr-xr-xindra/newview/llagentlanguage.cpp24
-rwxr-xr-xindra/newview/llaisapi.cpp628
-rwxr-xr-xindra/newview/llaisapi.h125
-rwxr-xr-xindra/newview/llappcorehttp.cpp84
-rwxr-xr-xindra/newview/llappcorehttp.h28
-rwxr-xr-xindra/newview/llappearancemgr.cpp551
-rwxr-xr-xindra/newview/llappearancemgr.h25
-rwxr-xr-xindra/newview/llappviewer.cpp111
-rwxr-xr-xindra/newview/llappviewer.h4
-rwxr-xr-xindra/newview/llassetuploadqueue.cpp220
-rwxr-xr-xindra/newview/llassetuploadqueue.h93
-rwxr-xr-xindra/newview/llassetuploadresponders.cpp1148
-rwxr-xr-xindra/newview/llassetuploadresponders.h151
-rw-r--r--indra/newview/llavatarrenderinfoaccountant.cpp386
-rw-r--r--indra/newview/llavatarrenderinfoaccountant.h13
-rwxr-xr-xindra/newview/llcapabilitylistener.cpp202
-rwxr-xr-xindra/newview/llcapabilitylistener.h131
-rwxr-xr-xindra/newview/llcaphttpsender.cpp49
-rwxr-xr-xindra/newview/llcaphttpsender.h48
-rwxr-xr-xindra/newview/llclassifiedstatsresponder.cpp72
-rwxr-xr-xindra/newview/llclassifiedstatsresponder.h50
-rwxr-xr-xindra/newview/llcompilequeue.cpp218
-rwxr-xr-xindra/newview/llcompilequeue.h9
-rwxr-xr-xindra/newview/llestateinfomodel.cpp83
-rwxr-xr-xindra/newview/llestateinfomodel.h5
-rwxr-xr-xindra/newview/lleventpoll.cpp477
-rwxr-xr-xindra/newview/lleventpoll.h19
-rw-r--r--indra/newview/llexperienceassociationresponder.cpp97
-rw-r--r--indra/newview/llexperienceassociationresponder.h58
-rwxr-xr-xindra/newview/llfacebookconnect.cpp668
-rw-r--r--indra/newview/llfacebookconnect.h11
-rwxr-xr-xindra/newview/llfeaturemanager.cpp121
-rwxr-xr-xindra/newview/llfeaturemanager.h3
-rwxr-xr-xindra/newview/llfilepicker.cpp4
-rw-r--r--indra/newview/llflickrconnect.cpp584
-rw-r--r--indra/newview/llflickrconnect.h11
-rwxr-xr-xindra/newview/llfloaterabout.cpp95
-rwxr-xr-xindra/newview/llfloaterauction.cpp11
-rwxr-xr-xindra/newview/llfloaterautoreplacesettings.cpp1
-rwxr-xr-xindra/newview/llfloateravatarpicker.cpp58
-rwxr-xr-xindra/newview/llfloateravatarpicker.h3
-rwxr-xr-xindra/newview/llfloaterbvhpreview.cpp20
-rwxr-xr-xindra/newview/llfloaterdisplayname.cpp217
-rwxr-xr-xindra/newview/llfloaterdisplayname.h38
-rw-r--r--indra/newview/llfloaterexperienceprofile.cpp283
-rw-r--r--indra/newview/llfloaterexperienceprofile.h6
-rw-r--r--indra/newview/llfloaterexperiences.cpp225
-rw-r--r--indra/newview/llfloaterexperiences.h17
-rwxr-xr-xindra/newview/llfloatergodtools.cpp6
-rwxr-xr-xindra/newview/llfloaterhoverheight.cpp1
-rwxr-xr-xindra/newview/llfloaterimsession.cpp26
-rwxr-xr-xindra/newview/llfloatermarketplacelistings.cpp2
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp9
-rwxr-xr-xindra/newview/llfloatermodeluploadbase.cpp35
-rwxr-xr-xindra/newview/llfloatermodeluploadbase.h4
-rwxr-xr-xindra/newview/llfloaternamedesc.cpp20
-rwxr-xr-xindra/newview/llfloateroutbox.cpp623
-rwxr-xr-xindra/newview/llfloateroutbox.h116
-rwxr-xr-xindra/newview/llfloaterperms.cpp106
-rwxr-xr-xindra/newview/llfloaterperms.h4
-rwxr-xr-xindra/newview/llfloaterregiondebugconsole.cpp105
-rwxr-xr-xindra/newview/llfloaterregiondebugconsole.h7
-rwxr-xr-xindra/newview/llfloaterregioninfo.cpp122
-rwxr-xr-xindra/newview/llfloaterregioninfo.h5
-rwxr-xr-xindra/newview/llfloaterreporter.cpp110
-rwxr-xr-xindra/newview/llfloaterreporter.h2
-rwxr-xr-xindra/newview/llfloaterscriptlimits.cpp585
-rwxr-xr-xindra/newview/llfloaterscriptlimits.h58
-rwxr-xr-xindra/newview/llfloatertos.cpp86
-rwxr-xr-xindra/newview/llfloatertos.h5
-rwxr-xr-xindra/newview/llfloatertranslationsettings.cpp64
-rwxr-xr-xindra/newview/llfloatertranslationsettings.h2
-rwxr-xr-xindra/newview/llfloaterurlentry.cpp90
-rwxr-xr-xindra/newview/llfloaterurlentry.h7
-rwxr-xr-xindra/newview/llgroupmgr.cpp235
-rwxr-xr-xindra/newview/llgroupmgr.h19
-rwxr-xr-xindra/newview/llhomelocationresponder.cpp108
-rwxr-xr-xindra/newview/llhomelocationresponder.h44
-rwxr-xr-xindra/newview/llhttpretrypolicy.cpp53
-rwxr-xr-xindra/newview/llhttpretrypolicy.h4
-rwxr-xr-xindra/newview/llimview.cpp344
-rwxr-xr-xindra/newview/llimview.h4
-rwxr-xr-xindra/newview/llinventorybridge.cpp241
-rwxr-xr-xindra/newview/llinventorybridge.h10
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp160
-rwxr-xr-xindra/newview/llinventoryfunctions.h4
-rwxr-xr-xindra/newview/llinventorymodel.cpp136
-rwxr-xr-xindra/newview/llinventorymodel.h27
-rwxr-xr-xindra/newview/llinventorypanel.cpp24
-rwxr-xr-xindra/newview/llmarketplacefunctions.cpp1481
-rwxr-xr-xindra/newview/llmarketplacefunctions.h22
-rwxr-xr-xindra/newview/llmaterialmgr.cpp141
-rw-r--r--indra/newview/llmaterialmgr.h49
-rwxr-xr-xindra/newview/llmediadataclient.cpp563
-rwxr-xr-xindra/newview/llmediadataclient.h145
-rwxr-xr-xindra/newview/llmeshrepository.cpp180
-rwxr-xr-xindra/newview/llmeshrepository.h11
-rwxr-xr-xindra/newview/llnotificationhandler.h16
-rwxr-xr-xindra/newview/llnotificationmanager.cpp7
-rwxr-xr-xindra/newview/llpanelclassified.cpp42
-rwxr-xr-xindra/newview/llpanelclassified.h5
-rw-r--r--indra/newview/llpanelexperiencelisteditor.cpp2
-rw-r--r--indra/newview/llpanelexperiencelog.cpp4
-rw-r--r--indra/newview/llpanelexperiencepicker.cpp67
-rw-r--r--indra/newview/llpanelexperiencepicker.h3
-rw-r--r--indra/newview/llpanelgroupexperiences.cpp57
-rw-r--r--indra/newview/llpanelgroupexperiences.h3
-rwxr-xr-xindra/newview/llpanellandmarks.cpp13
-rwxr-xr-xindra/newview/llpanellogin.cpp9
-rwxr-xr-xindra/newview/llpanelme.cpp1
-rwxr-xr-xindra/newview/llpanelplaceinfo.cpp14
-rw-r--r--indra/newview/llpanelsnapshotpostcard.cpp52
-rwxr-xr-xindra/newview/llpathfindingmanager.cpp667
-rwxr-xr-xindra/newview/llpathfindingmanager.h16
-rwxr-xr-xindra/newview/llpostcard.cpp124
-rwxr-xr-xindra/newview/llpostcard.h26
-rwxr-xr-xindra/newview/llpreviewgesture.cpp252
-rwxr-xr-xindra/newview/llpreviewgesture.h1
-rwxr-xr-xindra/newview/llpreviewnotecard.cpp133
-rwxr-xr-xindra/newview/llpreviewnotecard.h2
-rwxr-xr-xindra/newview/llpreviewscript.cpp325
-rwxr-xr-xindra/newview/llpreviewscript.h15
-rwxr-xr-xindra/newview/llproductinforequest.cpp63
-rwxr-xr-xindra/newview/llproductinforequest.h22
-rwxr-xr-xindra/newview/llremoteparcelrequest.cpp108
-rwxr-xr-xindra/newview/llremoteparcelrequest.h24
-rwxr-xr-xindra/newview/llsecapi.cpp41
-rwxr-xr-xindra/newview/llsecapi.h3
-rwxr-xr-xindra/newview/llsidepanelinventory.cpp1
-rwxr-xr-xindra/newview/llsidepaneliteminfo.cpp5
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp25
-rwxr-xr-xindra/newview/llspeakers.cpp99
-rwxr-xr-xindra/newview/llspeakers.h4
-rwxr-xr-xindra/newview/llstartup.cpp74
-rw-r--r--indra/newview/llsyntaxid.cpp140
-rw-r--r--indra/newview/llsyntaxid.h10
-rwxr-xr-xindra/newview/lltexturefetch.cpp64
-rwxr-xr-xindra/newview/lltexturefetch.h13
-rwxr-xr-xindra/newview/lltexturestats.cpp14
-rwxr-xr-xindra/newview/lltexturestatsuploader.cpp49
-rwxr-xr-xindra/newview/lltexturestatsuploader.h40
-rwxr-xr-xindra/newview/lltooldraganddrop.cpp15
-rwxr-xr-xindra/newview/lltranslate.cpp406
-rwxr-xr-xindra/newview/lltranslate.h217
-rw-r--r--indra/newview/lltwitterconnect.cpp564
-rw-r--r--indra/newview/lltwitterconnect.h10
-rwxr-xr-xindra/newview/lluploadfloaterobservers.cpp63
-rwxr-xr-xindra/newview/lluploadfloaterobservers.h15
-rw-r--r--indra/newview/llviewerassetupload.cpp839
-rw-r--r--indra/newview/llviewerassetupload.h236
-rwxr-xr-xindra/newview/llviewerdisplayname.cpp211
-rwxr-xr-xindra/newview/llviewerdisplayname.h53
-rwxr-xr-xindra/newview/llviewerfloaterreg.cpp4
-rw-r--r--indra/newview/llviewerfoldertype.cpp2
-rwxr-xr-xindra/newview/llviewerinventory.cpp92
-rwxr-xr-xindra/newview/llviewermedia.cpp496
-rwxr-xr-xindra/newview/llviewermedia.h15
-rwxr-xr-xindra/newview/llviewermenu.cpp41
-rwxr-xr-xindra/newview/llviewermenufile.cpp587
-rwxr-xr-xindra/newview/llviewermenufile.h68
-rwxr-xr-xindra/newview/llviewermessage.cpp85
-rwxr-xr-xindra/newview/llviewerobject.cpp6
-rwxr-xr-xindra/newview/llviewerobjectlist.cpp468
-rwxr-xr-xindra/newview/llviewerobjectlist.h20
-rwxr-xr-xindra/newview/llviewerparcelmedia.cpp6
-rwxr-xr-xindra/newview/llviewerparcelmgr.cpp12
-rwxr-xr-xindra/newview/llviewerregion.cpp662
-rwxr-xr-xindra/newview/llviewerregion.h9
-rwxr-xr-xindra/newview/llviewerstats.cpp23
-rwxr-xr-xindra/newview/llviewertexture.h6
-rwxr-xr-xindra/newview/llviewertexturelist.cpp2
-rwxr-xr-xindra/newview/llvoavatar.cpp2
-rwxr-xr-xindra/newview/llvoavatarself.cpp196
-rwxr-xr-xindra/newview/llvoavatarself.h5
-rwxr-xr-xindra/newview/llvoicechannel.cpp137
-rwxr-xr-xindra/newview/llvoicechannel.h4
-rwxr-xr-xindra/newview/llvoicevivox.cpp214
-rwxr-xr-xindra/newview/llvoicevivox.h9
-rwxr-xr-xindra/newview/llwebprofile.cpp358
-rwxr-xr-xindra/newview/llwebprofile.h12
-rwxr-xr-xindra/newview/llwlhandlers.cpp215
-rwxr-xr-xindra/newview/llwlhandlers.h46
-rwxr-xr-xindra/newview/llxmlrpctransaction.cpp502
-rwxr-xr-xindra/newview/llxmlrpctransaction.h4
-rwxr-xr-xindra/newview/pipeline.cpp1
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_inventory.xml8
-rwxr-xr-xindra/newview/skins/default/xui/en/menu_viewer.xml7
-rwxr-xr-xindra/newview/tests/llcapabilitylistener_test.cpp271
-rwxr-xr-xindra/newview/tests/llhttpretrypolicy_test.cpp12
-rwxr-xr-xindra/newview/tests/llmediadataclient_test.cpp3
-rwxr-xr-xindra/newview/tests/llremoteparcelrequest_test.cpp2
-rwxr-xr-xindra/newview/tests/lltranslate_test.cpp340
-rwxr-xr-xindra/test/CMakeLists.txt6
-rwxr-xr-xindra/test/io.cpp421
-rwxr-xr-xindra/test/message_tut.cpp2
-rwxr-xr-xindra/viewer_components/login/CMakeLists.txt8
-rwxr-xr-xindra/viewer_components/login/lllogin.cpp251
-rwxr-xr-xindra/viewer_components/login/tests/lllogin_test.cpp191
-rwxr-xr-xindra/viewer_components/updater/CMakeLists.txt18
-rwxr-xr-xindra/viewer_components/updater/llupdatechecker.cpp89
-rwxr-xr-xindra/viewer_components/updater/llupdatechecker.h121
-rwxr-xr-xindra/viewer_components/updater/llupdatedownloader.cpp54
-rwxr-xr-xindra/win_crash_logger/CMakeLists.txt6
320 files changed, 16387 insertions, 28239 deletions
diff --git a/indra/cmake/00-COMPILE-LINK-RUN.txt b/indra/cmake/00-COMPILE-LINK-RUN.txt
index 49b899c50d..162b22865c 100644
--- a/indra/cmake/00-COMPILE-LINK-RUN.txt
+++ b/indra/cmake/00-COMPILE-LINK-RUN.txt
@@ -51,7 +51,6 @@ Compilation
WINVER=0x0501 " "
_WIN32_WINNT=0x0501 " "
LL_OS_DRAGDROP_ENABLED=1 " "
- CARES_STATICLIB " "
LIB_NDOF=1 " "
----------------------------------------------------------------------------
@@ -109,7 +108,6 @@ Compilation
DEBUG_INFO=1
LL_DARWIN=1 " "
LL_OS_DRAGDROP_ENABLED=1 " "
- CARES_STATICLIB " "
LIB_NDOF=1 " "
----------------------------------------------------------------------------
diff --git a/indra/cmake/CARes.cmake b/indra/cmake/CARes.cmake
deleted file mode 100755
index baa55aa49d..0000000000
--- a/indra/cmake/CARes.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- cmake -*-
-include(Linking)
-include(Prebuilt)
-
-set(CARES_FIND_QUIETLY ON)
-set(CARES_FIND_REQUIRED ON)
-
-if (USESYSTEMLIBS)
- include(FindCARes)
-else (USESYSTEMLIBS)
- use_prebuilt_binary(ares)
- add_definitions("-DCARES_STATICLIB")
- if (WINDOWS)
- set(CARES_LIBRARIES areslib)
- elseif (DARWIN)
- set(CARES_LIBRARIES cares)
- else (WINDOWS)
- set(CARES_LIBRARIES cares)
- endif (WINDOWS)
- set(CARES_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/ares)
-endif (USESYSTEMLIBS)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index cd7da5d6c1..d700c7fd99 100755
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -13,7 +13,6 @@ set(cmake_SOURCE_FILES
BerkeleyDB.cmake
Boost.cmake
BuildVersion.cmake
- CARes.cmake
CMakeCopyIfDifferent.cmake
ConfigurePkgConfig.cmake
CURL.cmake
@@ -27,7 +26,6 @@ set(cmake_SOURCE_FILES
FindAPR.cmake
FindAutobuild.cmake
FindBerkeleyDB.cmake
- FindCARes.cmake
FindFMODEX.cmake
FindGLH.cmake
FindGoogleBreakpad.cmake
@@ -58,7 +56,6 @@ set(cmake_SOURCE_FILES
JsonCpp.cmake
LLAddBuildTest.cmake
LLAppearance.cmake
- LLAppearanceUtility.cmake
LLAudio.cmake
LLCharacter.cmake
LLCommon.cmake
diff --git a/indra/cmake/FindCARes.cmake b/indra/cmake/FindCARes.cmake
deleted file mode 100755
index 1ed5b32913..0000000000
--- a/indra/cmake/FindCARes.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- cmake -*-
-
-# - Find c-ares
-# Find the c-ares includes and library
-# This module defines
-# CARES_INCLUDE_DIR, where to find ares.h, etc.
-# CARES_LIBRARIES, the libraries needed to use c-ares.
-# CARES_FOUND, If false, do not try to use c-ares.
-# also defined, but not for general use are
-# CARES_LIBRARY, where to find the c-ares library.
-
-FIND_PATH(CARES_INCLUDE_DIR ares.h
-/usr/local/include
-/usr/include
-)
-
-SET(CARES_NAMES ${CARES_NAMES} cares)
-FIND_LIBRARY(CARES_LIBRARY
- NAMES ${CARES_NAMES}
- PATHS /usr/lib /usr/local/lib
- )
-
-IF (CARES_LIBRARY AND CARES_INCLUDE_DIR)
- SET(CARES_LIBRARIES ${CARES_LIBRARY})
- SET(CARES_FOUND "YES")
-ELSE (CARES_LIBRARY AND CARES_INCLUDE_DIR)
- SET(CARES_FOUND "NO")
-ENDIF (CARES_LIBRARY AND CARES_INCLUDE_DIR)
-
-
-IF (CARES_FOUND)
- IF (NOT CARES_FIND_QUIETLY)
- MESSAGE(STATUS "Found c-ares: ${CARES_LIBRARIES}")
- ENDIF (NOT CARES_FIND_QUIETLY)
-ELSE (CARES_FOUND)
- IF (CARES_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find c-ares library")
- ENDIF (CARES_FIND_REQUIRED)
-ENDIF (CARES_FOUND)
-
-# Deprecated declarations.
-SET (NATIVE_CARES_INCLUDE_PATH ${CARES_INCLUDE_DIR} )
-GET_FILENAME_COMPONENT (NATIVE_CARES_LIB_PATH ${CARES_LIBRARY} PATH)
-
-MARK_AS_ADVANCED(
- CARES_LIBRARY
- CARES_INCLUDE_DIR
- )
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index ac5c5c6a2a..db8b95dbe2 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -35,6 +35,7 @@ INCLUDE(GoogleMock)
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
llcommon
+ llcorehttp
)
IF(NOT "${project}" STREQUAL "llmath")
# add llmath as a dep unless the tested module *is* llmath!
@@ -49,6 +50,9 @@ INCLUDE(GoogleMock)
${GOOGLEMOCK_INCLUDE_DIRS}
)
SET(alltest_LIBRARIES
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
${GOOGLEMOCK_LIBRARIES}
${PTHREAD_LIBRARY}
${WINDOWS_LIBRARIES}
@@ -191,6 +195,9 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
SET(libraries
${library_dependencies}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
${GOOGLEMOCK_LIBRARIES}
${PTHREAD_LIBRARY}
)
diff --git a/indra/cmake/LLAppearance.cmake b/indra/cmake/LLAppearance.cmake
index bd3795a526..ae265d07e3 100644
--- a/indra/cmake/LLAppearance.cmake
+++ b/indra/cmake/LLAppearance.cmake
@@ -1,6 +1,9 @@
# -*- cmake -*-
include(Variables)
+include(Boost)
+include(LLMessage)
+include(LLCoreHttp)
set(LLAPPEARANCE_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llappearance
@@ -12,6 +15,13 @@ if (BUILD_HEADLESS)
)
endif (BUILD_HEADLESS)
-set(LLAPPEARANCE_LIBRARIES llappearance)
+set(LLAPPEARANCE_LIBRARIES llappearance
+ llmessage
+ llcorehttp
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
+ )
+
diff --git a/indra/cmake/LLAppearanceUtility.cmake b/indra/cmake/LLAppearanceUtility.cmake
index 709b91c134..28b49bf75f 100644
--- a/indra/cmake/LLAppearanceUtility.cmake
+++ b/indra/cmake/LLAppearanceUtility.cmake
@@ -1,5 +1,6 @@
# -*- cmake -*-
include(Prebuilt)
+include(Boost)
# Linux proprietary build only
if (INSTALL_PROPRIETARY)
@@ -10,3 +11,4 @@ if (INSTALL_PROPRIETARY)
endif (LINUX)
endif (INSTALL_PROPRIETARY)
+
diff --git a/indra/cmake/LLCoreHttp.cmake b/indra/cmake/LLCoreHttp.cmake
index 61e4b23d98..379ae207de 100755
--- a/indra/cmake/LLCoreHttp.cmake
+++ b/indra/cmake/LLCoreHttp.cmake
@@ -1,16 +1,17 @@
# -*- cmake -*-
-include(CARes)
include(CURL)
include(OpenSSL)
include(Boost)
set(LLCOREHTTP_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llcorehttp
- ${CARES_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
${BOOST_INCLUDE_DIRS}
)
-set(LLCOREHTTP_LIBRARIES llcorehttp)
+set(LLCOREHTTP_LIBRARIES llcorehttp
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY})
diff --git a/indra/cmake/LLMessage.cmake b/indra/cmake/LLMessage.cmake
index 0143d04fd7..7be53ec0ec 100755
--- a/indra/cmake/LLMessage.cmake
+++ b/indra/cmake/LLMessage.cmake
@@ -1,13 +1,11 @@
# -*- cmake -*-
-include(CARes)
include(CURL)
include(OpenSSL)
include(XmlRpcEpi)
set(LLMESSAGE_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llmessage
- ${CARES_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
)
diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt
index c0fc1b2be0..029096df37 100755
--- a/indra/linux_crash_logger/CMakeLists.txt
+++ b/indra/linux_crash_logger/CMakeLists.txt
@@ -4,6 +4,7 @@ project(linux_crash_logger)
include(00-Common)
include(GLH)
+include(LLCoreHttp)
include(LLCommon)
include(LLCrashLogger)
include(LLMath)
@@ -13,8 +14,10 @@ include(LLXML)
include(Linking)
include(UI)
include(FreeType)
+include(Boost)
include_directories(
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLCRASHLOGGER_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
@@ -53,6 +56,10 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES})
+# llcommon uses `clock_gettime' which is provided by librt on linux.
+set(LIBRT_LIBRARY rt)
+
+
target_link_libraries(linux-crash-logger
${LLCRASHLOGGER_LIBRARIES}
${LLVFS_LIBRARIES}
@@ -60,10 +67,14 @@ target_link_libraries(linux-crash-logger
${LLMESSAGE_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLCOMMON_LIBRARIES}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
${UI_LIBRARIES}
${DB_LIBRARIES}
${FREETYPE_LIBRARIES}
+ ${LIBRT_LIBRARY}
)
add_custom_target(linux-crash-logger-target ALL
diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt
index 0dbd58b7cd..20eb4678dd 100644
--- a/indra/llappearance/CMakeLists.txt
+++ b/indra/llappearance/CMakeLists.txt
@@ -9,6 +9,7 @@ include(LLImage)
include(LLInventory)
include(LLMath)
include(LLMessage)
+include(LLCoreHttp)
include(LLRender)
include(LLVFS)
include(LLWindow)
@@ -86,6 +87,8 @@ target_link_libraries(llappearance
${LLMATH_LIBRARIES}
${LLXML_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLCOMMON_LIBRARIES}
)
@@ -101,6 +104,8 @@ if (BUILD_HEADLESS)
${LLMATH_LIBRARIES}
${LLXML_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLCOMMON_LIBRARIES}
)
endif (BUILD_HEADLESS)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 5863310162..8ae487354a 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -8,6 +8,7 @@ include(LLCommon)
include(Linking)
include(Boost)
include(LLSharedLibs)
+include(JsonCpp)
include(GoogleBreakpad)
include(GooglePerfTools)
include(Copy3rdPartyLibs)
@@ -17,6 +18,7 @@ include(URIPARSER)
include_directories(
${EXPAT_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
+ ${JSONCPP_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
${BREAKPAD_INCLUDE_DIRECTORIES}
${URIPARSER_INCLUDE_DIRS}
@@ -86,6 +88,7 @@ set(llcommon_SOURCE_FILES
llrefcount.cpp
llrun.cpp
llsd.cpp
+ llsdjson.cpp
llsdparam.cpp
llsdserialize.cpp
llsdserialize_xml.cpp
@@ -195,6 +198,7 @@ set(llcommon_HEADER_FILES
llrefcount.h
llsafehandle.h
llsd.h
+ llsdjson.h
llsdparam.h
llsdserialize.h
llsdserialize_xml.h
@@ -262,10 +266,14 @@ target_link_libraries(
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
+ ${JSONCPP_LIBRARIES}
${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
${BOOST_PROGRAM_OPTIONS_LIBRARY}
${BOOST_REGEX_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
${GOOGLE_PERFTOOLS_LIBRARIES}
${URIPARSER_LIBRARIES}
)
@@ -308,7 +316,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
- LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs};${BOOST_CONTEXT_LIBRARY};${BOOST_THREAD_LIBRARY};${BOOST_COROUTINE_LIBRARY};${BOOST_SYSTEM_LIBRARY}")
+ LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs};${BOOST_COROUTINE_LIBRARY};${BOOST_CONTEXT_LIBRARY};${BOOST_THREAD_LIBRARY};${BOOST_SYSTEM_LIBRARY}")
LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}")
diff --git a/indra/llcommon/fix_macros.h b/indra/llcommon/fix_macros.h
index ef959decff..43c09c54bc 100755
--- a/indra/llcommon/fix_macros.h
+++ b/indra/llcommon/fix_macros.h
@@ -16,10 +16,6 @@
// these macros all over again.
// who injects MACROS with such generic names?! Grr.
-#ifdef equivalent
-#undef equivalent
-#endif
-
#ifdef check
#undef check
#endif
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 5cfcdab41c..e5a913a6a9 100755
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -51,6 +51,7 @@
#include <cstdlib>
#include <ctime>
#include <iosfwd>
+#include <memory>
// Linden only libs in alpha-order other than stdtypes.h
// *NOTE: Please keep includes here to a minimum, see above.
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index baaddcaed1..d76401d01b 100755
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -39,6 +39,44 @@
#include "llerror.h"
#include "stringize.h"
+// do nothing, when we need nothing done
+void LLCoros::no_cleanup(CoroData*) {}
+
+// CoroData for the currently-running coroutine. Use a thread_specific_ptr
+// because each thread potentially has its own distinct pool of coroutines.
+// This thread_specific_ptr does NOT own the CoroData object! That's owned by
+// LLCoros::mCoros. It merely identifies it. For this reason we instantiate
+// it with a no-op cleanup function.
+boost::thread_specific_ptr<LLCoros::CoroData>
+LLCoros::sCurrentCoro(LLCoros::no_cleanup);
+
+//static
+LLCoros::coro::self& LLCoros::get_self()
+{
+ CoroData* current = sCurrentCoro.get();
+ if (! current)
+ {
+ LL_ERRS("LLCoros") << "Calling get_self() from non-coroutine context!" << LL_ENDL;
+ }
+ return *current->mSelf;
+}
+
+llcoro::Suspending::Suspending():
+ mSuspended(LLCoros::sCurrentCoro.get())
+{
+ // Revert mCurrentCoro to the value it had at the moment we last switched
+ // into this coroutine.
+ LLCoros::sCurrentCoro.reset(mSuspended->mPrev);
+}
+
+llcoro::Suspending::~Suspending()
+{
+ // Okay, we're back, update our mPrev
+ mSuspended->mPrev = LLCoros::sCurrentCoro.get();
+ // and reinstate our sCurrentCoro.
+ LLCoros::sCurrentCoro.reset(mSuspended);
+}
+
LLCoros::LLCoros():
// MAINT-2724: default coroutine stack size too small on Windows.
// Previously we used
@@ -58,9 +96,9 @@ bool LLCoros::cleanup(const LLSD&)
{
// Has this coroutine exited (normal return, exception, exit() call)
// since last tick?
- if (mi->second->exited())
+ if (mi->second->mCoro.exited())
{
- LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
+ LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
// The erase() call will invalidate its passed iterator value --
// so increment mi FIRST -- but pass its original value to
// erase(). This is what postincrement is all about.
@@ -94,7 +132,7 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const
{
if (mCoros.find(name) == mCoros.end())
{
- LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
+ LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
return name;
}
}
@@ -114,20 +152,15 @@ bool LLCoros::kill(const std::string& name)
return true;
}
-std::string LLCoros::getNameByID(const void* self_id) const
+std::string LLCoros::getName() const
{
- // Walk the existing coroutines, looking for one from which the 'self_id'
- // passed to us comes.
- for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)
+ CoroData* current = sCurrentCoro.get();
+ if (! current)
{
- namespace coro_private = boost::dcoroutines::detail;
- if (static_cast<void*>(coro_private::coroutine_accessor::get_impl(const_cast<coro&>(*mi->second)).get())
- == self_id)
- {
- return mi->first;
- }
+ // not in a coroutine
+ return "";
}
- return "";
+ return current->mName;
}
void LLCoros::setStackSize(S32 stacksize)
@@ -136,10 +169,24 @@ void LLCoros::setStackSize(S32 stacksize)
mStackSize = stacksize;
}
+// Top-level wrapper around caller's coroutine callable. This function accepts
+// the coroutine library's implicit coro::self& parameter and sets sCurrentSelf
+// but does not pass it down to the caller's callable.
+void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& callable)
+{
+ // capture the 'self' param in CoroData
+ data->mSelf = &self;
+ // run the code the caller actually wants in the coroutine
+ callable();
+ // This cleanup isn't perfectly symmetrical with the way we initially set
+ // data->mPrev, but this is our last chance to reset mCurrentCoro.
+ sCurrentCoro.reset(data->mPrev);
+}
+
/*****************************************************************************
* MUST BE LAST
*****************************************************************************/
-// Turn off MSVC optimizations for just LLCoros::launchImpl() -- see
+// Turn off MSVC optimizations for just LLCoros::launch() -- see
// DEV-32777. But MSVC doesn't support push/pop for optimization flags as it
// does for warning suppression, and we really don't want to force
// optimization ON for other code even in Debug or RelWithDebInfo builds.
@@ -147,15 +194,33 @@ void LLCoros::setStackSize(S32 stacksize)
#if LL_MSVC
// work around broken optimizations
#pragma warning(disable: 4748)
+#pragma warning(disable: 4355) // 'this' used in initializer list: yes, intentionally
#pragma optimize("", off)
#endif // LL_MSVC
-std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro)
+LLCoros::CoroData::CoroData(CoroData* prev, const std::string& name,
+ const callable_t& callable, S32 stacksize):
+ mPrev(prev),
+ mName(name),
+ // Wrap the caller's callable in our toplevel() function so we can manage
+ // sCurrentCoro appropriately at startup and shutdown of each coroutine.
+ mCoro(boost::bind(toplevel, _1, this, callable), stacksize),
+ mSelf(0)
+{
+}
+
+std::string LLCoros::launch(const std::string& prefix, const callable_t& callable)
{
std::string name(generateDistinctName(prefix));
+ // pass the current value of sCurrentCoro as previous context
+ CoroData* newCoro = new CoroData(sCurrentCoro.get(), name,
+ callable, mStackSize);
+ // Store it in our pointer map
mCoros.insert(name, newCoro);
+ // also set it as current
+ sCurrentCoro.reset(newCoro);
/* Run the coroutine until its first wait, then return here */
- (*newCoro)(std::nothrow);
+ (newCoro->mCoro)(std::nothrow);
return name;
}
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 01ee11da1a..56eed8cafe 100755
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -32,12 +32,17 @@
#include <boost/dcoroutine/coroutine.hpp>
#include "llsingleton.h"
#include <boost/ptr_container/ptr_map.hpp>
+#include <boost/function.hpp>
+#include <boost/thread/tss.hpp>
#include <string>
-#include <boost/preprocessor/repetition/enum_params.hpp>
-#include <boost/preprocessor/repetition/enum_binary_params.hpp>
-#include <boost/preprocessor/iteration/local.hpp>
#include <stdexcept>
+// forward-declare helper class
+namespace llcoro
+{
+class Suspending;
+}
+
/**
* Registry of named Boost.Coroutine instances
*
@@ -80,8 +85,8 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
public:
/// Canonical boost::dcoroutines::coroutine signature we use
typedef boost::dcoroutines::coroutine<void()> coro;
- /// Canonical 'self' type
- typedef coro::self self;
+ /// Canonical callable type
+ typedef boost::function<void()> callable_t;
/**
* Create and start running a new coroutine with specified name. The name
@@ -94,39 +99,33 @@ public:
* {
* public:
* ...
- * // Do NOT NOT NOT accept reference params other than 'self'!
+ * // Do NOT NOT NOT accept reference params!
* // Pass by value only!
- * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
+ * void myCoroutineMethod(std::string, LLSD);
* ...
* };
* ...
* std::string name = LLCoros::instance().launch(
- * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
+ * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this,
* "somestring", LLSD(17));
* @endcode
*
- * Your function/method must accept LLCoros::self& as its first parameter.
- * It can accept any other parameters you want -- but ONLY BY VALUE!
- * Other reference parameters are a BAD IDEA! You Have Been Warned. See
+ * Your function/method can accept any parameters you want -- but ONLY BY
+ * VALUE! Reference parameters are a BAD IDEA! You Have Been Warned. See
* DEV-32777 comments for an explanation.
*
- * Pass a callable that accepts the single LLCoros::self& parameter. It
- * may work to pass a free function whose only parameter is 'self'; for
- * all other cases use boost::bind(). Of course, for a non-static class
- * method, the first parameter must be the class instance. Use the
- * placeholder _1 for the 'self' parameter. Any other parameters should be
- * passed via the bind() expression.
+ * Pass a nullary callable. It works to directly pass a nullary free
+ * function (or static method); for all other cases use boost::bind(). Of
+ * course, for a non-static class method, the first parameter must be the
+ * class instance. Any other parameters should be passed via the bind()
+ * expression.
*
* launch() tweaks the suggested name so it won't collide with any
* existing coroutine instance, creates the coroutine instance, registers
* it with the tweaked name and runs it until its first wait. At that
* point it returns the tweaked name.
*/
- template <typename CALLABLE>
- std::string launch(const std::string& prefix, const CALLABLE& callable)
- {
- return launchImpl(prefix, new coro(callable, mStackSize));
- }
+ std::string launch(const std::string& prefix, const callable_t& callable);
/**
* Abort a running coroutine by name. Normally, when a coroutine either
@@ -138,33 +137,85 @@ public:
bool kill(const std::string& name);
/**
- * From within a coroutine, pass its @c self object to look up the
- * (tweaked) name string by which this coroutine is registered. Returns
- * the empty string if not found (e.g. if the coroutine was launched by
- * hand rather than using LLCoros::launch()).
+ * From within a coroutine, look up the (tweaked) name string by which
+ * this coroutine is registered. Returns the empty string if not found
+ * (e.g. if the coroutine was launched by hand rather than using
+ * LLCoros::launch()).
*/
- template <typename COROUTINE_SELF>
- std::string getName(const COROUTINE_SELF& self) const
- {
- return getNameByID(self.get_id());
- }
-
- /// getName() by self.get_id()
- std::string getNameByID(const void* self_id) const;
+ std::string getName() const;
/// for delayed initialization
void setStackSize(S32 stacksize);
+ /// get the current coro::self& for those who really really care
+ static coro::self& get_self();
+
private:
- friend class LLSingleton<LLCoros>;
LLCoros();
- std::string launchImpl(const std::string& prefix, coro* newCoro);
+ friend class LLSingleton<LLCoros>;
+ friend class llcoro::Suspending;
std::string generateDistinctName(const std::string& prefix) const;
bool cleanup(const LLSD&);
+ struct CoroData;
+ static void no_cleanup(CoroData*);
+ static void toplevel(coro::self& self, CoroData* data, const callable_t& callable);
S32 mStackSize;
- typedef boost::ptr_map<std::string, coro> CoroMap;
+
+ // coroutine-local storage, as it were: one per coro we track
+ struct CoroData
+ {
+ CoroData(CoroData* prev, const std::string& name,
+ const callable_t& callable, S32 stacksize);
+
+ // The boost::dcoroutines library supports asymmetric coroutines. Every
+ // time we context switch out of a coroutine, we pass control to the
+ // previously-active one (or to the non-coroutine stack owned by the
+ // thread). So our management of the "current" coroutine must be able to
+ // restore the previous value when we're about to switch away.
+ CoroData* mPrev;
+ // tweaked name of the current coroutine
+ const std::string mName;
+ // the actual coroutine instance
+ LLCoros::coro mCoro;
+ // When the dcoroutine library calls a top-level callable, it implicitly
+ // passes coro::self& as the first parameter. All our consumer code used
+ // to explicitly pass coro::self& down through all levels of call stack,
+ // because at the leaf level we need it for context-switching. But since
+ // coroutines are based on cooperative switching, we can cause the
+ // top-level entry point to stash a pointer to the currently-running
+ // coroutine, and manage it appropriately as we switch out and back in.
+ // That eliminates the need to pass it as an explicit parameter down
+ // through every level, which is unfortunately viral in nature. Finding it
+ // implicitly rather than explicitly allows minor maintenance in which a
+ // leaf-level function adds a new async I/O call that suspends the calling
+ // coroutine, WITHOUT having to propagate coro::self& through every
+ // function signature down to that point -- and of course through every
+ // other caller of every such function.
+ LLCoros::coro::self* mSelf;
+ };
+ typedef boost::ptr_map<std::string, CoroData> CoroMap;
CoroMap mCoros;
+
+ // identify the current coroutine's CoroData
+ static boost::thread_specific_ptr<LLCoros::CoroData> sCurrentCoro;
+};
+
+namespace llcoro
+{
+
+/// Instantiate one of these in a block surrounding any leaf point when
+/// control literally switches away from this coroutine.
+class Suspending
+{
+public:
+ Suspending();
+ ~Suspending();
+
+private:
+ LLCoros::CoroData* mSuspended;
};
+} // namespace llcoro
+
#endif /* ! defined(LL_LLCOROS_H) */
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 63040e1772..b1b5e9be7d 100755
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -354,6 +354,7 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__)
#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__)
// alternative to llassert_always that prints explanatory message
+#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(##__VA_ARGS__) << "(" #exp ")"
#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(##__VA_ARGS__) << "(" #exp ")"
// Only print the log message once (good for warnings or infos that would otherwise
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
index 81cc33fbba..c9bfcacedc 100755
--- a/indra/llcommon/lleventcoro.cpp
+++ b/indra/llcommon/lleventcoro.cpp
@@ -34,38 +34,63 @@
#include <map>
// std headers
// external library headers
+#include <boost/dcoroutine/coroutine.hpp>
+#include <boost/dcoroutine/future.hpp>
// other Linden headers
#include "llsdserialize.h"
#include "llerror.h"
#include "llcoros.h"
-std::string LLEventDetail::listenerNameForCoroImpl(const void* self_id)
+namespace
{
- // First, if this coroutine was launched by LLCoros::launch(), find that name.
- std::string name(LLCoros::instance().getNameByID(self_id));
+
+/**
+ * suspendUntilEventOn() permits a coroutine to temporarily listen on an
+ * LLEventPump any number of times. We don't really want to have to ask
+ * the caller to label each such call with a distinct string; the whole
+ * point of suspendUntilEventOn() is to present a nice sequential interface to
+ * the underlying LLEventPump-with-named-listeners machinery. So we'll use
+ * LLEventPump::inventName() to generate a distinct name for each
+ * temporary listener. On the other hand, because a given coroutine might
+ * call suspendUntilEventOn() any number of times, we don't really want to
+ * consume an arbitrary number of generated inventName()s: that namespace,
+ * though large, is nonetheless finite. So we memoize an invented name for
+ * each distinct coroutine instance.
+ */
+std::string listenerNameForCoro()
+{
+ // If this coroutine was launched by LLCoros::launch(), find that name.
+ std::string name(LLCoros::instance().getName());
if (! name.empty())
{
return name;
}
- // Apparently this coroutine wasn't launched by LLCoros::launch(). Check
- // whether we have a memo for this self_id.
- typedef std::map<const void*, std::string> MapType;
- static MapType memo;
- MapType::const_iterator found = memo.find(self_id);
- if (found != memo.end())
- {
- // this coroutine instance has called us before, reuse same name
- return found->second;
- }
// this is the first time we've been called for this coroutine instance
name = LLEventPump::inventName("coro");
- memo[self_id] = name;
- LL_INFOS("LLEventCoro") << "listenerNameForCoroImpl(" << self_id << "): inventing coro name '"
+ LL_INFOS("LLEventCoro") << "listenerNameForCoro(): inventing coro name '"
<< name << "'" << LL_ENDL;
return name;
}
-void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
+/**
+ * Implement behavior described for postAndSuspend()'s @a replyPumpNamePath
+ * parameter:
+ *
+ * * If <tt>path.isUndefined()</tt>, do nothing.
+ * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value
+ * into <tt>dest[path.asString()]</tt>.
+ * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a
+ * value into <tt>dest[path.asInteger()]</tt>.
+ * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step
+ * down through the structure of @a dest. The last array entry in @a
+ * path specifies the entry in the lowest-level structure in @a dest
+ * into which to store @a value.
+ *
+ * @note
+ * In the degenerate case in which @a path is an empty array, @a dest will
+ * @em become @a value rather than @em containing it.
+ */
+void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
{
if (rawPath.isUndefined())
{
@@ -118,6 +143,155 @@ void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD&
*pdest = value;
}
+} // anonymous
+
+void llcoro::suspend()
+{
+ // By viewer convention, we post an event on the "mainloop" LLEventPump
+ // each iteration of the main event-handling loop. So waiting for a single
+ // event on "mainloop" gives us a one-frame suspend.
+ suspendUntilEventOn("mainloop");
+}
+
+LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+ const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath)
+{
+ // declare the future
+ boost::dcoroutines::future<LLSD> future(LLCoros::get_self());
+ // make a callback that will assign a value to the future, and listen on
+ // the specified LLEventPump with that callback
+ std::string listenerName(listenerNameForCoro());
+ LLTempBoundListener connection(
+ replyPump.getPump().listen(listenerName,
+ voidlistener(boost::dcoroutines::make_callback(future))));
+ // skip the "post" part if requestPump is default-constructed
+ if (requestPump)
+ {
+ // If replyPumpNamePath is non-empty, store the replyPump name in the
+ // request event.
+ LLSD modevent(event);
+ storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName());
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName
+ << " posting to " << requestPump.getPump().getName()
+ << LL_ENDL;
+
+ // *NOTE:Mani - Removed because modevent could contain user's hashed passwd.
+ // << ": " << modevent << LL_ENDL;
+ requestPump.getPump().post(modevent);
+ }
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName
+ << " about to wait on LLEventPump " << replyPump.getPump().getName()
+ << LL_ENDL;
+ // trying to dereference ("resolve") the future makes us wait for it
+ LLSD value;
+ {
+ // instantiate Suspending to manage the "current" coroutine
+ llcoro::Suspending suspended;
+ value = *future;
+ } // destroy Suspending as soon as we're back
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << listenerName
+ << " resuming with " << value << LL_ENDL;
+ // returning should disconnect the connection
+ return value;
+}
+
+namespace
+{
+
+/**
+ * This helper is specifically for the two-pump version of suspendUntilEventOn().
+ * We use a single future object, but we want to listen on two pumps with it.
+ * Since we must still adapt from (the callable constructed by)
+ * boost::dcoroutines::make_callback() (void return) to provide an event
+ * listener (bool return), we've adapted VoidListener for the purpose. The
+ * basic idea is that we construct a distinct instance of WaitForEventOnHelper
+ * -- binding different instance data -- for each of the pumps. Then, when a
+ * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine
+ * that LLSD with its discriminator to feed the future object.
+ */
+template <typename LISTENER>
+class WaitForEventOnHelper
+{
+public:
+ WaitForEventOnHelper(const LISTENER& listener, int discriminator):
+ mListener(listener),
+ mDiscrim(discriminator)
+ {}
+ // this signature is required for an LLEventPump listener
+ bool operator()(const LLSD& event)
+ {
+ // our future object is defined to accept LLEventWithID
+ mListener(LLEventWithID(event, mDiscrim));
+ // don't swallow the event, let other listeners see it
+ return false;
+ }
+private:
+ LISTENER mListener;
+ const int mDiscrim;
+};
+
+/// WaitForEventOnHelper type-inference helper
+template <typename LISTENER>
+WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator)
+{
+ return WaitForEventOnHelper<LISTENER>(listener, discriminator);
+}
+
+} // anonymous
+
+namespace llcoro
+{
+
+LLEventWithID postAndSuspend2(const LLSD& event,
+ const LLEventPumpOrPumpName& requestPump,
+ const LLEventPumpOrPumpName& replyPump0,
+ const LLEventPumpOrPumpName& replyPump1,
+ const LLSD& replyPump0NamePath,
+ const LLSD& replyPump1NamePath)
+{
+ // declare the future
+ boost::dcoroutines::future<LLEventWithID> future(LLCoros::get_self());
+ // either callback will assign a value to this future; listen on
+ // each specified LLEventPump with a callback
+ std::string name(listenerNameForCoro());
+ LLTempBoundListener connection0(
+ replyPump0.getPump().listen(name + "a",
+ wfeoh(boost::dcoroutines::make_callback(future), 0)));
+ LLTempBoundListener connection1(
+ replyPump1.getPump().listen(name + "b",
+ wfeoh(boost::dcoroutines::make_callback(future), 1)));
+ // skip the "post" part if requestPump is default-constructed
+ if (requestPump)
+ {
+ // If either replyPumpNamePath is non-empty, store the corresponding
+ // replyPump name in the request event.
+ LLSD modevent(event);
+ storeToLLSDPath(modevent, replyPump0NamePath,
+ replyPump0.getPump().getName());
+ storeToLLSDPath(modevent, replyPump1NamePath,
+ replyPump1.getPump().getName());
+ LL_DEBUGS("lleventcoro") << "postAndSuspend2(): coroutine " << name
+ << " posting to " << requestPump.getPump().getName()
+ << ": " << modevent << LL_ENDL;
+ requestPump.getPump().post(modevent);
+ }
+ LL_DEBUGS("lleventcoro") << "postAndSuspend2(): coroutine " << name
+ << " about to wait on LLEventPumps " << replyPump0.getPump().getName()
+ << ", " << replyPump1.getPump().getName() << LL_ENDL;
+ // trying to dereference ("resolve") the future makes us wait for it
+ LLEventWithID value;
+ {
+ // instantiate Suspending to manage "current" coroutine
+ llcoro::Suspending suspended;
+ value = *future;
+ } // destroy Suspending as soon as we're back
+ LL_DEBUGS("lleventcoro") << "postAndSuspend(): coroutine " << name
+ << " resuming with (" << value.first << ", " << value.second << ")"
+ << LL_ENDL;
+ // returning should disconnect both connections
+ return value;
+}
+
LLSD errorException(const LLEventWithID& result, const std::string& desc)
{
// If the result arrived on the error pump (pump 1), instead of
@@ -144,3 +318,5 @@ LLSD errorLog(const LLEventWithID& result, const std::string& desc)
// A simple return must therefore be from the reply pump (pump 0).
return result.first;
}
+
+} // namespace llcoro
diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h
index abbeeaa373..6fda3d2572 100755
--- a/indra/llcommon/lleventcoro.h
+++ b/indra/llcommon/lleventcoro.h
@@ -29,8 +29,6 @@
#if ! defined(LL_LLEVENTCORO_H)
#define LL_LLEVENTCORO_H
-#include <boost/dcoroutine/coroutine.hpp>
-#include <boost/dcoroutine/future.hpp>
#include <boost/optional.hpp>
#include <string>
#include <stdexcept>
@@ -74,13 +72,16 @@ private:
boost::optional<LLEventPump&> mPump;
};
+namespace llcoro
+{
+
/// This is an adapter for a signature like void LISTENER(const LLSD&), which
/// isn't a valid LLEventPump listener: such listeners should return bool.
template <typename LISTENER>
-class LLVoidListener
+class VoidListener
{
public:
- LLVoidListener(const LISTENER& listener):
+ VoidListener(const LISTENER& listener):
mListener(listener)
{}
bool operator()(const LLSD& event)
@@ -93,92 +94,45 @@ private:
LISTENER mListener;
};
-/// LLVoidListener helper function to infer the type of the LISTENER
+/// VoidListener helper function to infer the type of the LISTENER
template <typename LISTENER>
-LLVoidListener<LISTENER> voidlistener(const LISTENER& listener)
+VoidListener<LISTENER> voidlistener(const LISTENER& listener)
{
- return LLVoidListener<LISTENER>(listener);
+ return VoidListener<LISTENER>(listener);
}
-namespace LLEventDetail
-{
- /// Implementation for listenerNameForCoro(), see below
- LL_COMMON_API std::string listenerNameForCoroImpl(const void* self_id);
-
- /**
- * waitForEventOn() permits a coroutine to temporarily listen on an
- * LLEventPump any number of times. We don't really want to have to ask
- * the caller to label each such call with a distinct string; the whole
- * point of waitForEventOn() is to present a nice sequential interface to
- * the underlying LLEventPump-with-named-listeners machinery. So we'll use
- * LLEventPump::inventName() to generate a distinct name for each
- * temporary listener. On the other hand, because a given coroutine might
- * call waitForEventOn() any number of times, we don't really want to
- * consume an arbitrary number of generated inventName()s: that namespace,
- * though large, is nonetheless finite. So we memoize an invented name for
- * each distinct coroutine instance (each different 'self' object). We
- * can't know the type of 'self', because it depends on the coroutine
- * body's signature. So we cast its address to void*, looking for distinct
- * pointer values. Yes, that means that an early coroutine could cache a
- * value here, then be destroyed, only to be supplanted by a later
- * coroutine (of the same or different type), and we'll end up
- * "recognizing" the second one and reusing the listener name -- but
- * that's okay, since it won't collide with any listener name used by the
- * earlier coroutine since that earlier coroutine no longer exists.
- */
- template <typename COROUTINE_SELF>
- std::string listenerNameForCoro(COROUTINE_SELF& self)
- {
- return listenerNameForCoroImpl(self.get_id());
- }
-
- /**
- * Implement behavior described for postAndWait()'s @a replyPumpNamePath
- * parameter:
- *
- * * If <tt>path.isUndefined()</tt>, do nothing.
- * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value
- * into <tt>dest[path.asString()]</tt>.
- * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a
- * value into <tt>dest[path.asInteger()]</tt>.
- * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step
- * down through the structure of @a dest. The last array entry in @a
- * path specifies the entry in the lowest-level structure in @a dest
- * into which to store @a value.
- *
- * @note
- * In the degenerate case in which @a path is an empty array, @a dest will
- * @em become @a value rather than @em containing it.
- */
- LL_COMMON_API void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value);
-} // namespace LLEventDetail
+/**
+ * Yield control from a coroutine for one "mainloop" tick. If your coroutine
+ * runs without suspending for nontrivial time, sprinkle in calls to this
+ * function to avoid stalling the rest of the viewer processing.
+ */
+void suspend();
/**
- * Post specified LLSD event on the specified LLEventPump, then wait for a
+ * Post specified LLSD event on the specified LLEventPump, then suspend for a
* response on specified other LLEventPump. This is more than mere
* convenience: the difference between this function and the sequence
* @code
* requestPump.post(myEvent);
- * LLSD reply = waitForEventOn(self, replyPump);
+ * LLSD reply = suspendUntilEventOn(replyPump);
* @endcode
* is that the sequence above fails if the reply is posted immediately on
* @a replyPump, that is, before <tt>requestPump.post()</tt> returns. In the
* sequence above, the running coroutine isn't even listening on @a replyPump
- * until <tt>requestPump.post()</tt> returns and @c waitForEventOn() is
+ * until <tt>requestPump.post()</tt> returns and @c suspendUntilEventOn() is
* entered. Therefore, the coroutine completely misses an immediate reply
- * event, making it wait indefinitely.
+ * event, making it suspend indefinitely.
*
- * By contrast, postAndWait() listens on the @a replyPump @em before posting
+ * By contrast, postAndSuspend() listens on the @a replyPump @em before posting
* the specified LLSD event on the specified @a requestPump.
*
- * @param self The @c self object passed into a coroutine
* @param event LLSD data to be posted on @a requestPump
* @param requestPump an LLEventPump on which to post @a event. Pass either
* the LLEventPump& or its string name. However, if you pass a
* default-constructed @c LLEventPumpOrPumpName, we skip the post() call.
- * @param replyPump an LLEventPump on which postAndWait() will listen for a
+ * @param replyPump an LLEventPump on which postAndSuspend() will listen for a
* reply. Pass either the LLEventPump& or its string name. The calling
- * coroutine will wait until that reply arrives. (If you're concerned about a
+ * coroutine will suspend until that reply arrives. (If you're concerned about a
* reply that might not arrive, please see also LLEventTimeout.)
* @param replyPumpNamePath specifies the location within @a event in which to
* store <tt>replyPump.getName()</tt>. This is a strictly optional convenience
@@ -201,101 +155,29 @@ namespace LLEventDetail
* @a replyPumpNamePath specifies the entry in the lowest-level structure in
* @a event into which to store <tt>replyPump.getName()</tt>.
*/
-template <typename SELF>
-LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
- const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD())
-{
- // declare the future
- boost::dcoroutines::future<LLSD> future(self);
- // make a callback that will assign a value to the future, and listen on
- // the specified LLEventPump with that callback
- std::string listenerName(LLEventDetail::listenerNameForCoro(self));
- LLTempBoundListener connection(
- replyPump.getPump().listen(listenerName,
- voidlistener(boost::dcoroutines::make_callback(future))));
- // skip the "post" part if requestPump is default-constructed
- if (requestPump)
- {
- // If replyPumpNamePath is non-empty, store the replyPump name in the
- // request event.
- LLSD modevent(event);
- LLEventDetail::storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName());
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
- << " posting to " << requestPump.getPump().getName()
- << LL_ENDL;
-
- // *NOTE:Mani - Removed because modevent could contain user's hashed passwd.
- // << ": " << modevent << LL_ENDL;
- requestPump.getPump().post(modevent);
- }
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
- << " about to wait on LLEventPump " << replyPump.getPump().getName()
- << LL_ENDL;
- // trying to dereference ("resolve") the future makes us wait for it
- LLSD value(*future);
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName
- << " resuming with " << value << LL_ENDL;
- // returning should disconnect the connection
- return value;
-}
+LLSD postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+ const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD());
/// Wait for the next event on the specified LLEventPump. Pass either the
/// LLEventPump& or its string name.
-template <typename SELF>
-LLSD waitForEventOn(SELF& self, const LLEventPumpOrPumpName& pump)
+inline
+LLSD suspendUntilEventOn(const LLEventPumpOrPumpName& pump)
{
- // This is now a convenience wrapper for postAndWait().
- return postAndWait(self, LLSD(), LLEventPumpOrPumpName(), pump);
+ // This is now a convenience wrapper for postAndSuspend().
+ return postAndSuspend(LLSD(), LLEventPumpOrPumpName(), pump);
}
-/// return type for two-pump variant of waitForEventOn()
+} // namespace llcoro
+
+/// return type for two-pump variant of suspendUntilEventOn()
typedef std::pair<LLSD, int> LLEventWithID;
-namespace LLEventDetail
+namespace llcoro
{
- /**
- * This helper is specifically for the two-pump version of waitForEventOn().
- * We use a single future object, but we want to listen on two pumps with it.
- * Since we must still adapt from (the callable constructed by)
- * boost::dcoroutines::make_callback() (void return) to provide an event
- * listener (bool return), we've adapted LLVoidListener for the purpose. The
- * basic idea is that we construct a distinct instance of WaitForEventOnHelper
- * -- binding different instance data -- for each of the pumps. Then, when a
- * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine
- * that LLSD with its discriminator to feed the future object.
- */
- template <typename LISTENER>
- class WaitForEventOnHelper
- {
- public:
- WaitForEventOnHelper(const LISTENER& listener, int discriminator):
- mListener(listener),
- mDiscrim(discriminator)
- {}
- // this signature is required for an LLEventPump listener
- bool operator()(const LLSD& event)
- {
- // our future object is defined to accept LLEventWithID
- mListener(LLEventWithID(event, mDiscrim));
- // don't swallow the event, let other listeners see it
- return false;
- }
- private:
- LISTENER mListener;
- const int mDiscrim;
- };
-
- /// WaitForEventOnHelper type-inference helper
- template <typename LISTENER>
- WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator)
- {
- return WaitForEventOnHelper<LISTENER>(listener, discriminator);
- }
-} // namespace LLEventDetail
/**
* This function waits for a reply on either of two specified LLEventPumps.
- * Otherwise, it closely resembles postAndWait(); please see the documentation
+ * Otherwise, it closely resembles postAndSuspend(); please see the documentation
* for that function for detailed parameter info.
*
* While we could have implemented the single-pump variant in terms of this
@@ -310,81 +192,41 @@ namespace LLEventDetail
* the index of the pump on which it arrived (0 or 1).
*
* @note
- * I'd have preferred to overload the name postAndWait() for both signatures.
+ * I'd have preferred to overload the name postAndSuspend() for both signatures.
* But consider the following ambiguous call:
* @code
- * postAndWait(self, LLSD(), requestPump, replyPump, "someString");
+ * postAndSuspend(LLSD(), requestPump, replyPump, "someString");
* @endcode
* "someString" could be converted to either LLSD (@a replyPumpNamePath for
* the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump
* function).
*
- * It seems less burdensome to write postAndWait2() than to write either
+ * It seems less burdensome to write postAndSuspend2() than to write either
* LLSD("someString") or LLEventOrPumpName("someString").
*/
-template <typename SELF>
-LLEventWithID postAndWait2(SELF& self, const LLSD& event,
+LLEventWithID postAndSuspend2(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLEventPumpOrPumpName& replyPump0,
const LLEventPumpOrPumpName& replyPump1,
const LLSD& replyPump0NamePath=LLSD(),
- const LLSD& replyPump1NamePath=LLSD())
-{
- // declare the future
- boost::dcoroutines::future<LLEventWithID> future(self);
- // either callback will assign a value to this future; listen on
- // each specified LLEventPump with a callback
- std::string name(LLEventDetail::listenerNameForCoro(self));
- LLTempBoundListener connection0(
- replyPump0.getPump().listen(name + "a",
- LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 0)));
- LLTempBoundListener connection1(
- replyPump1.getPump().listen(name + "b",
- LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 1)));
- // skip the "post" part if requestPump is default-constructed
- if (requestPump)
- {
- // If either replyPumpNamePath is non-empty, store the corresponding
- // replyPump name in the request event.
- LLSD modevent(event);
- LLEventDetail::storeToLLSDPath(modevent, replyPump0NamePath,
- replyPump0.getPump().getName());
- LLEventDetail::storeToLLSDPath(modevent, replyPump1NamePath,
- replyPump1.getPump().getName());
- LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
- << " posting to " << requestPump.getPump().getName()
- << ": " << modevent << LL_ENDL;
- requestPump.getPump().post(modevent);
- }
- LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name
- << " about to wait on LLEventPumps " << replyPump0.getPump().getName()
- << ", " << replyPump1.getPump().getName() << LL_ENDL;
- // trying to dereference ("resolve") the future makes us wait for it
- LLEventWithID value(*future);
- LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name
- << " resuming with (" << value.first << ", " << value.second << ")"
- << LL_ENDL;
- // returning should disconnect both connections
- return value;
-}
+ const LLSD& replyPump1NamePath=LLSD());
/**
* Wait for the next event on either of two specified LLEventPumps.
*/
-template <typename SELF>
+inline
LLEventWithID
-waitForEventOn(SELF& self,
- const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
+suspendUntilEventOn(const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)
{
- // This is now a convenience wrapper for postAndWait2().
- return postAndWait2(self, LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
+ // This is now a convenience wrapper for postAndSuspend2().
+ return postAndSuspend2(LLSD(), LLEventPumpOrPumpName(), pump0, pump1);
}
/**
- * Helper for the two-pump variant of waitForEventOn(), e.g.:
+ * Helper for the two-pump variant of suspendUntilEventOn(), e.g.:
*
* @code
- * LLSD reply = errorException(waitForEventOn(self, replyPump, errorPump),
+ * LLSD reply = errorException(suspendUntilEventOn(replyPump, errorPump),
* "error response from login.cgi");
* @endcode
*
@@ -400,6 +242,8 @@ waitForEventOn(SELF& self,
*/
LLSD errorException(const LLEventWithID& result, const std::string& desc);
+} // namespace llcoro
+
/**
* Exception thrown by errorException(). We don't call this LLEventError
* because it's not an error in event processing: rather, this exception
@@ -420,12 +264,17 @@ private:
LLSD mData;
};
+namespace llcoro
+{
+
/**
* Like errorException(), save that this trips a fatal error using LL_ERRS
* rather than throwing an exception.
*/
LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc);
+} // namespace llcoro
+
/**
* Certain event APIs require the name of an LLEventPump on which they should
* post results. While it works to invent a distinct name and let
@@ -437,7 +286,7 @@ LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc
* 2. Provide its actual name to the event API in question as the name of the
* reply LLEventPump.
* 3. Initiate the request to the event API.
- * 4. Call your LLEventTempStream's wait() method to wait for the reply.
+ * 4. Call your LLEventTempStream's suspend() method to suspend for the reply.
* 5. Let the LLCoroEventPump go out of scope.
*/
class LL_COMMON_API LLCoroEventPump
@@ -454,26 +303,16 @@ public:
/**
* Wait for an event on this LLEventPump.
- *
- * @note
- * The other major usage pattern we considered was to bind @c self at
- * LLCoroEventPump construction time, which would avoid passing the
- * parameter to each wait() call. But if we were going to bind @c self as
- * a class member, we'd need to specify a class template parameter
- * indicating its type. The big advantage of passing it to the wait() call
- * is that the type can be implicit.
*/
- template <typename SELF>
- LLSD wait(SELF& self)
+ LLSD suspend()
{
- return waitForEventOn(self, mPump);
+ return llcoro::suspendUntilEventOn(mPump);
}
- template <typename SELF>
- LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump,
+ LLSD postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPumpNamePath=LLSD())
{
- return ::postAndWait(self, event, requestPump, mPump, replyPumpNamePath);
+ return llcoro::postAndSuspend(event, requestPump, mPump, replyPumpNamePath);
}
private:
@@ -509,57 +348,51 @@ public:
/// request pump 1
LLEventPump& getPump1() { return mPump1; }
- /// waitForEventOn(self, either of our two LLEventPumps)
- template <typename SELF>
- LLEventWithID wait(SELF& self)
+ /// suspendUntilEventOn(either of our two LLEventPumps)
+ LLEventWithID suspend()
{
- return waitForEventOn(self, mPump0, mPump1);
+ return llcoro::suspendUntilEventOn(mPump0, mPump1);
}
- /// errorException(wait(self))
- template <typename SELF>
- LLSD waitWithException(SELF& self)
+ /// errorException(suspend())
+ LLSD suspendWithException()
{
- return errorException(wait(self), std::string("Error event on ") + getName1());
+ return llcoro::errorException(suspend(), std::string("Error event on ") + getName1());
}
- /// errorLog(wait(self))
- template <typename SELF>
- LLSD waitWithLog(SELF& self)
+ /// errorLog(suspend())
+ LLSD suspendWithLog()
{
- return errorLog(wait(self), std::string("Error event on ") + getName1());
+ return llcoro::errorLog(suspend(), std::string("Error event on ") + getName1());
}
- template <typename SELF>
- LLEventWithID postAndWait(SELF& self, const LLSD& event,
+ LLEventWithID postAndSuspend(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return postAndWait2(self, event, requestPump, mPump0, mPump1,
- replyPump0NamePath, replyPump1NamePath);
+ return llcoro::postAndSuspend2(event, requestPump, mPump0, mPump1,
+ replyPump0NamePath, replyPump1NamePath);
}
- template <typename SELF>
- LLSD postAndWaitWithException(SELF& self, const LLSD& event,
+ LLSD postAndSuspendWithException(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return errorException(postAndWait(self, event, requestPump,
- replyPump0NamePath, replyPump1NamePath),
- std::string("Error event on ") + getName1());
+ return llcoro::errorException(postAndSuspend(event, requestPump,
+ replyPump0NamePath, replyPump1NamePath),
+ std::string("Error event on ") + getName1());
}
- template <typename SELF>
- LLSD postAndWaitWithLog(SELF& self, const LLSD& event,
+ LLSD postAndSuspendWithLog(const LLSD& event,
const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return errorLog(postAndWait(self, event, requestPump,
- replyPump0NamePath, replyPump1NamePath),
- std::string("Error event on ") + getName1());
+ return llcoro::errorLog(postAndSuspend(event, requestPump,
+ replyPump0NamePath, replyPump1NamePath),
+ std::string("Error event on ") + getName1());
}
private:
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 715df36f39..db29504b42 100755
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -710,7 +710,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// Tie the lifespan of this child process to the lifespan of our APR
// pool: on destruction of the pool, forcibly kill the process. Tell
- // APR to try SIGTERM and wait 3 seconds. If that didn't work, use
+ // APR to try SIGTERM and suspend 3 seconds. If that didn't work, use
// SIGKILL.
apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT);
|*==========================================================================*/
@@ -986,9 +986,9 @@ void LLProcess::handle_status(int reason, int status)
// wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT);
// It's just wrong to call apr_proc_wait() here. The only way APR knows to
// call us with APR_OC_REASON_DEATH is that it's already reaped this child
- // process, so calling wait() will only produce "huh?" from the OS. We
+ // process, so calling suspend() will only produce "huh?" from the OS. We
// must rely on the status param passed in, which unfortunately comes
- // straight from the OS wait() call, which means we have to decode it by
+ // straight from the OS suspend() call, which means we have to decode it by
// hand.
mStatus = interpret_status(status);
LL_INFOS("LLProcess") << getStatusString() << LL_ENDL;
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 3836a9b5fb..1107973569 100755
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -144,14 +144,9 @@ private:
};
/**
- * intrusive pointer support
- * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type
- */
-/**
* intrusive pointer support for LLThreadSafeRefCount
* this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type
*/
-
inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)
{
p->ref();
@@ -162,6 +157,10 @@ inline void intrusive_ptr_release(LLThreadSafeRefCount* p)
p->unref();
}
+/**
+ * intrusive pointer support
+ * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type
+ */
inline void intrusive_ptr_add_ref(LLRefCount* p)
{
p->ref();
diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp
new file mode 100644
index 0000000000..8caaaee534
--- /dev/null
+++ b/indra/llcommon/llsdjson.cpp
@@ -0,0 +1,126 @@
+/**
+ * @file llsdjson.cpp
+ * @brief LLSD flexible data system
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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$
+ */
+
+// Must turn on conditional declarations in header file so definitions end up
+// with proper linkage.
+#define LLSD_DEBUG_INFO
+#include "linden_common.h"
+
+#include "llsdjson.h"
+
+#include "llerror.h"
+#include "../llmath/llmath.h"
+
+//=========================================================================
+LLSD LlsdFromJson(const Json::Value &val)
+{
+ LLSD result;
+
+ switch (val.type())
+ {
+ default:
+ case Json::nullValue:
+ break;
+ case Json::intValue:
+ result = LLSD(static_cast<LLSD::Integer>(val.asInt()));
+ break;
+ case Json::uintValue:
+ result = LLSD(static_cast<LLSD::Integer>(val.asUInt()));
+ break;
+ case Json::realValue:
+ result = LLSD(static_cast<LLSD::Real>(val.asDouble()));
+ break;
+ case Json::stringValue:
+ result = LLSD(static_cast<LLSD::String>(val.asString()));
+ break;
+ case Json::booleanValue:
+ result = LLSD(static_cast<LLSD::Boolean>(val.asBool()));
+ break;
+ case Json::arrayValue:
+ result = LLSD::emptyArray();
+ for (Json::ValueConstIterator it = val.begin(); it != val.end(); ++it)
+ {
+ result.append(LlsdFromJson((*it)));
+ }
+ break;
+ case Json::objectValue:
+ result = LLSD::emptyMap();
+ for (Json::ValueConstIterator it = val.begin(); it != val.end(); ++it)
+ {
+ result[it.memberName()] = LlsdFromJson((*it));
+ }
+ break;
+ }
+ return result;
+}
+
+//=========================================================================
+Json::Value LlsdToJson(const LLSD &val)
+{
+ Json::Value result;
+
+ switch (val.type())
+ {
+ case LLSD::TypeUndefined:
+ result = Json::Value::null;
+ break;
+ case LLSD::TypeBoolean:
+ result = Json::Value(static_cast<bool>(val.asBoolean()));
+ break;
+ case LLSD::TypeInteger:
+ result = Json::Value(static_cast<int>(val.asInteger()));
+ break;
+ case LLSD::TypeReal:
+ result = Json::Value(static_cast<double>(val.asReal()));
+ break;
+ case LLSD::TypeURI:
+ case LLSD::TypeDate:
+ case LLSD::TypeUUID:
+ case LLSD::TypeString:
+ result = Json::Value(val.asString());
+ break;
+ case LLSD::TypeMap:
+ result = Json::Value(Json::objectValue);
+ for (LLSD::map_const_iterator it = val.beginMap(); it != val.endMap(); ++it)
+ {
+ result[it->first] = LlsdToJson(it->second);
+ }
+ break;
+ case LLSD::TypeArray:
+ result = Json::Value(Json::arrayValue);
+ for (LLSD::array_const_iterator it = val.beginArray(); it != val.endArray(); ++it)
+ {
+ result.append(LlsdToJson(*it));
+ }
+ break;
+ case LLSD::TypeBinary:
+ default:
+ LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type (" << val.type() << ")." << LL_ENDL;
+ break;
+ }
+
+ return result;
+}
diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h
new file mode 100644
index 0000000000..2be7112404
--- /dev/null
+++ b/indra/llcommon/llsdjson.h
@@ -0,0 +1,77 @@
+/**
+ * @file llsdjson.cpp
+ * @brief LLSD flexible data system
+ *
+ * $LicenseInfo:firstyear=2015&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2015, 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_LLSDJSON_H
+#define LL_LLSDJSON_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "stdtypes.h"
+
+#include "llsd.h"
+#include "value.h"
+
+/// Convert a parsed JSON structure into LLSD maintaining member names and
+/// array indexes.
+/// JSON/JavaScript types are converted as follows:
+///
+/// JSON Type | LLSD Type
+/// --------------+--------------
+/// null | undefined
+/// integer | LLSD::Integer
+/// unsigned | LLSD::Integer
+/// real/numeric | LLSD::Real
+/// string | LLSD::String
+/// boolean | LLSD::Boolean
+/// array | LLSD::Array
+/// object | LLSD::Map
+///
+/// For maps and arrays child entries will be converted and added to the structure.
+/// Order is preserved for an array but not for objects.
+LLSD LlsdFromJson(const Json::Value &val);
+
+/// Convert an LLSD object into Parsed JSON object maintaining member names and
+/// array indexs.
+///
+/// Types are converted as follows:
+/// LLSD Type | JSON Type
+/// --------------+----------------
+/// TypeUndefined | null
+/// TypeBoolean | boolean
+/// TypeInteger | integer
+/// TypeReal | real/numeric
+/// TypeString | string
+/// TypeURI | string
+/// TypeDate | string
+/// TypeUUID | string
+/// TypeMap | object
+/// TypeArray | array
+/// TypeBinary | unsupported
+Json::Value LlsdToJson(const LLSD &val);
+
+#endif // LL_LLSDJSON_H
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 0177f48bf5..393f6d7a8c 100755
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -1394,6 +1394,7 @@ BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)
return rv;
}
+// *TODO: reimplement in terms of algorithm
//static
template<class T>
void LLStringUtilBase<T>::stripNonprintable(string_type& string)
@@ -1427,6 +1428,7 @@ void LLStringUtilBase<T>::stripNonprintable(string_type& string)
delete []c_string;
}
+// *TODO: reimplement in terms of algorithm
template<class T>
std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,
const string_type& triggers,
diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp
index 2096807e53..1ee79e9eb6 100755
--- a/indra/llcommon/tests/lleventcoro_test.cpp
+++ b/indra/llcommon/tests/lleventcoro_test.cpp
@@ -59,17 +59,20 @@
// http://www.boost.org/LICENSE_1_0.txt)
/*****************************************************************************/
+#define BOOST_RESULT_OF_USE_TR1 1
// On some platforms, Boost.Coroutine must #define magic symbols before
// #including platform-API headers. Naturally, that's ineffective unless the
// Boost.Coroutine #include is the *first* #include of the platform header.
// That means that client code must generally #include Boost.Coroutine headers
// before anything else.
+#define BOOST_RESULT_OF_USE_TR1 1
#include <boost/dcoroutine/coroutine.hpp>
// Normally, lleventcoro.h obviates future.hpp. We only include this because
// we implement a "by hand" test of future functionality.
#include <boost/dcoroutine/future.hpp>
#include <boost/bind.hpp>
#include <boost/range.hpp>
+#include <boost/utility.hpp>
#include "linden_common.h"
@@ -82,9 +85,12 @@
#include "llevents.h"
#include "tests/wrapllerrs.h"
#include "stringize.h"
+#include "llcoros.h"
#include "lleventcoro.h"
#include "../test/debug.h"
+using namespace llcoro;
+
/*****************************************************************************
* from the banana.cpp example program borrowed for test<1>()
*****************************************************************************/
@@ -121,13 +127,10 @@ typedef coroutine<std::string::iterator(void)> match_coroutine_type;
/*****************************************************************************
* Test helpers
*****************************************************************************/
-// I suspect this will be typical of coroutines used in Linden software
-typedef boost::dcoroutines::coroutine<void()> coroutine_type;
-
/// Simulate an event API whose response is immediate: sent on receipt of the
/// initial request, rather than after some delay. This is the case that
-/// distinguishes postAndWait() from calling post(), then calling
-/// waitForEventOn().
+/// distinguishes postAndSuspend() from calling post(), then calling
+/// suspendUntilEventOn().
class ImmediateAPI
{
public:
@@ -162,306 +165,7 @@ private:
*****************************************************************************/
namespace tut
{
- struct coroutine_data
- {
- // Define coroutine bodies as methods here so they can use ensure*()
-
- void explicit_wait(coroutine_type::self& self)
- {
- BEGIN
- {
- // ... do whatever preliminary stuff must happen ...
-
- // declare the future
- boost::dcoroutines::future<LLSD> future(self);
- // tell the future what to wait for
- LLTempBoundListener connection(
- LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::dcoroutines::make_callback(future))));
- ensure("Not yet", ! future);
- // attempting to dereference ("resolve") the future causes the calling
- // coroutine to wait for it
- debug("about to wait");
- result = *future;
- ensure("Got it", future);
- }
- END
- }
-
- void waitForEventOn1(coroutine_type::self& self)
- {
- BEGIN
- {
- result = waitForEventOn(self, "source");
- }
- END
- }
-
- void waitForEventOn2(coroutine_type::self& self)
- {
- BEGIN
- {
- LLEventWithID pair = waitForEventOn(self, "reply", "error");
- result = pair.first;
- which = pair.second;
- debug(STRINGIZE("result = " << result << ", which = " << which));
- }
- END
- }
-
- void postAndWait1(coroutine_type::self& self)
- {
- BEGIN
- {
- result = postAndWait(self,
- LLSDMap("value", 17), // request event
- immediateAPI.getPump(), // requestPump
- "reply1", // replyPump
- "reply"); // request["reply"] = name
- }
- END
- }
-
- void postAndWait2(coroutine_type::self& self)
- {
- BEGIN
- {
- LLEventWithID pair = ::postAndWait2(self,
- LLSDMap("value", 18),
- immediateAPI.getPump(),
- "reply2",
- "error2",
- "reply",
- "error");
- result = pair.first;
- which = pair.second;
- debug(STRINGIZE("result = " << result << ", which = " << which));
- }
- END
- }
-
- void postAndWait2_1(coroutine_type::self& self)
- {
- BEGIN
- {
- LLEventWithID pair = ::postAndWait2(self,
- LLSDMap("value", 18)("fail", LLSD()),
- immediateAPI.getPump(),
- "reply2",
- "error2",
- "reply",
- "error");
- result = pair.first;
- which = pair.second;
- debug(STRINGIZE("result = " << result << ", which = " << which));
- }
- END
- }
-
- void coroPump(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPump waiter;
- replyName = waiter.getName();
- result = waiter.wait(self);
- }
- END
- }
-
- void coroPumpPost(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPump waiter;
- result = waiter.postAndWait(self, LLSDMap("value", 17),
- immediateAPI.getPump(), "reply");
- }
- END
- }
-
- void coroPumps(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- LLEventWithID pair(waiter.wait(self));
- result = pair.first;
- which = pair.second;
- }
- END
- }
-
- void coroPumpsNoEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- result = waiter.waitWithException(self);
- }
- END
- }
-
- void coroPumpsEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- try
- {
- result = waiter.waitWithException(self);
- debug("no exception");
- }
- catch (const LLErrorEvent& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- errordata = e.getData();
- }
- }
- END
- }
-
- void coroPumpsNoLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- result = waiter.waitWithLog(self);
- }
- END
- }
-
- void coroPumpsLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- replyName = waiter.getName0();
- errorName = waiter.getName1();
- WrapLLErrs capture;
- try
- {
- result = waiter.waitWithLog(self);
- debug("no exception");
- }
- catch (const WrapLLErrs::FatalException& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- threw = e.what();
- }
- }
- END
- }
-
- void coroPumpsPost(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- LLEventWithID pair(waiter.postAndWait(self, LLSDMap("value", 23),
- immediateAPI.getPump(), "reply", "error"));
- result = pair.first;
- which = pair.second;
- }
- END
- }
-
- void coroPumpsPost_1(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- LLEventWithID pair(
- waiter.postAndWait(self, LLSDMap("value", 23)("fail", LLSD()),
- immediateAPI.getPump(), "reply", "error"));
- result = pair.first;
- which = pair.second;
- }
- END
- }
-
- void coroPumpsPostNoEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- result = waiter.postAndWaitWithException(self, LLSDMap("value", 8),
- immediateAPI.getPump(), "reply", "error");
- }
- END
- }
-
- void coroPumpsPostEx(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- try
- {
- result = waiter.postAndWaitWithException(self,
- LLSDMap("value", 9)("fail", LLSD()),
- immediateAPI.getPump(), "reply", "error");
- debug("no exception");
- }
- catch (const LLErrorEvent& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- errordata = e.getData();
- }
- }
- END
- }
-
- void coroPumpsPostNoLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- result = waiter.postAndWaitWithLog(self, LLSDMap("value", 30),
- immediateAPI.getPump(), "reply", "error");
- }
- END
- }
-
- void coroPumpsPostLog(coroutine_type::self& self)
- {
- BEGIN
- {
- LLCoroEventPumps waiter;
- WrapLLErrs capture;
- try
- {
- result = waiter.postAndWaitWithLog(self,
- LLSDMap("value", 31)("fail", LLSD()),
- immediateAPI.getPump(), "reply", "error");
- debug("no exception");
- }
- catch (const WrapLLErrs::FatalException& e)
- {
- debug(STRINGIZE("exception " << e.what()));
- threw = e.what();
- }
- }
- END
- }
-
- void ensure_done(coroutine_type& coro)
- {
- ensure("coroutine complete", ! coro);
- }
-
- ImmediateAPI immediateAPI;
- std::string replyName, errorName, threw;
- LLSD result, errordata;
- int which;
- };
+ struct coroutine_data {};
typedef test_group<coroutine_data> coroutine_group;
typedef coroutine_group::object object;
coroutine_group coroutinegrp("coroutine");
@@ -511,54 +215,113 @@ namespace tut
ensure("done", ! matcher);
}
+ // use static data so we can intersperse coroutine functions with the
+ // tests that engage them
+ ImmediateAPI immediateAPI;
+ std::string replyName, errorName, threw;
+ LLSD result, errordata;
+ int which;
+
+ // reinit vars at the start of each test
+ void clear()
+ {
+ replyName.clear();
+ errorName.clear();
+ threw.clear();
+ result = LLSD();
+ errordata = LLSD();
+ which = 0;
+ }
+
+ void explicit_wait(boost::dcoroutines::coroutine<void()>::self& self)
+ {
+ BEGIN
+ {
+ // ... do whatever preliminary stuff must happen ...
+
+ // declare the future
+ boost::dcoroutines::future<LLSD> future(self);
+ // tell the future what to suspend for
+ LLTempBoundListener connection(
+ LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::dcoroutines::make_callback(future))));
+ ensure("Not yet", ! future);
+ // attempting to dereference ("resolve") the future causes the calling
+ // coroutine to suspend for it
+ debug("about to suspend");
+ result = *future;
+ ensure("Got it", future);
+ }
+ END
+ }
+
template<> template<>
void object::test<2>()
{
+ clear();
set_test_name("explicit_wait");
DEBUG;
// Construct the coroutine instance that will run explicit_wait.
// Pass the ctor a callable that accepts the coroutine_type::self
// param passed by the library.
- coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1));
+ boost::dcoroutines::coroutine<void()> coro(explicit_wait);
// Start the coroutine
coro(std::nothrow);
// When the coroutine waits for the event pump, it returns here.
debug("about to send");
- // Satisfy the wait.
+ // Satisfy the suspend.
LLEventPumps::instance().obtain("source").post("received");
- // Now wait for the coroutine to complete.
- ensure_done(coro);
+ // Now suspend for the coroutine to complete.
+ ensure("coroutine complete", ! coro);
// ensure the coroutine ran and woke up again with the intended result
ensure_equals(result.asString(), "received");
}
+ void waitForEventOn1()
+ {
+ BEGIN
+ {
+ result = suspendUntilEventOn("source");
+ }
+ END
+ }
+
template<> template<>
void object::test<3>()
{
+ clear();
set_test_name("waitForEventOn1");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<3>", waitForEventOn1);
debug("about to send");
LLEventPumps::instance().obtain("source").post("received");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "received");
}
+ void waitForEventOn2()
+ {
+ BEGIN
+ {
+ LLEventWithID pair = suspendUntilEventOn("reply", "error");
+ result = pair.first;
+ which = pair.second;
+ debug(STRINGIZE("result = " << result << ", which = " << which));
+ }
+ END
+ }
+
template<> template<>
void object::test<4>()
{
+ clear();
set_test_name("waitForEventOn2 reply");
{
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<4>", waitForEventOn2);
debug("about to send");
LLEventPumps::instance().obtain("reply").post("received");
debug("back from send");
- ensure_done(coro);
}
ensure_equals(result.asString(), "received");
ensure_equals("which pump", which, 0);
@@ -567,43 +330,65 @@ namespace tut
template<> template<>
void object::test<5>()
{
+ clear();
set_test_name("waitForEventOn2 error");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<5>", waitForEventOn2);
debug("about to send");
LLEventPumps::instance().obtain("error").post("badness");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "badness");
ensure_equals("which pump", which, 1);
}
+ void coroPump()
+ {
+ BEGIN
+ {
+ LLCoroEventPump waiter;
+ replyName = waiter.getName();
+ result = waiter.suspend();
+ }
+ END
+ }
+
template<> template<>
void object::test<6>()
{
+ clear();
set_test_name("coroPump");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<6>", coroPump);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "received");
}
+ void coroPumps()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ LLEventWithID pair(waiter.suspend());
+ result = pair.first;
+ which = pair.second;
+ }
+ END
+ }
+
template<> template<>
void object::test<7>()
{
+ clear();
set_test_name("coroPumps reply");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<7>", coroPumps);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "received");
ensure_equals("which pump", which, 0);
}
@@ -611,188 +396,389 @@ namespace tut
template<> template<>
void object::test<8>()
{
+ clear();
set_test_name("coroPumps error");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<8>", coroPumps);
debug("about to send");
LLEventPumps::instance().obtain(errorName).post("badness");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "badness");
ensure_equals("which pump", which, 1);
}
+ void coroPumpsNoEx()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ result = waiter.suspendWithException();
+ }
+ END
+ }
+
template<> template<>
void object::test<9>()
{
+ clear();
set_test_name("coroPumpsNoEx");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<9>", coroPumpsNoEx);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "received");
}
+ void coroPumpsEx()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ try
+ {
+ result = waiter.suspendWithException();
+ debug("no exception");
+ }
+ catch (const LLErrorEvent& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ errordata = e.getData();
+ }
+ }
+ END
+ }
+
template<> template<>
void object::test<10>()
{
+ clear();
set_test_name("coroPumpsEx");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<10>", coroPumpsEx);
debug("about to send");
LLEventPumps::instance().obtain(errorName).post("badness");
debug("back from send");
- ensure_done(coro);
ensure("no result", result.isUndefined());
ensure_equals("got error", errordata.asString(), "badness");
}
+ void coroPumpsNoLog()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ result = waiter.suspendWithLog();
+ }
+ END
+ }
+
template<> template<>
void object::test<11>()
{
+ clear();
set_test_name("coroPumpsNoLog");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<11>", coroPumpsNoLog);
debug("about to send");
LLEventPumps::instance().obtain(replyName).post("received");
debug("back from send");
- ensure_done(coro);
ensure_equals(result.asString(), "received");
}
+ void coroPumpsLog()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ replyName = waiter.getName0();
+ errorName = waiter.getName1();
+ WrapLLErrs capture;
+ try
+ {
+ result = waiter.suspendWithLog();
+ debug("no exception");
+ }
+ catch (const WrapLLErrs::FatalException& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ threw = e.what();
+ }
+ }
+ END
+ }
+
template<> template<>
void object::test<12>()
{
+ clear();
set_test_name("coroPumpsLog");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1));
- coro(std::nothrow);
+ LLCoros::instance().launch("test<12>", coroPumpsLog);
debug("about to send");
LLEventPumps::instance().obtain(errorName).post("badness");
debug("back from send");
- ensure_done(coro);
ensure("no result", result.isUndefined());
ensure_contains("got error", threw, "badness");
}
+ void postAndWait1()
+ {
+ BEGIN
+ {
+ result = postAndSuspend(LLSDMap("value", 17), // request event
+ immediateAPI.getPump(), // requestPump
+ "reply1", // replyPump
+ "reply"); // request["reply"] = name
+ }
+ END
+ }
+
template<> template<>
void object::test<13>()
{
+ clear();
set_test_name("postAndWait1");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<13>", postAndWait1);
ensure_equals(result.asInteger(), 18);
}
+ void postAndWait2()
+ {
+ BEGIN
+ {
+ LLEventWithID pair = ::postAndSuspend2(LLSDMap("value", 18),
+ immediateAPI.getPump(),
+ "reply2",
+ "error2",
+ "reply",
+ "error");
+ result = pair.first;
+ which = pair.second;
+ debug(STRINGIZE("result = " << result << ", which = " << which));
+ }
+ END
+ }
+
template<> template<>
void object::test<14>()
{
+ clear();
set_test_name("postAndWait2");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<14>", postAndWait2);
ensure_equals(result.asInteger(), 19);
ensure_equals(which, 0);
}
+ void postAndWait2_1()
+ {
+ BEGIN
+ {
+ LLEventWithID pair = ::postAndSuspend2(LLSDMap("value", 18)("fail", LLSD()),
+ immediateAPI.getPump(),
+ "reply2",
+ "error2",
+ "reply",
+ "error");
+ result = pair.first;
+ which = pair.second;
+ debug(STRINGIZE("result = " << result << ", which = " << which));
+ }
+ END
+ }
+
template<> template<>
void object::test<15>()
{
+ clear();
set_test_name("postAndWait2_1");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<15>", postAndWait2_1);
ensure_equals(result.asInteger(), 19);
ensure_equals(which, 1);
}
+ void coroPumpPost()
+ {
+ BEGIN
+ {
+ LLCoroEventPump waiter;
+ result = waiter.postAndSuspend(LLSDMap("value", 17),
+ immediateAPI.getPump(), "reply");
+ }
+ END
+ }
+
template<> template<>
void object::test<16>()
{
+ clear();
set_test_name("coroPumpPost");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<16>", coroPumpPost);
ensure_equals(result.asInteger(), 18);
}
+ void coroPumpsPost()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ LLEventWithID pair(waiter.postAndSuspend(LLSDMap("value", 23),
+ immediateAPI.getPump(), "reply", "error"));
+ result = pair.first;
+ which = pair.second;
+ }
+ END
+ }
+
template<> template<>
void object::test<17>()
{
+ clear();
set_test_name("coroPumpsPost reply");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<17>", coroPumpsPost);
ensure_equals(result.asInteger(), 24);
ensure_equals("which pump", which, 0);
}
+ void coroPumpsPost_1()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ LLEventWithID pair(
+ waiter.postAndSuspend(LLSDMap("value", 23)("fail", LLSD()),
+ immediateAPI.getPump(), "reply", "error"));
+ result = pair.first;
+ which = pair.second;
+ }
+ END
+ }
+
template<> template<>
void object::test<18>()
{
+ clear();
set_test_name("coroPumpsPost error");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<18>", coroPumpsPost_1);
ensure_equals(result.asInteger(), 24);
ensure_equals("which pump", which, 1);
}
+ void coroPumpsPostNoEx()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ result = waiter.postAndSuspendWithException(LLSDMap("value", 8),
+ immediateAPI.getPump(), "reply", "error");
+ }
+ END
+ }
+
template<> template<>
void object::test<19>()
{
+ clear();
set_test_name("coroPumpsPostNoEx");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<19>", coroPumpsPostNoEx);
ensure_equals(result.asInteger(), 9);
}
+ void coroPumpsPostEx()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ try
+ {
+ result = waiter.postAndSuspendWithException(
+ LLSDMap("value", 9)("fail", LLSD()),
+ immediateAPI.getPump(), "reply", "error");
+ debug("no exception");
+ }
+ catch (const LLErrorEvent& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ errordata = e.getData();
+ }
+ }
+ END
+ }
+
template<> template<>
void object::test<20>()
{
+ clear();
set_test_name("coroPumpsPostEx");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<20>", coroPumpsPostEx);
ensure("no result", result.isUndefined());
ensure_equals("got error", errordata.asInteger(), 10);
}
+ void coroPumpsPostNoLog()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ result = waiter.postAndSuspendWithLog(LLSDMap("value", 30),
+ immediateAPI.getPump(), "reply", "error");
+ }
+ END
+ }
+
template<> template<>
void object::test<21>()
{
+ clear();
set_test_name("coroPumpsPostNoLog");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<21>", coroPumpsPostNoLog);
ensure_equals(result.asInteger(), 31);
}
+ void coroPumpsPostLog()
+ {
+ BEGIN
+ {
+ LLCoroEventPumps waiter;
+ WrapLLErrs capture;
+ try
+ {
+ result = waiter.postAndSuspendWithLog(
+ LLSDMap("value", 31)("fail", LLSD()),
+ immediateAPI.getPump(), "reply", "error");
+ debug("no exception");
+ }
+ catch (const WrapLLErrs::FatalException& e)
+ {
+ debug(STRINGIZE("exception " << e.what()));
+ threw = e.what();
+ }
+ }
+ END
+ }
+
template<> template<>
void object::test<22>()
{
+ clear();
set_test_name("coroPumpsPostLog");
DEBUG;
- coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1));
- coro(std::nothrow);
- ensure_done(coro);
+ LLCoros::instance().launch("test<22>", coroPumpsPostLog);
ensure("no result", result.isUndefined());
ensure_contains("got error", threw, "32");
}
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index a0b1ea13b1..4aecf61bd7 100755
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -5,7 +5,6 @@ project(llcorehttp)
include(00-Common)
include(GoogleMock)
include(CURL)
-include(CARes)
include(OpenSSL)
include(ZLIB)
include(LLCoreHttp)
@@ -26,6 +25,7 @@ set(llcorehttp_SOURCE_FILES
bufferarray.cpp
bufferstream.cpp
httpcommon.cpp
+ llhttpconstants.cpp
httpheaders.cpp
httpoptions.cpp
httprequest.cpp
@@ -51,6 +51,7 @@ set(llcorehttp_HEADER_FILES
bufferarray.h
bufferstream.h
httpcommon.h
+ llhttpconstants.h
httphandler.h
httpheaders.h
httpoptions.h
@@ -89,7 +90,6 @@ add_library (llcorehttp ${llcorehttp_SOURCE_FILES})
target_link_libraries(
llcorehttp
${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${BOOST_THREAD_LIBRARY}
@@ -127,16 +127,19 @@ if (LL_TESTS)
${LLCOMMON_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${BOOST_SYSTEM_LIBRARY}
${BOOST_THREAD_LIBRARY}
)
+ # If http_proxy is in the current environment (e.g. to fetch s3-proxy
+ # autobuild packages), suppress it for this integration test: it screws up
+ # the tests.
LL_ADD_INTEGRATION_TEST(llcorehttp
"${llcorehttp_TEST_SOURCE_FILES}"
"${test_libs}"
+ "-Dhttp_proxy"
${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py"
)
@@ -155,7 +158,6 @@ if (LL_TESTS)
${LLCOMMON_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${CURL_LIBRARIES}
- ${CARES_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${BOOST_SYSTEM_LIBRARY}
diff --git a/indra/llcorehttp/_httpinternal.h b/indra/llcorehttp/_httpinternal.h
index a2a60ca056..79c89d6c92 100755
--- a/indra/llcorehttp/_httpinternal.h
+++ b/indra/llcorehttp/_httpinternal.h
@@ -104,8 +104,9 @@ namespace LLCore
{
// Maxium number of policy classes that can be defined.
-// *TODO: Currently limited to the default class + 1, extend.
-const int HTTP_POLICY_CLASS_LIMIT = 8;
+// *TODO: Currently limited to the default class + 1, extend.
+// (TSN: should this be more dynamically sized. Is there a reason to hard limit the number of policies?)
+const int HTTP_POLICY_CLASS_LIMIT = 32;
// Debug/informational tracing. Used both
// as a global option and in per-request traces.
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp
index 81b44ab90b..17e997688f 100755
--- a/indra/llcorehttp/_httplibcurl.cpp
+++ b/indra/llcorehttp/_httplibcurl.cpp
@@ -554,7 +554,7 @@ void HttpLibcurl::HandleCache::freeHandle(CURL * handle)
// ---------------------------------------
-struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist)
+struct curl_slist * append_headers_to_slist(const HttpHeaders::ptr_t &headers, struct curl_slist * slist)
{
const HttpHeaders::const_iterator end(headers->end());
for (HttpHeaders::const_iterator it(headers->begin()); end != it; ++it)
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index b9632a7921..86110f5b46 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -122,8 +122,8 @@ HttpOpRequest::HttpOpRequest()
mReqBody(NULL),
mReqOffset(0),
mReqLength(0),
- mReqHeaders(NULL),
- mReqOptions(NULL),
+ mReqHeaders(),
+ mReqOptions(),
mCurlActive(false),
mCurlHandle(NULL),
mCurlService(NULL),
@@ -135,11 +135,12 @@ HttpOpRequest::HttpOpRequest()
mReplyOffset(0),
mReplyLength(0),
mReplyFullLength(0),
- mReplyHeaders(NULL),
+ mReplyHeaders(),
mPolicyRetries(0),
mPolicy503Retries(0),
mPolicyRetryAt(HttpTime(0)),
- mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT)
+ mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT),
+ mCallbackSSLVerify(NULL)
{
// *NOTE: As members are added, retry initialization/cleanup
// may need to be extended in @see prepareRequest().
@@ -155,18 +156,6 @@ HttpOpRequest::~HttpOpRequest()
mReqBody = NULL;
}
- if (mReqOptions)
- {
- mReqOptions->release();
- mReqOptions = NULL;
- }
-
- if (mReqHeaders)
- {
- mReqHeaders->release();
- mReqHeaders = NULL;
- }
-
if (mCurlHandle)
{
// Uncertain of thread context so free using
@@ -193,11 +182,6 @@ HttpOpRequest::~HttpOpRequest()
mReplyBody = NULL;
}
- if (mReplyHeaders)
- {
- mReplyHeaders->release();
- mReplyHeaders = NULL;
- }
}
@@ -259,7 +243,9 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setStatus(mStatus);
response->setBody(mReplyBody);
response->setHeaders(mReplyHeaders);
- if (mReplyOffset || mReplyLength)
+ response->setRequestURL(mReqURL);
+
+ if (mReplyOffset || mReplyLength)
{
// Got an explicit offset/length in response
response->setRange(mReplyOffset, mReplyLength, mReplyFullLength);
@@ -267,6 +253,14 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setContentType(mReplyConType);
response->setRetries(mPolicyRetries, mPolicy503Retries);
+ HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
+
+ curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload);
+ curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime);
+ curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload);
+
+ response->setTransferStats(stats);
+
mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
response->release();
@@ -287,8 +281,8 @@ HttpStatus HttpOpRequest::cancel()
HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
- HttpOptions * options,
- HttpHeaders * headers)
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
{
setupCommon(policy_id, priority, url, NULL, options, headers);
mReqMethod = HOR_GET;
@@ -302,8 +296,8 @@ HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
const std::string & url,
size_t offset,
size_t len,
- HttpOptions * options,
- HttpHeaders * headers)
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
{
setupCommon(policy_id, priority, url, NULL, options, headers);
mReqMethod = HOR_GET;
@@ -322,8 +316,8 @@ HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers)
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
{
setupCommon(policy_id, priority, url, body, options, headers);
mReqMethod = HOR_POST;
@@ -336,8 +330,8 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers)
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
{
setupCommon(policy_id, priority, url, body, options, headers);
mReqMethod = HOR_PUT;
@@ -346,12 +340,65 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
}
+HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
+{
+ setupCommon(policy_id, priority, url, NULL, options, headers);
+ mReqMethod = HOR_DELETE;
+
+ return HttpStatus();
+}
+
+
+HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
+{
+ setupCommon(policy_id, priority, url, body, options, headers);
+ mReqMethod = HOR_PATCH;
+
+ return HttpStatus();
+}
+
+
+HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t &headers)
+{
+ setupCommon(policy_id, priority, url, NULL, options, headers);
+ mReqMethod = HOR_COPY;
+
+ return HttpStatus();
+}
+
+
+HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t &headers)
+{
+ setupCommon(policy_id, priority, url, NULL, options, headers);
+ mReqMethod = HOR_MOVE;
+
+ return HttpStatus();
+}
+
+
void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers)
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers)
{
mProcFlags = 0U;
mReqPolicy = policy_id;
@@ -364,12 +411,10 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
}
if (headers && ! mReqHeaders)
{
- headers->addRef();
mReqHeaders = headers;
}
- if (options && ! mReqOptions)
+ if (options && !mReqOptions)
{
- options->addRef();
mReqOptions = options;
if (options->getWantHeaders())
{
@@ -416,11 +461,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
mReplyOffset = 0;
mReplyLength = 0;
mReplyFullLength = 0;
- if (mReplyHeaders)
- {
- mReplyHeaders->release();
- mReplyHeaders = NULL;
- }
+ mReplyHeaders.reset();
mReplyConType.clear();
// *FIXME: better error handling later
@@ -452,18 +493,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
check_curl_easy_code(code, CURLOPT_ENCODING);
- // The Linksys WRT54G V5 router has an issue with frequent
- // DNS lookups from LAN machines. If they happen too often,
- // like for every HTTP request, the router gets annoyed after
- // about 700 or so requests and starts issuing TCP RSTs to
- // new connections. Reuse the DNS lookups for even a few
- // seconds and no RSTs.
- code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
check_curl_easy_code(code, CURLOPT_AUTOREFERER);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1);
- check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
check_curl_easy_code(code, CURLOPT_MAXREDIRS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
@@ -474,11 +505,57 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_code(code, CURLOPT_READFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this);
check_curl_easy_code(code, CURLOPT_READDATA);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback);
+ check_curl_easy_code(code, CURLOPT_SEEKFUNCTION);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, this);
+ check_curl_easy_code(code, CURLOPT_SEEKDATA);
+
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
+ check_curl_easy_code(code, CURLOPT_COOKIEFILE);
+
+ if (gpolicy.mSslCtxCallback)
+ {
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
+ check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, this);
+ check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA);
+ mCallbackSSLVerify = gpolicy.mSslCtxCallback;
+ }
+
+ long follow_redirect(1L);
+ long sslPeerV(0L);
+ long sslHostV(0L);
+ long dnsCacheTimeout(-1L);
+ long nobody(0L);
+
+ if (mReqOptions)
+ {
+ follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L;
+ sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L;
+ sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L;
+ dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
+ nobody = mReqOptions->getHeadersOnly() ? 1L : 0L;
+ }
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
+ check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
+
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody);
+ check_curl_easy_code(code, CURLOPT_NOBODY);
+
+ // The Linksys WRT54G V5 router has an issue with frequent
+ // DNS lookups from LAN machines. If they happen too often,
+ // like for every HTTP request, the router gets annoyed after
+ // about 700 or so requests and starts issuing TCP RSTs to
+ // new connections. Reuse the DNS lookups for even a few
+ // seconds and no RSTs.
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
+ check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
+
if (gpolicy.mUseLLProxy)
{
// Use the viewer-based thread-safe API which has a
@@ -509,10 +586,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
switch (mReqMethod)
{
case HOR_GET:
- code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);
+ if (nobody == 0)
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);
check_curl_easy_code(code, CURLOPT_HTTPGET);
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
break;
case HOR_POST:
@@ -531,12 +607,14 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);
check_curl_easy_code(code, CURLOPT_POSTFIELDSIZE);
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
}
break;
- case HOR_PUT:
+ case HOR_PATCH:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ // fall through. The rest is the same as PUT
+ case HOR_PUT:
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);
check_curl_easy_code(code, CURLOPT_UPLOAD);
@@ -547,15 +625,25 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
}
code = curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
check_curl_easy_code(code, CURLOPT_INFILESIZE);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);
- check_curl_easy_code(code, CURLOPT_POSTFIELDS);
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");
}
break;
+ case HOR_DELETE:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ break;
+
+ case HOR_COPY:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "COPY");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ break;
+
+ case HOR_MOVE:
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE");
+ check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+ break;
+
default:
LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: "
<< int(mReqMethod) << ". Can't recover."
@@ -563,6 +651,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
break;
}
+
+ // *TODO: Should this be 'Keep-Alive' ?
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
+
// Tracing
if (mTracing >= HTTP_TRACE_CURL_HEADERS)
{
@@ -723,6 +816,37 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void
return read_size;
}
+
+int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+
+ if (!op->mReqBody)
+ {
+ return 0;
+ }
+
+ size_t newPos = 0;
+ if (origin == SEEK_SET)
+ newPos = offset;
+ else if (origin == SEEK_END)
+ newPos = static_cast<curl_off_t>(op->mReqBody->size()) + offset;
+ else if (origin == SEEK_CUR)
+ newPos = static_cast<curl_off_t>(op->mCurlBodyPos) + offset;
+ else
+ return 2;
+
+ if (newPos >= op->mReqBody->size())
+ {
+ LL_WARNS(LOG_CORE) << "Attempt to seek to position outside post body." << LL_ENDL;
+ return 2;
+ }
+
+ op->mCurlBodyPos = (size_t)newPos;
+
+ return 0;
+}
+
size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata)
{
@@ -817,7 +941,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
// Save headers in response
if (! op->mReplyHeaders)
{
- op->mReplyHeaders = new HttpHeaders;
+ op->mReplyHeaders = HttpHeaders::ptr_t(new HttpHeaders);
}
op->mReplyHeaders->append(name, value ? value : "");
}
@@ -873,6 +997,35 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
}
+CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+
+ if (op->mCallbackSSLVerify)
+ {
+ SSL_CTX * ctx = (SSL_CTX *)sslctx;
+ // disable any default verification for server certs
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ // set the verification callback.
+ SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata);
+ // the calls are void
+ }
+
+ return CURLE_OK;
+}
+
+int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(param));
+
+ if (op->mCallbackSSLVerify)
+ {
+ op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx);
+ }
+
+ return (op->mStatus) ? 1 : 0;
+}
+
int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
{
HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 2f628b5aba..1b449a5abc 100755
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -33,19 +33,22 @@
#include <string>
#include <curl/curl.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+
#include "httpcommon.h"
#include "httprequest.h"
#include "_httpoperation.h"
#include "_refcounted.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
namespace LLCore
{
class BufferArray;
-class HttpHeaders;
-class HttpOptions;
/// HttpOpRequest requests a supported HTTP method invocation with
@@ -77,7 +80,11 @@ public:
{
HOR_GET,
HOR_POST,
- HOR_PUT
+ HOR_PUT,
+ HOR_DELETE,
+ HOR_PATCH,
+ HOR_COPY,
+ HOR_MOVE
};
virtual void stageFromRequest(HttpService *);
@@ -98,32 +105,57 @@ public:
HttpStatus setupGet(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
- HttpOptions * options,
- HttpHeaders * headers);
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
HttpStatus setupGetByteRange(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
size_t offset,
size_t len,
- HttpOptions * options,
- HttpHeaders * headers);
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
HttpStatus setupPost(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers);
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
HttpStatus setupPut(HttpRequest::policy_t policy_id,
HttpRequest::priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers);
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
+
+ HttpStatus setupDelete(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
+
+ HttpStatus setupPatch(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
+
+ HttpStatus setupCopy(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
- // Internal method used to setup the libcurl options for a request.
+ HttpStatus setupMove(HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
+
+ // Internal method used to setup the libcurl options for a request.
// Does all the libcurl handle setup in one place.
//
// Threading: called by worker thread
@@ -141,8 +173,8 @@ protected:
HttpRequest::priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers);
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers);
// libcurl operational callbacks
//
@@ -150,7 +182,11 @@ protected:
//
static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata);
static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata);
+ static int seekCallback(void *data, curl_off_t offset, int origin);
static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata);
+ static CURLcode curlSslCtxCallback(CURL *curl, void *ssl_ctx, void *userptr);
+ static int sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
+
static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata);
protected:
@@ -159,6 +195,8 @@ protected:
static const unsigned int PF_SAVE_HEADERS = 0x00000002U;
static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U;
+ HttpRequest::policyCallback_t mCallbackSSLVerify;
+
public:
// Request data
EMethod mReqMethod;
@@ -166,8 +204,8 @@ public:
BufferArray * mReqBody;
off_t mReqOffset;
size_t mReqLength;
- HttpHeaders * mReqHeaders;
- HttpOptions * mReqOptions;
+ HttpHeaders::ptr_t mReqHeaders;
+ HttpOptions::ptr_t mReqOptions;
// Transport data
bool mCurlActive;
@@ -184,7 +222,7 @@ public:
off_t mReplyOffset;
size_t mReplyLength;
size_t mReplyFullLength;
- HttpHeaders * mReplyHeaders;
+ HttpHeaders::ptr_t mReplyHeaders;
std::string mReplyConType;
int mReplyRetryAfter;
@@ -215,7 +253,7 @@ public:
// Internal function to append the contents of an HttpHeaders
// instance to a curl_slist object.
-curl_slist * append_headers_to_slist(const HttpHeaders *, curl_slist * slist);
+curl_slist * append_headers_to_slist(const HttpHeaders::ptr_t &, curl_slist * slist);
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp
index 1dc95f3dce..3d0df96ade 100755
--- a/indra/llcorehttp/_httppolicyglobal.cpp
+++ b/indra/llcorehttp/_httppolicyglobal.cpp
@@ -106,6 +106,20 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::stri
return HttpStatus();
}
+HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value)
+{
+ switch (opt)
+ {
+ case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+ mSslCtxCallback = value;
+ break;
+
+ default:
+ return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+ }
+
+ return HttpStatus();
+}
HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const
{
@@ -154,4 +168,20 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * v
return HttpStatus();
}
+
+HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const
+{
+ switch (opt)
+ {
+ case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+ *value = mSslCtxCallback;
+ break;
+
+ default:
+ return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+ }
+
+ return HttpStatus();
+}
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h
index 67c4ba9481..e02da4386a 100755
--- a/indra/llcorehttp/_httppolicyglobal.h
+++ b/indra/llcorehttp/_httppolicyglobal.h
@@ -60,8 +60,10 @@ private:
public:
HttpStatus set(HttpRequest::EPolicyOption opt, long value);
HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value);
+ HttpStatus set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value);
HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const;
+ HttpStatus get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const;
public:
long mConnectionLimit;
@@ -70,6 +72,7 @@ public:
std::string mHttpProxy;
long mTrace;
long mUseLLProxy;
+ HttpRequest::policyCallback_t mSslCtxCallback;
}; // end class HttpPolicyGlobal
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index c673e1be1d..252db78c89 100755
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -53,15 +53,16 @@ namespace LLCore
const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
{ // isLong isDynamic isGlobal isClass
- { true, true, true, true }, // PO_CONNECTION_LIMIT
- { true, true, false, true }, // PO_PER_HOST_CONNECTION_LIMIT
- { false, false, true, false }, // PO_CA_PATH
- { false, false, true, false }, // PO_CA_FILE
- { false, true, true, false }, // PO_HTTP_PROXY
- { true, true, true, false }, // PO_LLPROXY
- { true, true, true, false }, // PO_TRACE
- { true, true, false, true }, // PO_ENABLE_PIPELINING
- { true, true, false, true } // PO_THROTTLE_RATE
+ { true, true, true, true, false }, // PO_CONNECTION_LIMIT
+ { true, true, false, true, false }, // PO_PER_HOST_CONNECTION_LIMIT
+ { false, false, true, false, false }, // PO_CA_PATH
+ { false, false, true, false, false }, // PO_CA_FILE
+ { false, true, true, false, false }, // PO_HTTP_PROXY
+ { true, true, true, false, false }, // PO_LLPROXY
+ { true, true, true, false, false }, // PO_TRACE
+ { true, true, false, true, false }, // PO_ENABLE_PIPELINING
+ { true, true, false, true, false }, // PO_THROTTLE_RATE
+ { false, false, true, false, true } // PO_SSL_VERIFY_CALLBACK
};
HttpService * HttpService::sInstance(NULL);
volatile HttpService::EState HttpService::sState(NOT_INITIALIZED);
@@ -413,6 +414,34 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
return status;
}
+HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+ HttpRequest::policyCallback_t * ret_value)
+{
+ HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+ if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
+ || opt >= HttpRequest::PO_LAST // ditto
+ || (sOptionDesc[opt].mIsLong) // datatype is string
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range
+ || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass)) // class setting permitted
+ // can always get, no dynamic check
+ {
+ return status;
+ }
+
+ // Only global has callback values
+ if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+ {
+ HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+ status = opts.get(opt, ret_value);
+ }
+
+ return status;
+}
+
+
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
long value, long * ret_value)
@@ -489,6 +518,37 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
return status;
}
-
+
+HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+ HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value)
+{
+ HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+ if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
+ || opt >= HttpRequest::PO_LAST // ditto
+ || (sOptionDesc[opt].mIsLong) // datatype is string
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range
+ || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass) // class setting permitted
+ || (RUNNING == sState && !sOptionDesc[opt].mIsDynamic)) // dynamic setting permitted
+ {
+ return status;
+ }
+
+ // Callbacks values are always global (at this time).
+ if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+ {
+ HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+ status = opts.set(opt, value);
+ if (status && ret_value)
+ {
+ status = opts.get(opt, ret_value);
+ }
+ }
+
+ return status;
+}
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index cf23f3ab61..ac518a5de7 100755
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -201,17 +201,24 @@ protected:
bool mIsDynamic;
bool mIsGlobal;
bool mIsClass;
+ bool mIsCallback;
};
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
long * ret_value);
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
std::string * ret_value);
+ HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+ HttpRequest::policyCallback_t * ret_value);
+
HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
long value, long * ret_value);
HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
const std::string & value, std::string * ret_value);
-
+ HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+ HttpRequest::policyCallback_t value,
+ HttpRequest::policyCallback_t * ret_value);
+
protected:
static const OptionDescriptor sOptionDesc[HttpRequest::PO_LAST];
static HttpService * sInstance;
diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h
index 402e725152..7f713f2298 100755
--- a/indra/llcorehttp/_refcounted.h
+++ b/indra/llcorehttp/_refcounted.h
@@ -32,6 +32,7 @@
#include "fix_macros.h"
#include <boost/thread.hpp>
+#include <boost/intrusive_ptr.hpp>
#include "llapr.h"
@@ -120,7 +121,36 @@ inline void RefCounted::destroySelf()
delete this;
}
+/**
+ * boost::intrusive_ptr may be used to manage RefCounted classes.
+ * Unfortunately RefCounted and boost::intrusive_ptr use different conventions
+ * for the initial refcount value. To avoid leaky (immortal) objects, you
+ * should really construct boost::intrusive_ptr<RefCounted*>(rawptr, false).
+ * IntrusivePtr<T> encapsulates that for you.
+ */
+template <typename T>
+struct IntrusivePtr: public boost::intrusive_ptr<T>
+{
+ IntrusivePtr():
+ boost::intrusive_ptr<T>()
+ {}
+ IntrusivePtr(T* p):
+ boost::intrusive_ptr<T>(p, false)
+ {}
+};
+
+inline void intrusive_ptr_add_ref(RefCounted* p)
+{
+ p->addRef();
+}
+
+inline void intrusive_ptr_release(RefCounted* p)
+{
+ p->release();
+}
+
} // end namespace LLCoreInt
+
#endif // LLCOREINT__REFCOUNTED_H_
diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h
index 1094a435b4..320adf2b8b 100755
--- a/indra/llcorehttp/bufferarray.h
+++ b/indra/llcorehttp/bufferarray.h
@@ -30,6 +30,7 @@
#include <cstdlib>
#include <vector>
+#include "boost/intrusive_ptr.hpp"
#include "_refcounted.h"
@@ -73,6 +74,8 @@ public:
BufferArray();
+ typedef LLCoreInt::IntrusivePtr<BufferArray> ptr_t;
+
protected:
virtual ~BufferArray(); // Use release()
@@ -129,6 +132,7 @@ protected:
container_t mBlocks;
size_t mLen;
+
}; // end class BufferArray
diff --git a/indra/llcorehttp/examples/http_texture_load.cpp b/indra/llcorehttp/examples/http_texture_load.cpp
index 9d9631b980..737282c7df 100755
--- a/indra/llcorehttp/examples/http_texture_load.cpp
+++ b/indra/llcorehttp/examples/http_texture_load.cpp
@@ -83,7 +83,7 @@ public:
WorkingSet();
~WorkingSet();
- bool reload(LLCore::HttpRequest *, LLCore::HttpOptions *);
+ bool reload(LLCore::HttpRequest *, LLCore::HttpOptions::ptr_t &);
virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
@@ -121,7 +121,7 @@ public:
int mRetriesHttp503;
int mSuccesses;
long mByteCount;
- LLCore::HttpHeaders * mHeaders;
+ LLCore::HttpHeaders::ptr_t mHeaders;
};
@@ -304,7 +304,7 @@ int main(int argc, char** argv)
LLCore::HttpRequest * hr = new LLCore::HttpRequest();
// Get request options
- LLCore::HttpOptions * opt = new LLCore::HttpOptions();
+ LLCore::HttpOptions::ptr_t opt = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
opt->setRetries(12);
opt->setUseRetryAfter(true);
@@ -363,8 +363,7 @@ int main(int argc, char** argv)
// Clean up
hr->requestStopThread(NULL);
ms_sleep(1000);
- opt->release();
- opt = NULL;
+ opt.reset();
delete hr;
LLCore::HttpRequest::destroyService();
term_curl();
@@ -427,22 +426,17 @@ WorkingSet::WorkingSet()
{
mAssets.reserve(30000);
- mHeaders = new LLCore::HttpHeaders;
+ mHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHeaders->append("Accept", "image/x-j2c");
}
WorkingSet::~WorkingSet()
{
- if (mHeaders)
- {
- mHeaders->release();
- mHeaders = NULL;
- }
}
-bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions * opt)
+bool WorkingSet::reload(LLCore::HttpRequest * hr, LLCore::HttpOptions::ptr_t & opt)
{
if (mRequestLowWater <= mHandles.size())
{
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 7907e958a4..c423047bb0 100755
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -23,12 +23,24 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
+#if LL_WINDOWS
+#define SAFE_SSL 1
+#elif LL_DARWIN
+#define SAFE_SSL 1
+#else
+#define SAFE_SSL 1
+#endif
+#include "linden_common.h" // Modifies curl/curl.h interfaces
#include "httpcommon.h"
-
+#include "llmutex.h"
+#include "llthread.h"
#include <curl/curl.h>
#include <string>
#include <sstream>
+#if SAFE_SSL
+#include <openssl/crypto.h>
+#endif
namespace LLCore
@@ -42,7 +54,7 @@ HttpStatus::operator unsigned long() const
{
static const int shift(sizeof(unsigned long) * 4);
- unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus);
+ unsigned long result(((unsigned long)mDetails->mType) << shift | (unsigned long)(int)mDetails->mStatus);
return result;
}
@@ -131,30 +143,34 @@ std::string HttpStatus::toString() const
{
return std::string("");
}
- switch (mType)
+ switch (getType())
{
case EXT_CURL_EASY:
- return std::string(curl_easy_strerror(CURLcode(mStatus)));
+ return std::string(curl_easy_strerror(CURLcode(getStatus())));
case EXT_CURL_MULTI:
- return std::string(curl_multi_strerror(CURLMcode(mStatus)));
+ return std::string(curl_multi_strerror(CURLMcode(getStatus())));
case LLCORE:
- if (mStatus >= 0 && mStatus < llcore_errors_count)
+ if (getStatus() >= 0 && getStatus() < llcore_errors_count)
{
- return std::string(llcore_errors[mStatus]);
+ return std::string(llcore_errors[getStatus()]);
}
break;
default:
if (isHttpStatus())
{
+ // special handling for status 499 "Linden Catchall"
+ if ((getType() == 499) && (!getMessage().empty()))
+ return getMessage();
+
// Binary search for the error code and string
int bottom(0), top(http_errors_count);
while (true)
{
int at((bottom + top) / 2);
- if (mType == http_errors[at].mCode)
+ if (getType() == http_errors[at].mCode)
{
return std::string(http_errors[at].mText);
}
@@ -162,7 +178,7 @@ std::string HttpStatus::toString() const
{
break;
}
- else if (mType < http_errors[at].mCode)
+ else if (getType() < http_errors[at].mCode)
{
top = at;
}
@@ -182,9 +198,9 @@ std::string HttpStatus::toTerseString() const
{
std::ostringstream result;
- unsigned int error_value((unsigned short) mStatus);
+ unsigned int error_value((unsigned short)getStatus());
- switch (mType)
+ switch (getType())
{
case EXT_CURL_EASY:
result << "Easy_";
@@ -202,7 +218,7 @@ std::string HttpStatus::toTerseString() const
if (isHttpStatus())
{
result << "Http_";
- error_value = mType;
+ error_value = getType();
}
else
{
@@ -244,7 +260,7 @@ bool HttpStatus::isRetryable() const
// Disable the '*this == inv_status' test and look for 'Core_9'
// failures in log files.
- return ((isHttpStatus() && mType >= 499 && mType <= 599) || // Include special 499 in retryables
+ return ((isHttpStatus() && getType() >= 499 && getType() <= 599) || // Include special 499 in retryables
*this == cant_connect || // Connection reset/endpoint problems
*this == cant_res_proxy || // DNS problems
*this == cant_res_host || // DNS problems
@@ -259,5 +275,168 @@ bool HttpStatus::isRetryable() const
*this == inv_cont_range); // Short data read disagrees with content-range
}
-} // end namespace LLCore
+namespace LLHttp
+{
+namespace
+{
+typedef boost::shared_ptr<LLMutex> LLMutex_ptr;
+std::vector<LLMutex_ptr> sSSLMutex;
+
+CURL *getCurlTemplateHandle()
+{
+ static CURL *curlpTemplateHandle = NULL;
+
+ if (curlpTemplateHandle == NULL)
+ { // Late creation of the template curl handle
+ curlpTemplateHandle = curl_easy_init();
+ if (curlpTemplateHandle == NULL)
+ {
+ LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL;
+ }
+ else
+ {
+ CURLcode result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ check_curl_code(result, CURLOPT_IPRESOLVE);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOSIGNAL, 1);
+ check_curl_code(result, CURLOPT_NOSIGNAL);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOPROGRESS, 1);
+ check_curl_code(result, CURLOPT_NOPROGRESS);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_ENCODING, "");
+ check_curl_code(result, CURLOPT_ENCODING);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_AUTOREFERER, 1);
+ check_curl_code(result, CURLOPT_AUTOREFERER);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_FOLLOWLOCATION, 1);
+ check_curl_code(result, CURLOPT_FOLLOWLOCATION);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYPEER, 1);
+ check_curl_code(result, CURLOPT_SSL_VERIFYPEER);
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ check_curl_code(result, CURLOPT_SSL_VERIFYHOST);
+
+ // The Linksys WRT54G V5 router has an issue with frequent
+ // DNS lookups from LAN machines. If they happen too often,
+ // like for every HTTP request, the router gets annoyed after
+ // about 700 or so requests and starts issuing TCP RSTs to
+ // new connections. Reuse the DNS lookups for even a few
+ // seconds and no RSTs.
+ result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
+ check_curl_code(result, CURLOPT_DNS_CACHE_TIMEOUT);
+ }
+ }
+
+ return curlpTemplateHandle;
+}
+
+LLMutex *getCurlMutex()
+{
+ static LLMutex* sHandleMutexp = NULL;
+
+ if (!sHandleMutexp)
+ {
+ sHandleMutexp = new LLMutex(NULL);
+ }
+
+ return sHandleMutexp;
+}
+
+void deallocateEasyCurl(CURL *curlp)
+{
+ LLMutexLock lock(getCurlMutex());
+
+ curl_easy_cleanup(curlp);
+}
+
+
+#if SAFE_SSL
+//static
+void ssl_locking_callback(int mode, int type, const char *file, int line)
+{
+ if (type >= sSSLMutex.size())
+ {
+ LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL;
+ }
+
+ if (mode & CRYPTO_LOCK)
+ {
+ sSSLMutex[type]->lock();
+ }
+ else
+ {
+ sSSLMutex[type]->unlock();
+ }
+}
+
+//static
+unsigned long ssl_thread_id(void)
+{
+ return LLThread::currentID();
+}
+#endif
+
+}
+
+void initialize()
+{
+ // Do not change this "unless you are familiar with and mean to control
+ // internal operations of libcurl"
+ // - http://curl.haxx.se/libcurl/c/curl_global_init.html
+ CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
+
+ check_curl_code(code, CURL_GLOBAL_ALL);
+
+#if SAFE_SSL
+ S32 mutex_count = CRYPTO_num_locks();
+ for (S32 i = 0; i < mutex_count; i++)
+ {
+ sSSLMutex.push_back(LLMutex_ptr(new LLMutex(NULL)));
+ }
+ CRYPTO_set_id_callback(&ssl_thread_id);
+ CRYPTO_set_locking_callback(&ssl_locking_callback);
+#endif
+
+}
+
+
+void cleanup()
+{
+#if SAFE_SSL
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+ sSSLMutex.clear();
+#endif
+
+ curl_global_cleanup();
+}
+
+
+CURL_ptr createEasyHandle()
+{
+ LLMutexLock lock(getCurlMutex());
+
+ CURL* handle = curl_easy_duphandle(getCurlTemplateHandle());
+
+ return CURL_ptr(handle, &deallocateEasyCurl);
+}
+
+std::string getCURLVersion()
+{
+ return std::string(curl_version());
+}
+
+void check_curl_code(CURLcode code, int curl_setopt_option)
+{
+ if (CURLE_OK != code)
+ {
+ // Comment from old llcurl code which may no longer apply:
+ //
+ // linux appears to throw a curl error once per session for a bad initialization
+ // at a pretty random time (when enabling cookies).
+ LL_WARNS() << "libcurl error detected: " << curl_easy_strerror(code)
+ << ", curl_easy_setopt option: " << curl_setopt_option
+ << LL_ENDL;
+ }
+
+}
+
+}
+} // end namespace LLCore
diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index 9601f94125..1bc20fe6b5 100755
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -188,9 +188,12 @@
///
#include "linden_common.h" // Modifies curl/curl.h interfaces
-
+#include "boost/intrusive_ptr.hpp"
+#include "boost/shared_ptr.hpp"
+#include "boost/weak_ptr.hpp"
+#include "boost/function.hpp"
#include <string>
-
+#include <curl/curl.h>
namespace LLCore
{
@@ -286,52 +289,63 @@ enum HttpError
/// 5. Construct an HTTP 301 status code to be treated as success:
/// HttpStatus(301, HE_SUCCESS);
///
+/// 6. Construct a failed status of HTTP Status 499 with a custom error message
+/// HttpStatus(499, "Failed LLSD Response");
struct HttpStatus
{
typedef unsigned short type_enum_t;
HttpStatus()
- : mType(LLCORE),
- mStatus(HE_SUCCESS)
- {}
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS));
+ }
HttpStatus(type_enum_t type, short status)
- : mType(type),
- mStatus(status)
- {}
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(type, status));
+ }
HttpStatus(int http_status)
- : mType(http_status),
- mStatus(http_status >= 200 && http_status <= 299
- ? HE_SUCCESS
- : HE_REPLY_ERROR)
- {
- llassert(http_status >= 100 && http_status <= 999);
- }
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(http_status,
+ (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR));
+ llassert(http_status >= 100 && http_status <= 999);
+ }
+
+ HttpStatus(int http_status, const std::string &message)
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(http_status,
+ (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR));
+ llassert(http_status >= 100 && http_status <= 999);
+ mDetails->mMessage = message;
+ }
HttpStatus(const HttpStatus & rhs)
- : mType(rhs.mType),
- mStatus(rhs.mStatus)
- {}
+ {
+ mDetails = rhs.mDetails;
+ }
+
+ ~HttpStatus()
+ {
+ }
HttpStatus & operator=(const HttpStatus & rhs)
- {
- // Don't care if lhs & rhs are the same object
+ {
+ mDetails = rhs.mDetails;
+ return *this;
+ }
- mType = rhs.mType;
- mStatus = rhs.mStatus;
- return *this;
- }
+ HttpStatus & clone(const HttpStatus &rhs)
+ {
+ mDetails = boost::shared_ptr<Details>(new Details(*rhs.mDetails));
+ return *this;
+ }
static const type_enum_t EXT_CURL_EASY = 0; ///< mStatus is an error from a curl_easy_*() call
static const type_enum_t EXT_CURL_MULTI = 1; ///< mStatus is an error from a curl_multi_*() call
static const type_enum_t LLCORE = 2; ///< mStatus is an HE_* error code
///< 100-999 directly represent HTTP status codes
-
- type_enum_t mType;
- short mStatus;
-
/// Test for successful status in the code regardless
/// of error source (internal, libcurl).
///
@@ -339,7 +353,7 @@ struct HttpStatus
///
operator bool() const
{
- return 0 == mStatus;
+ return 0 == mDetails->mStatus;
}
/// Inverse of previous operator.
@@ -347,14 +361,14 @@ struct HttpStatus
/// @return 'true' on any error condition
bool operator !() const
{
- return 0 != mStatus;
+ return 0 != mDetails->mStatus;
}
/// Equality and inequality tests to bypass bool conversion
/// which will do the wrong thing in conditional expressions.
bool operator==(const HttpStatus & rhs) const
{
- return mType == rhs.mType && mStatus == rhs.mStatus;
+ return (*mDetails == *rhs.mDetails);
}
bool operator!=(const HttpStatus & rhs) const
@@ -395,7 +409,7 @@ struct HttpStatus
/// HTTP response status (100 - 999).
bool isHttpStatus() const
{
- return mType >= type_enum_t(100) && mType <= type_enum_t(999);
+ return mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999);
}
/// Returns true if the status is one that will be retried
@@ -403,9 +417,94 @@ struct HttpStatus
/// where that logic needs to be replicated. Only applies
/// to failed statuses, successful statuses will return false.
bool isRetryable() const;
-
+
+ /// Returns the currently set status code as a raw number
+ ///
+ short getStatus() const
+ {
+ return mDetails->mStatus;
+ }
+
+ /// Returns the currently set status type
+ ///
+ type_enum_t getType() const
+ {
+ return mDetails->mType;
+ }
+
+ /// Returns an optional error message if one has been set.
+ ///
+ std::string getMessage() const
+ {
+ return mDetails->mMessage;
+ }
+
+ /// Sets an optional error message
+ ///
+ void setMessage(const std::string &message)
+ {
+ mDetails->mMessage = message;
+ }
+
+ /// Retrieves an optionally recorded SSL certificate.
+ void * getErrorData() const
+ {
+ return mDetails->mErrorData;
+ }
+
+ /// Optionally sets an SSL certificate on this status.
+ void setErrorData(void *data)
+ {
+ mDetails->mErrorData = data;
+ }
+
+private:
+
+ struct Details
+ {
+ Details(type_enum_t type, short status):
+ mType(type),
+ mStatus(status),
+ mMessage(),
+ mErrorData(NULL)
+ {}
+
+ Details(const Details &rhs) :
+ mType(rhs.mType),
+ mStatus(rhs.mStatus),
+ mMessage(rhs.mMessage),
+ mErrorData(rhs.mErrorData)
+ {}
+
+ bool operator == (const Details &rhs) const
+ {
+ return (mType == rhs.mType) && (mStatus == rhs.mStatus);
+ }
+
+ type_enum_t mType;
+ short mStatus;
+ std::string mMessage;
+ void * mErrorData;
+ };
+
+ boost::shared_ptr<Details> mDetails;
+
}; // end struct HttpStatus
+/// A namespace for several free methods and low level utilities.
+namespace LLHttp
+{
+ typedef boost::shared_ptr<CURL> CURL_ptr;
+
+ void initialize();
+ void cleanup();
+
+ CURL_ptr createEasyHandle();
+ std::string getCURLVersion();
+
+ void check_curl_code(CURLcode code, int curl_setopt_option);
+}
+
} // end namespace LLCore
#endif // _LLCORE_HTTP_COMMON_H_
diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h
index 9171e4e7b9..7bc9096703 100755
--- a/indra/llcorehttp/httphandler.h
+++ b/indra/llcorehttp/httphandler.h
@@ -45,7 +45,7 @@ class HttpResponse;
/// be shared by any number of requests and across instances
/// of HttpRequest running in the same thread.
///
-/// Threading: HttpHandler itself is pure interface and is
+/// Threading: HttpHandler itself is interface and is
/// tread-compatible. Most derivations, however, will have
/// different constraints.
///
@@ -53,12 +53,13 @@ class HttpResponse;
/// that is rarely a good idea. Queued requests and replies keep
/// a naked pointer to the handler and this can result in a
/// dangling pointer if lifetimes aren't managed correctly.
-
-class HttpHandler
+///
+/// *TODO: public std::enable_shared_from_this<HttpHandler>
+class HttpHandler
{
public:
virtual ~HttpHandler()
- {}
+ { }
/// Method invoked during calls to @see update(). Each invocation
/// represents the completion of some requested operation. Caller
diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp
index 23ebea361c..f586191a7c 100755
--- a/indra/llcorehttp/httpheaders.cpp
+++ b/indra/llcorehttp/httpheaders.cpp
@@ -34,7 +34,6 @@ namespace LLCore
HttpHeaders::HttpHeaders()
- : RefCounted(true)
{}
@@ -105,7 +104,7 @@ void HttpHeaders::appendNormal(const char * header, size_t size)
// 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 std::string * HttpHeaders::find(const std::string &name) const
{
const_reverse_iterator iend(rend());
for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter)
@@ -118,6 +117,24 @@ const std::string * HttpHeaders::find(const char * name) const
return NULL;
}
+void HttpHeaders::remove(const char *name)
+{
+ remove(std::string(name));
+}
+
+void HttpHeaders::remove(const std::string &name)
+{
+ iterator iend(end());
+ for (iterator iter(begin()); iend != iter; ++iter)
+ {
+ if ((*iter).first == name)
+ {
+ mHeaders.erase(iter);
+ return;
+ }
+ }
+}
+
// Standard Iterators
HttpHeaders::iterator HttpHeaders::begin()
diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h
index f70cd898f3..b9168cb6ec 100755
--- a/indra/llcorehttp/httpheaders.h
+++ b/indra/llcorehttp/httpheaders.h
@@ -28,8 +28,8 @@
#define _LLCORE_HTTP_HEADERS_H_
+#include "httpcommon.h"
#include <string>
-
#include "_refcounted.h"
@@ -74,7 +74,7 @@ namespace LLCore
/// constructor is given a refcount.
///
-class HttpHeaders : public LLCoreInt::RefCounted
+class HttpHeaders: private boost::noncopyable
{
public:
typedef std::pair<std::string, std::string> header_t;
@@ -85,15 +85,17 @@ public:
typedef container_t::const_reverse_iterator const_reverse_iterator;
typedef container_t::value_type value_type;
typedef container_t::size_type size_type;
+ typedef boost::shared_ptr<HttpHeaders> ptr_t;
public:
/// @post In addition to the instance, caller has a refcount
/// to the instance. A call to @see release() will destroy
/// the instance.
HttpHeaders();
+ virtual ~HttpHeaders(); // Use release()
+ //typedef LLCoreInt::IntrusivePtr<HttpHeaders> ptr_t;
protected:
- virtual ~HttpHeaders(); // Use release()
HttpHeaders(const HttpHeaders &); // Not defined
void operator=(const HttpHeaders &); // Not defined
@@ -145,8 +147,16 @@ public:
// 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;
+ const std::string * find(const std::string &name) const;
+ const std::string * find(const char * name) const
+ {
+ return find(std::string(name));
+ }
+
+ // Remove the header from the list if found.
+ //
+ void remove(const std::string &name);
+ void remove(const char *name);
// Count of headers currently in the list.
size_type size() const
diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp
index 5bf1ecb4a5..aab447f2dd 100755
--- a/indra/llcorehttp/httpoptions.cpp
+++ b/indra/llcorehttp/httpoptions.cpp
@@ -25,7 +25,7 @@
*/
#include "httpoptions.h"
-
+#include "lldefs.h"
#include "_httpinternal.h"
@@ -33,14 +33,18 @@ namespace LLCore
{
-HttpOptions::HttpOptions()
- : RefCounted(true),
- mWantHeaders(false),
- mTracing(HTTP_TRACE_OFF),
- mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
- mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
- mRetries(HTTP_RETRY_COUNT_DEFAULT),
- mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT)
+HttpOptions::HttpOptions() :
+ mWantHeaders(false),
+ mTracing(HTTP_TRACE_OFF),
+ mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
+ mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
+ mRetries(HTTP_RETRY_COUNT_DEFAULT),
+ mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT),
+ mFollowRedirects(true),
+ mVerifyPeer(false),
+ mVerifyHost(false),
+ mDNSCacheTimeout(-1L),
+ mNoBody(false)
{}
@@ -82,5 +86,31 @@ void HttpOptions::setUseRetryAfter(bool use_retry)
mUseRetryAfter = use_retry;
}
+void HttpOptions::setFollowRedirects(bool follow_redirect)
+{
+ mFollowRedirects = follow_redirect;
+}
+
+void HttpOptions::setSSLVerifyPeer(bool verify)
+{
+ mVerifyPeer = verify;
+}
+
+void HttpOptions::setSSLVerifyHost(bool verify)
+{
+ mVerifyHost = verify;
+}
+
+void HttpOptions::setDNSCacheTimeout(int timeout)
+{
+ mDNSCacheTimeout = timeout;
+}
+
+void HttpOptions::setHeadersOnly(bool nobody)
+{
+ mNoBody = nobody;
+ if (mNoBody)
+ setWantHeaders(true);
+}
} // end namespace LLCore
diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h
index 4ab5ff18c4..510eaa45bb 100755
--- a/indra/llcorehttp/httpoptions.h
+++ b/indra/llcorehttp/httpoptions.h
@@ -29,7 +29,6 @@
#include "httpcommon.h"
-
#include "_refcounted.h"
@@ -56,59 +55,110 @@ namespace LLCore
/// Allocation: Refcounted, heap only. Caller of the constructor
/// is given a refcount.
///
-class HttpOptions : public LLCoreInt::RefCounted
+class HttpOptions : private boost::noncopyable
{
public:
HttpOptions();
+ typedef boost::shared_ptr<HttpOptions> ptr_t;
+
+ virtual ~HttpOptions(); // Use release()
+
protected:
- virtual ~HttpOptions(); // Use release()
HttpOptions(const HttpOptions &); // Not defined
void operator=(const HttpOptions &); // Not defined
public:
+
// Default: false
void setWantHeaders(bool wanted);
bool getWantHeaders() const
- {
- return mWantHeaders;
- }
+ {
+ return mWantHeaders;
+ }
// Default: 0
void setTrace(int long);
int getTrace() const
- {
- return mTracing;
- }
+ {
+ return mTracing;
+ }
// Default: 30
void setTimeout(unsigned int timeout);
unsigned int getTimeout() const
- {
- return mTimeout;
- }
+ {
+ return mTimeout;
+ }
// Default: 0
void setTransferTimeout(unsigned int timeout);
unsigned int getTransferTimeout() const
- {
- return mTransferTimeout;
- }
+ {
+ return mTransferTimeout;
+ }
+ /// Sets the number of retries on an LLCore::HTTPRequest before the
+ /// request fails.
// Default: 8
void setRetries(unsigned int retries);
unsigned int getRetries() const
- {
- return mRetries;
- }
+ {
+ return mRetries;
+ }
// Default: true
void setUseRetryAfter(bool use_retry);
bool getUseRetryAfter() const
- {
- return mUseRetryAfter;
- }
+ {
+ return mUseRetryAfter;
+ }
+
+ /// Instructs the LLCore::HTTPRequest to follow redirects
+ /// Default: false
+ void setFollowRedirects(bool follow_redirect);
+ bool getFollowRedirects() const
+ {
+ return mFollowRedirects;
+ }
+
+ /// Instructs the LLCore::HTTPRequest to verify that the exchanged security
+ /// certificate is authentic.
+ /// Default: false
+ void setSSLVerifyPeer(bool verify);
+ bool getSSLVerifyPeer() const
+ {
+ return mVerifyPeer;
+ }
+
+ /// Instructs the LLCore::HTTPRequest to verify that the name in the
+ /// security certificate matches the name of the host contacted.
+ /// Default: false
+ void setSSLVerifyHost(bool verify);
+ bool getSSLVerifyHost() const
+ {
+ return mVerifyHost;
+ }
+
+ /// Sets the time for DNS name caching in seconds. Setting this value
+ /// to 0 will disable name caching. Setting this value to -1 causes the
+ /// name cache to never time out.
+ /// Default: -1
+ void setDNSCacheTimeout(int timeout);
+ int getDNSCacheTimeout() const
+ {
+ return mDNSCacheTimeout;
+ }
+
+ /// Retrieve only the headers and status from the request. Setting this
+ /// to true implies setWantHeaders(true) as well.
+ /// Default: false
+ void setHeadersOnly(bool nobody);
+ bool getHeadersOnly() const
+ {
+ return mNoBody;
+ }
protected:
bool mWantHeaders;
@@ -117,6 +167,11 @@ protected:
unsigned int mTransferTimeout;
unsigned int mRetries;
bool mUseRetryAfter;
+ bool mFollowRedirects;
+ bool mVerifyPeer;
+ bool mVerifyHost;
+ int mDNSCacheTimeout;
+ bool mNoBody;
}; // end class HttpOptions
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 7b1888e3eb..63233259fb 100755
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -117,6 +117,15 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass
return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
}
+HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback_t value, policyCallback_t * ret_value)
+{
+ if (HttpService::RUNNING == HttpService::instanceOf()->getState())
+ {
+ return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
+ }
+
+ return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
+}
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
long value, HttpHandler * handler)
@@ -188,8 +197,8 @@ HttpStatus HttpRequest::getStatus() const
HttpHandle HttpRequest::requestGet(policy_t policy_id,
priority_t priority,
const std::string & url,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * user_handler)
{
HttpStatus status;
@@ -222,8 +231,8 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
const std::string & url,
size_t offset,
size_t len,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * user_handler)
{
HttpStatus status;
@@ -255,8 +264,8 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * user_handler)
{
HttpStatus status;
@@ -288,8 +297,8 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * user_handler)
{
HttpStatus status;
@@ -316,6 +325,131 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
return handle;
}
+HttpHandle HttpRequest::requestDelete(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupDelete(policy_id, priority, url, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
+HttpHandle HttpRequest::requestPatch(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
+HttpHandle HttpRequest::requestCopy(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupCopy(policy_id, priority, url, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
+HttpHandle HttpRequest::requestMove(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler)
+{
+ HttpStatus status;
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ HttpOpRequest * op = new HttpOpRequest();
+ if (!(status = op->setupMove(policy_id, priority, url, options, headers)))
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+ op->setReplyPath(mReplyQueue, user_handler);
+ if (!(status = mRequestQueue->addOp(op))) // transfers refcount
+ {
+ op->release();
+ mLastReqStatus = status;
+ return handle;
+ }
+
+ mLastReqStatus = status;
+ handle = static_cast<HttpHandle>(op);
+
+ return handle;
+}
+
HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
{
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 7f23723b0b..6c2449266f 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -31,6 +31,8 @@
#include "httpcommon.h"
#include "httphandler.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
namespace LLCore
{
@@ -38,8 +40,6 @@ namespace LLCore
class HttpRequestQueue;
class HttpReplyQueue;
class HttpService;
-class HttpOptions;
-class HttpHeaders;
class HttpOperation;
class BufferArray;
@@ -97,6 +97,8 @@ public:
typedef unsigned int policy_t;
typedef unsigned int priority_t;
+ typedef boost::shared_ptr<HttpRequest> ptr_t;
+ typedef boost::weak_ptr<HttpRequest> wptr_t;
public:
/// @name PolicyMethods
/// @{
@@ -163,7 +165,7 @@ public:
/// Long value that if non-zero enables the use of the
/// traditional LLProxy code for http/socks5 support. If
- // enabled, has priority over GP_HTTP_PROXY.
+ /// enabled, has priority over GP_HTTP_PROXY.
///
/// Global only
PO_LLPROXY,
@@ -219,15 +221,25 @@ public:
/// Controls whether client-side throttling should be
/// performed on this policy class. Positive values
/// enable throttling and specify the request rate
- /// (requests per second) that should be targetted.
+ /// (requests per second) that should be targeted.
/// A value of zero, the default, specifies no throttling.
///
/// Per-class only
PO_THROTTLE_RATE,
+ /// Controls the callback function used to control SSL CTX
+ /// certificate verification.
+ ///
+ /// Global only
+ PO_SSL_VERIFY_CALLBACK,
+
PO_LAST // Always at end
};
+ /// Prototype for policy based callbacks. The callback methods will be executed
+ /// on the worker thread so no modifications should be made to the HttpHandler object.
+ typedef boost::function<HttpStatus(const std::string &, HttpHandler const * const, void *)> policyCallback_t;
+
/// Set a policy option for a global or class parameter at
/// startup time (prior to thread start).
///
@@ -243,6 +255,8 @@ public:
long value, long * ret_value);
static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
const std::string & value, std::string * ret_value);
+ static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
+ policyCallback_t value, policyCallback_t * ret_value);;
/// Set a parameter on a class-based policy option. Calls
/// made after the start of the servicing thread are
@@ -334,8 +348,8 @@ public:
HttpHandle requestGet(policy_t policy_id,
priority_t priority,
const std::string & url,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * handler);
@@ -377,8 +391,8 @@ public:
const std::string & url,
size_t offset,
size_t len,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * handler);
@@ -418,8 +432,8 @@ public:
priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * handler);
@@ -459,12 +473,92 @@ public:
priority_t priority,
const std::string & url,
BufferArray * body,
- HttpOptions * options,
- HttpHeaders * headers,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
HttpHandler * handler);
- /// Queue a NoOp request.
+ /// Queue a full HTTP DELETE. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestDelete(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler);
+
+ /// Queue a full HTTP PATCH. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param body Byte stream to be sent as the body. No
+ /// further encoding or escaping will be done
+ /// to the content.
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestPatch(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ BufferArray * body,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler);
+
+ /// Queue a full HTTP COPY. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestCopy(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler);
+
+ /// Queue a full HTTP MOVE. Query arguments and body may
+ /// be provided. Caller is responsible for escaping and
+ /// encoding and communicating the content types.
+ ///
+ /// @param policy_id @see requestGet()
+ /// @param priority "
+ /// @param url "
+ /// @param options @see requestGet()K(optional)
+ /// @param headers "
+ /// @param handler "
+ /// @return "
+ ///
+ HttpHandle requestMove(policy_t policy_id,
+ priority_t priority,
+ const std::string & url,
+ const HttpOptions::ptr_t & options,
+ const HttpHeaders::ptr_t & headers,
+ HttpHandler * user_handler);
+
+ /// Queue a NoOp request.
/// The request is queued and serviced by the working thread which
/// immediately processes it and returns the request to the reply
/// queue.
diff --git a/indra/llcorehttp/httpresponse.cpp b/indra/llcorehttp/httpresponse.cpp
index c974395b0a..f5ad2ebd47 100755
--- a/indra/llcorehttp/httpresponse.cpp
+++ b/indra/llcorehttp/httpresponse.cpp
@@ -39,16 +39,17 @@ HttpResponse::HttpResponse()
mReplyLength(0U),
mReplyFullLength(0U),
mBufferArray(NULL),
- mHeaders(NULL),
+ mHeaders(),
mRetries(0U),
- m503Retries(0U)
+ m503Retries(0U),
+ mRequestUrl()
{}
HttpResponse::~HttpResponse()
{
setBody(NULL);
- setHeaders(NULL);
+ //setHeaders();
}
@@ -71,23 +72,14 @@ void HttpResponse::setBody(BufferArray * ba)
}
-void HttpResponse::setHeaders(HttpHeaders * headers)
+void HttpResponse::setHeaders(HttpHeaders::ptr_t &headers)
{
- if (mHeaders == headers)
- return;
-
- if (mHeaders)
- {
- mHeaders->release();
- }
-
- if (headers)
- {
- headers->addRef();
- }
-
- mHeaders = headers;
+ mHeaders = headers;
}
+size_t HttpResponse::getBodySize() const
+{
+ return (mBufferArray) ? mBufferArray->size() : 0;
+}
} // end namespace LLCore
diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h
index aee64e2878..0bfa4585c7 100755
--- a/indra/llcorehttp/httpresponse.h
+++ b/indra/llcorehttp/httpresponse.h
@@ -31,7 +31,7 @@
#include <string>
#include "httpcommon.h"
-
+#include "httpheaders.h"
#include "_refcounted.h"
@@ -69,6 +69,18 @@ protected:
void operator=(const HttpResponse &); // Not defined
public:
+ /// Statistics for the HTTP
+ struct TransferStats
+ {
+ typedef boost::shared_ptr<TransferStats> ptr_t;
+
+ TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
+ F64 mSizeDownload;
+ F64 mTotalTime;
+ F64 mSpeedDownload;
+ };
+
+
/// Returns the final status of the requested operation.
///
HttpStatus getStatus() const
@@ -92,6 +104,10 @@ public:
return mBufferArray;
}
+ /// Safely get the size of the body buffer. If the body buffer is missing
+ /// return 0 as the size.
+ size_t getBodySize() const;
+
/// Set the response data in the instance. Will drop the reference
/// count to any existing data and increment the count of that passed
/// in. It is legal to set the data to NULL.
@@ -104,13 +120,13 @@ public:
///
/// Caller can hold onto the headers by incrementing the reference
/// count of the returned object.
- HttpHeaders * getHeaders() const
- {
+ HttpHeaders::ptr_t getHeaders() const
+ {
return mHeaders;
- }
+ }
/// Behaves like @see setResponse() but for header data.
- void setHeaders(HttpHeaders * headers);
+ void setHeaders(HttpHeaders::ptr_t &headers);
/// If a 'Range:' header was used, these methods are involved
/// in setting and returning data about the actual response.
@@ -168,6 +184,27 @@ public:
m503Retries = retries_503;
}
+ void setTransferStats(TransferStats::ptr_t &stats)
+ {
+ mStats = stats;
+ }
+
+ TransferStats::ptr_t getTransferStats()
+ {
+ return mStats;
+ }
+
+ void setRequestURL(const std::string &url)
+ {
+ mRequestUrl = url;
+ }
+
+ const std::string &getRequestURL() const
+ {
+ return mRequestUrl;
+ }
+
+
protected:
// Response data here
HttpStatus mStatus;
@@ -175,10 +212,13 @@ protected:
unsigned int mReplyLength;
unsigned int mReplyFullLength;
BufferArray * mBufferArray;
- HttpHeaders * mHeaders;
+ HttpHeaders::ptr_t mHeaders;
std::string mContentType;
unsigned int mRetries;
unsigned int m503Retries;
+ std::string mRequestUrl;
+
+ TransferStats::ptr_t mStats;
};
diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llcorehttp/llhttpconstants.cpp
index 32f76f0d70..71d4f19408 100755
--- a/indra/llmessage/llhttpconstants.cpp
+++ b/indra/llcorehttp/llhttpconstants.cpp
@@ -133,94 +133,3 @@ 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/llcorehttp/llhttpconstants.h
index d6bcbd3c19..121448854e 100755
--- a/indra/llmessage/llhttpconstants.h
+++ b/indra/llcorehttp/llhttpconstants.h
@@ -116,13 +116,6 @@ enum EHTTPMethod
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);
diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp
index 668c36dc66..c05f1d9429 100755
--- a/indra/llcorehttp/tests/test_httpheaders.hpp
+++ b/indra/llcorehttp/tests/test_httpheaders.hpp
@@ -59,13 +59,12 @@ void HttpHeadersTestObjectType::test<1>()
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpHeaders * headers = new HttpHeaders();
- ensure("One ref on construction of HttpHeaders", headers->getRefCount() == 1);
+ HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
ensure("Memory being used", mMemTotal < GetMemTotal());
ensure("Nothing in headers", 0 == headers->size());
// release the implicit reference, causing the object to be released
- headers->release();
+ headers.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
@@ -80,7 +79,7 @@ void HttpHeadersTestObjectType::test<2>()
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpHeaders * headers = new HttpHeaders();
+ HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
{
// Append a few strings
@@ -101,7 +100,7 @@ void HttpHeadersTestObjectType::test<2>()
}
// release the implicit reference, causing the object to be released
- headers->release();
+ headers.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
@@ -116,7 +115,7 @@ void HttpHeadersTestObjectType::test<3>()
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpHeaders * headers = new HttpHeaders();
+ HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
{
// Append a few strings
@@ -151,7 +150,7 @@ void HttpHeadersTestObjectType::test<3>()
}
// release the implicit reference, causing the object to be released
- headers->release();
+ headers.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
@@ -166,8 +165,8 @@ void HttpHeadersTestObjectType::test<4>()
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpHeaders * headers = new HttpHeaders();
-
+ HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
+
{
static char line1[] = " AcCePT : image/yourfacehere";
static char line1v[] = "image/yourfacehere";
@@ -251,7 +250,7 @@ void HttpHeadersTestObjectType::test<4>()
}
// release the implicit reference, causing the object to be released
- headers->release();
+ headers.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
@@ -267,7 +266,7 @@ void HttpHeadersTestObjectType::test<5>()
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpHeaders * headers = new HttpHeaders();
+ HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
HttpHeaders::iterator end(headers->end()), begin(headers->begin());
ensure("Empty container has equal begin/end const iterators", end == begin);
@@ -337,7 +336,7 @@ void HttpHeadersTestObjectType::test<5>()
}
// release the implicit reference, causing the object to be released
- headers->release();
+ headers.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
@@ -353,7 +352,7 @@ void HttpHeadersTestObjectType::test<6>()
mMemTotal = GetMemTotal();
// create a new ref counted object with an implicit reference
- HttpHeaders * headers = new HttpHeaders();
+ HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin());
ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin);
@@ -421,7 +420,7 @@ void HttpHeadersTestObjectType::test<6>()
}
// release the implicit reference, causing the object to be released
- headers->release();
+ headers.reset();
// make sure we didn't leak any memory
ensure(mMemTotal == GetMemTotal());
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index 43f7e36da5..1f606bd0c1 100755
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -112,7 +112,7 @@ public:
if (! mHeadersRequired.empty() || ! mHeadersDisallowed.empty())
{
ensure("Response required with header check", response != NULL);
- HttpHeaders * header(response->getHeaders()); // Will not hold onto this
+ HttpHeaders::ptr_t header(response->getHeaders()); // Will not hold onto this
ensure("Some quantity of headers returned", header != NULL);
if (! mHeadersRequired.empty())
@@ -638,7 +638,7 @@ void HttpRequestTestObjectType::test<7>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * opts = NULL;
+ HttpOptions::ptr_t opts;
try
{
@@ -653,7 +653,7 @@ void HttpRequestTestObjectType::test<7>()
req = new HttpRequest();
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
- opts = new HttpOptions();
+ opts = HttpOptions::ptr_t(new HttpOptions());
opts->setRetries(1); // Don't try for too long - default retries take about 18S
// Issue a GET that can't connect
@@ -664,7 +664,7 @@ void HttpRequestTestObjectType::test<7>()
0,
0,
opts,
- NULL,
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
@@ -705,8 +705,7 @@ void HttpRequestTestObjectType::test<7>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options
- opts->release();
- opts = NULL;
+ opts.reset();
// release the request object
delete req;
@@ -728,11 +727,7 @@ void HttpRequestTestObjectType::test<7>()
catch (...)
{
stop_thread(req);
- if (opts)
- {
- opts->release();
- opts = NULL;
- }
+ opts.reset();
delete req;
HttpRequest::destroyService();
throw;
@@ -779,8 +774,8 @@ void HttpRequestTestObjectType::test<8>()
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base,
- NULL,
- NULL,
+ HttpOptions::ptr_t(),
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
@@ -889,8 +884,8 @@ void HttpRequestTestObjectType::test<9>()
url_base,
0,
0,
- NULL,
- NULL,
+ HttpOptions::ptr_t(),
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
@@ -1001,9 +996,9 @@ void HttpRequestTestObjectType::test<10>()
0U,
url_base,
body,
- NULL,
- NULL,
- &handler);
+ HttpOptions::ptr_t(),
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1119,9 +1114,9 @@ void HttpRequestTestObjectType::test<11>()
0U,
url_base,
body,
- NULL,
- NULL,
- &handler);
+ HttpOptions::ptr_t(),
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1239,9 +1234,9 @@ void HttpRequestTestObjectType::test<12>()
url_base,
0,
0,
- NULL,
- NULL,
- &handler);
+ HttpOptions::ptr_t(),
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1332,7 +1327,7 @@ void HttpRequestTestObjectType::test<13>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * opts = NULL;
+ HttpOptions::ptr_t opts;
try
{
@@ -1350,7 +1345,7 @@ void HttpRequestTestObjectType::test<13>()
req = new HttpRequest();
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
- opts = new HttpOptions();
+ opts = HttpOptions::ptr_t(new HttpOptions());
opts->setWantHeaders(true);
// Issue a GET that succeeds
@@ -1364,13 +1359,12 @@ void HttpRequestTestObjectType::test<13>()
0,
0,
opts,
- NULL,
- &handler);
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// release options
- opts->release();
- opts = NULL;
+ opts.reset();
// Run the notification pump.
int count(0);
@@ -1430,11 +1424,7 @@ void HttpRequestTestObjectType::test<13>()
catch (...)
{
stop_thread(req);
- if (opts)
- {
- opts->release();
- opts = NULL;
- }
+ opts.reset();
delete req;
HttpRequest::destroyService();
throw;
@@ -1460,7 +1450,7 @@ void HttpRequestTestObjectType::test<14>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * opts = NULL;
+ HttpOptions::ptr_t opts;
try
{
@@ -1475,7 +1465,7 @@ void HttpRequestTestObjectType::test<14>()
req = new HttpRequest();
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
- opts = new HttpOptions();
+ opts = HttpOptions::ptr_t(new HttpOptions);
opts->setRetries(0); // Don't retry
opts->setTimeout(2);
@@ -1487,8 +1477,8 @@ void HttpRequestTestObjectType::test<14>()
0,
0,
opts,
- NULL,
- &handler);
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1528,8 +1518,7 @@ void HttpRequestTestObjectType::test<14>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options
- opts->release();
- opts = NULL;
+ opts.reset();
// release the request object
delete req;
@@ -1552,11 +1541,7 @@ void HttpRequestTestObjectType::test<14>()
catch (...)
{
stop_thread(req);
- if (opts)
- {
- opts->release();
- opts = NULL;
- }
+ opts.reset();
delete req;
HttpRequest::destroyService();
throw;
@@ -1609,9 +1594,9 @@ void HttpRequestTestObjectType::test<15>()
HttpHandle handle = req->requestGet(HttpRequest::DEFAULT_POLICY_ID,
0U,
url_base,
- NULL,
- NULL,
- &handler);
+ HttpOptions::ptr_t(),
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
// Run the notification pump.
@@ -1703,8 +1688,8 @@ void HttpRequestTestObjectType::test<16>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * options = NULL;
- HttpHeaders * headers = NULL;
+ HttpOptions::ptr_t options;
+ HttpHeaders::ptr_t headers;
try
{
@@ -1719,7 +1704,7 @@ void HttpRequestTestObjectType::test<16>()
req = new HttpRequest();
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setWantHeaders(true);
// Issue a GET that *can* connect
@@ -1776,7 +1761,7 @@ void HttpRequestTestObjectType::test<16>()
0U,
url_base + "reflect/",
options,
- NULL,
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
@@ -1792,7 +1777,7 @@ void HttpRequestTestObjectType::test<16>()
ensure("One handler invocation for request", mHandlerCalls == 1);
// Do a texture-style fetch
- headers = new HttpHeaders;
+ headers = HttpHeaders::ptr_t(new HttpHeaders);
headers->append("Accept", "image/x-j2c");
mStatus = HttpStatus(200);
@@ -1897,17 +1882,8 @@ void HttpRequestTestObjectType::test<16>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options & headers
- if (options)
- {
- options->release();
- }
- options = NULL;
-
- if (headers)
- {
- headers->release();
- }
- headers = NULL;
+ options.reset();
+ headers.reset();
// release the request object
delete req;
@@ -1919,16 +1895,9 @@ void HttpRequestTestObjectType::test<16>()
catch (...)
{
stop_thread(req);
- if (options)
- {
- options->release();
- options = NULL;
- }
- if (headers)
- {
- headers->release();
- headers = NULL;
- }
+ options.reset();
+ headers.reset();
+
delete req;
HttpRequest::destroyService();
throw;
@@ -1960,8 +1929,8 @@ void HttpRequestTestObjectType::test<17>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * options = NULL;
- HttpHeaders * headers = NULL;
+ HttpOptions::ptr_t options;
+ HttpHeaders::ptr_t headers;
BufferArray * ba = NULL;
try
@@ -1977,7 +1946,7 @@ void HttpRequestTestObjectType::test<17>()
req = new HttpRequest();
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setWantHeaders(true);
// And a buffer array
@@ -2049,7 +2018,7 @@ void HttpRequestTestObjectType::test<17>()
url_base + "reflect/",
ba,
options,
- NULL,
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
ba->release();
@@ -2095,17 +2064,8 @@ void HttpRequestTestObjectType::test<17>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options & headers
- if (options)
- {
- options->release();
- }
- options = NULL;
-
- if (headers)
- {
- headers->release();
- }
- headers = NULL;
+ options.reset();
+ headers.reset();
// release the request object
delete req;
@@ -2122,17 +2082,10 @@ void HttpRequestTestObjectType::test<17>()
ba->release();
ba = NULL;
}
- if (options)
- {
- options->release();
- options = NULL;
- }
- if (headers)
- {
- headers->release();
- headers = NULL;
- }
- delete req;
+ options.reset();
+ headers.reset();
+
+ delete req;
HttpRequest::destroyService();
throw;
}
@@ -2163,8 +2116,8 @@ void HttpRequestTestObjectType::test<18>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * options = NULL;
- HttpHeaders * headers = NULL;
+ HttpOptions::ptr_t options;
+ HttpHeaders::ptr_t headers;
BufferArray * ba = NULL;
try
@@ -2180,7 +2133,7 @@ void HttpRequestTestObjectType::test<18>()
req = new HttpRequest();
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setWantHeaders(true);
// And a buffer array
@@ -2253,7 +2206,7 @@ void HttpRequestTestObjectType::test<18>()
url_base + "reflect/",
ba,
options,
- NULL,
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for get request", handle != LLCORE_HTTP_HANDLE_INVALID);
ba->release();
@@ -2299,17 +2252,8 @@ void HttpRequestTestObjectType::test<18>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options & headers
- if (options)
- {
- options->release();
- }
- options = NULL;
-
- if (headers)
- {
- headers->release();
- }
- headers = NULL;
+ options.reset();
+ headers.reset();
// release the request object
delete req;
@@ -2326,17 +2270,10 @@ void HttpRequestTestObjectType::test<18>()
ba->release();
ba = NULL;
}
- if (options)
- {
- options->release();
- options = NULL;
- }
- if (headers)
- {
- headers->release();
- headers = NULL;
- }
- delete req;
+ options.reset();
+ headers.reset();
+
+ delete req;
HttpRequest::destroyService();
throw;
}
@@ -2367,8 +2304,8 @@ void HttpRequestTestObjectType::test<19>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * options = NULL;
- HttpHeaders * headers = NULL;
+ HttpOptions::ptr_t options;
+ HttpHeaders::ptr_t headers;
try
{
@@ -2383,11 +2320,11 @@ void HttpRequestTestObjectType::test<19>()
req = new HttpRequest();
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setWantHeaders(true);
// headers
- headers = new HttpHeaders;
+ headers = HttpHeaders::ptr_t(new HttpHeaders);
headers->append("Keep-Alive", "120");
headers->append("Accept-encoding", "deflate");
headers->append("Accept", "text/plain");
@@ -2502,17 +2439,8 @@ void HttpRequestTestObjectType::test<19>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options & headers
- if (options)
- {
- options->release();
- }
- options = NULL;
-
- if (headers)
- {
- headers->release();
- }
- headers = NULL;
+ options.reset();
+ headers.reset();
// release the request object
delete req;
@@ -2524,16 +2452,9 @@ void HttpRequestTestObjectType::test<19>()
catch (...)
{
stop_thread(req);
- if (options)
- {
- options->release();
- options = NULL;
- }
- if (headers)
- {
- headers->release();
- headers = NULL;
- }
+ options.reset();
+ headers.reset();
+
delete req;
HttpRequest::destroyService();
throw;
@@ -2565,8 +2486,8 @@ void HttpRequestTestObjectType::test<20>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * options = NULL;
- HttpHeaders * headers = NULL;
+ HttpOptions::ptr_t options;
+ HttpHeaders::ptr_t headers;
BufferArray * ba = NULL;
try
@@ -2582,11 +2503,11 @@ void HttpRequestTestObjectType::test<20>()
req = new HttpRequest();
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setWantHeaders(true);
// headers
- headers = new HttpHeaders();
+ headers = HttpHeaders::ptr_t(new HttpHeaders());
headers->append("keep-Alive", "120");
headers->append("Accept", "text/html");
headers->append("content-type", "application/llsd+xml");
@@ -2720,17 +2641,8 @@ void HttpRequestTestObjectType::test<20>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options & headers
- if (options)
- {
- options->release();
- }
- options = NULL;
-
- if (headers)
- {
- headers->release();
- }
- headers = NULL;
+ options.reset();
+ headers.reset();
// release the request object
delete req;
@@ -2747,16 +2659,8 @@ void HttpRequestTestObjectType::test<20>()
ba->release();
ba = NULL;
}
- if (options)
- {
- options->release();
- options = NULL;
- }
- if (headers)
- {
- headers->release();
- headers = NULL;
- }
+ options.reset();
+ headers.reset();
delete req;
HttpRequest::destroyService();
throw;
@@ -2788,8 +2692,8 @@ void HttpRequestTestObjectType::test<21>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * options = NULL;
- HttpHeaders * headers = NULL;
+ HttpOptions::ptr_t options;
+ HttpHeaders::ptr_t headers;
BufferArray * ba = NULL;
try
@@ -2805,11 +2709,11 @@ void HttpRequestTestObjectType::test<21>()
req = new HttpRequest();
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setWantHeaders(true);
// headers
- headers = new HttpHeaders;
+ headers = HttpHeaders::ptr_t(new HttpHeaders);
headers->append("content-type", "text/plain");
headers->append("content-type", "text/html");
headers->append("content-type", "application/llsd+xml");
@@ -2937,17 +2841,8 @@ void HttpRequestTestObjectType::test<21>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options & headers
- if (options)
- {
- options->release();
- }
- options = NULL;
-
- if (headers)
- {
- headers->release();
- }
- headers = NULL;
+ options.reset();
+ headers.reset();
// release the request object
delete req;
@@ -2964,16 +2859,8 @@ void HttpRequestTestObjectType::test<21>()
ba->release();
ba = NULL;
}
- if (options)
- {
- options->release();
- options = NULL;
- }
- if (headers)
- {
- headers->release();
- headers = NULL;
- }
+ options.reset();
+ headers.reset();
delete req;
HttpRequest::destroyService();
throw;
@@ -3000,13 +2887,13 @@ void HttpRequestTestObjectType::test<22>()
mMemTotal = GetMemTotal();
mHandlerCalls = 0;
- HttpOptions * options = NULL;
+ HttpOptions::ptr_t options;
HttpRequest * req = NULL;
try
{
// options set
- options = new HttpOptions();
+ options = HttpOptions::ptr_t(new HttpOptions());
options->setRetries(1); // Partial_File is retryable and can timeout in here
// Get singletons created
@@ -3035,8 +2922,8 @@ void HttpRequestTestObjectType::test<22>()
0,
25,
options,
- NULL,
- &handler);
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
}
@@ -3067,7 +2954,7 @@ void HttpRequestTestObjectType::test<22>()
0,
25,
options,
- NULL,
+ HttpHeaders::ptr_t(),
&handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
}
@@ -3099,8 +2986,8 @@ void HttpRequestTestObjectType::test<22>()
0,
25,
options,
- NULL,
- &handler);
+ HttpHeaders::ptr_t(),
+ &handler);
ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
}
@@ -3144,11 +3031,7 @@ void HttpRequestTestObjectType::test<22>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options
- if (options)
- {
- options->release();
- options = NULL;
- }
+ options.reset();
// release the request object
delete req;
@@ -3198,7 +3081,7 @@ void HttpRequestTestObjectType::test<23>()
mHandlerCalls = 0;
HttpRequest * req = NULL;
- HttpOptions * opts = NULL;
+ HttpOptions::ptr_t opts;
try
{
@@ -3213,7 +3096,7 @@ void HttpRequestTestObjectType::test<23>()
req = new HttpRequest();
ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
- opts = new HttpOptions();
+ opts = HttpOptions::ptr_t(new HttpOptions());
opts->setRetries(1); // Retry once only
opts->setUseRetryAfter(true); // Try to parse the retry-after header
@@ -3230,8 +3113,8 @@ void HttpRequestTestObjectType::test<23>()
0,
0,
opts,
- NULL,
- &handler);
+ HttpHeaders::ptr_t(),
+ &handler);
std::ostringstream testtag;
testtag << "Valid handle returned for 503 request #" << i;
@@ -3277,8 +3160,7 @@ void HttpRequestTestObjectType::test<23>()
ensure("Thread actually stopped running", HttpService::isStopped());
// release options
- opts->release();
- opts = NULL;
+ opts.reset();
// release the request object
delete req;
@@ -3299,11 +3181,7 @@ void HttpRequestTestObjectType::test<23>()
catch (...)
{
stop_thread(req);
- if (opts)
- {
- opts->release();
- opts = NULL;
- }
+ opts.reset();
delete req;
HttpRequest::destroyService();
throw;
diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp
index 0b379836c9..4502d32fe1 100755
--- a/indra/llcorehttp/tests/test_httpstatus.hpp
+++ b/indra/llcorehttp/tests/test_httpstatus.hpp
@@ -55,77 +55,68 @@ void HttpStatusTestObjectType::test<1>()
// auto allocation fine for this
HttpStatus status;
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = 0;
+
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);
ensure(bool(status));
ensure(false == !(status));
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = 0;
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0);
ensure(bool(status));
ensure(false == !(status));
-
- status.mType = HttpStatus::LLCORE;
- status.mStatus = HE_SUCCESS;
+
+ status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS);
ensure(bool(status));
ensure(false == !(status));
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = -1;
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1);
ensure(false == bool(status));
ensure(!(status));
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = CURLE_BAD_DOWNLOAD_RESUME;
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_DOWNLOAD_RESUME);
ensure(false == bool(status));
ensure(!(status));
}
-template <> template <>
-void HttpStatusTestObjectType::test<2>()
-{
- set_test_name("HttpStatus memory structure");
-
- // Require that an HttpStatus object can be trivially
- // returned as a function return value in registers.
- // One should fit in an int on all platforms.
-
- ensure(sizeof(HttpStatus) <= sizeof(int));
-}
+// template <> template <>
+// void HttpStatusTestObjectType::test<2>()
+// {
+// set_test_name("HttpStatus memory structure");
+//
+// // Require that an HttpStatus object can be trivially
+// // returned as a function return value in registers.
+// // One should fit in an int on all platforms.
+//
+// //ensure(sizeof(HttpStatus) <= sizeof(int));
+// }
template <> template <>
-void HttpStatusTestObjectType::test<3>()
+void HttpStatusTestObjectType::test<2>()
{
set_test_name("HttpStatus valid status string conversion");
- HttpStatus status;
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = 0;
+ HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);
std::string msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(msg.empty());
-
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT;
+
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = CURLM_OUT_OF_MEMORY;
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
- status.mType = HttpStatus::LLCORE;
- status.mStatus = HE_SHUTTING_DOWN;
+ status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
@@ -133,32 +124,28 @@ void HttpStatusTestObjectType::test<3>()
template <> template <>
-void HttpStatusTestObjectType::test<4>()
+void HttpStatusTestObjectType::test<3>()
{
set_test_name("HttpStatus invalid status string conversion");
- HttpStatus status;
- status.mType = HttpStatus::EXT_CURL_EASY;
- status.mStatus = 32726;
+ HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726);
std::string msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
-
- status.mType = HttpStatus::EXT_CURL_MULTI;
- status.mStatus = -470;
+
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
- status.mType = HttpStatus::LLCORE;
- status.mStatus = 923;
+ status = HttpStatus(HttpStatus::LLCORE, 923);
msg = status.toString();
// std::cout << "Result: " << msg << std::endl;
ensure(! msg.empty());
}
template <> template <>
-void HttpStatusTestObjectType::test<5>()
+void HttpStatusTestObjectType::test<4>()
{
set_test_name("HttpStatus equality/inequality testing");
@@ -170,62 +157,55 @@ void HttpStatusTestObjectType::test<5>()
HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);
ensure(status1 != status2);
- status1.mType = HttpStatus::LLCORE;
- status1.mStatus = HE_REPLY_ERROR;
- status2.mType = HttpStatus::LLCORE;
- status2.mStatus= HE_SHUTTING_DOWN;
+ status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR);
+ status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN);
+
ensure(status1 != status2);
}
template <> template <>
-void HttpStatusTestObjectType::test<6>()
+void HttpStatusTestObjectType::test<5>()
{
set_test_name("HttpStatus basic HTTP status encoding");
HttpStatus status;
- status.mType = 200;
- status.mStatus = HE_SUCCESS;
+
+ status = HttpStatus(200, HE_SUCCESS);
std::string msg = status.toString();
ensure(msg.empty());
ensure(bool(status));
// Normally a success but application says error
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(200, HE_REPLY_ERROR);
msg = status.toString();
ensure(! msg.empty());
ensure(! bool(status));
ensure(status.toULong() > 1UL); // Biggish number, not a bool-to-ulong
// Same statuses with distinct success/fail are distinct
- status.mType = 200;
- status.mStatus = HE_SUCCESS;
+ status = HttpStatus(200, HE_SUCCESS);
HttpStatus status2(200, HE_REPLY_ERROR);
ensure(status != status2);
// Normally an error but application says okay
- status.mType = 406;
- status.mStatus = HE_SUCCESS;
+ status = HttpStatus(406, HE_SUCCESS);
msg = status.toString();
ensure(msg.empty());
ensure(bool(status));
// Different statuses but both successful are distinct
- status.mType = 200;
- status.mStatus = HE_SUCCESS;
- status2.mType = 201;
- status2.mStatus = HE_SUCCESS;
+ status = HttpStatus(200, HE_SUCCESS);
+ status2 = HttpStatus(201, HE_SUCCESS);
ensure(status != status2);
// Different statuses but both failed are distinct
- status.mType = 200;
- status.mStatus = HE_REPLY_ERROR;
- status2.mType = 201;
- status2.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(200, HE_REPLY_ERROR);
+ status2 = HttpStatus(201, HE_REPLY_ERROR);
ensure(status != status2);
}
template <> template <>
-void HttpStatusTestObjectType::test<7>()
+void HttpStatusTestObjectType::test<6>()
{
set_test_name("HttpStatus HTTP status text strings");
@@ -234,34 +214,30 @@ void HttpStatusTestObjectType::test<7>()
ensure(! msg.empty()); // Should be something
ensure(msg == "Continue");
- status.mStatus = HE_SUCCESS;
+ status = HttpStatus(200, HE_SUCCESS);
msg = status.toString();
ensure(msg.empty()); // Success is empty
- status.mType = 199;
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(199, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "Unknown error");
- status.mType = 505; // Last defined string
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(505, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "HTTP Version not supported");
- status.mType = 506; // One beyond
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(506, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "Unknown error");
- status.mType = 999; // Last HTTP status
- status.mStatus = HE_REPLY_ERROR;
+ status = HttpStatus(999, HE_REPLY_ERROR);
msg = status.toString();
ensure(msg == "Unknown error");
}
template <> template <>
-void HttpStatusTestObjectType::test<8>()
+void HttpStatusTestObjectType::test<7>()
{
set_test_name("HttpStatus toHex() nominal function");
@@ -273,7 +249,7 @@ void HttpStatusTestObjectType::test<8>()
template <> template <>
-void HttpStatusTestObjectType::test<9>()
+void HttpStatusTestObjectType::test<8>()
{
set_test_name("HttpStatus toTerseString() nominal function");
diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt
index ba4e34d92b..da23b46b7b 100755
--- a/indra/llcrashlogger/CMakeLists.txt
+++ b/indra/llcrashlogger/CMakeLists.txt
@@ -3,6 +3,7 @@
project(llcrashlogger)
include(00-Common)
+include(LLCoreHttp)
include(LLCommon)
include(LLMath)
include(LLMessage)
@@ -10,6 +11,7 @@ include(LLVFS)
include(LLXML)
include_directories(
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index 7a97c16ea7..6fd4579876 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -40,38 +40,45 @@
#include "lldir.h"
#include "llfile.h"
#include "llsdserialize.h"
-#include "lliopipe.h"
-#include "llpumpio.h"
-#include "llhttpclient.h"
#include "llsdserialize.h"
#include "llproxy.h"
-
-LLPumpIO* gServicePump = NULL;
+#include "llcorehttputil.h"
+#include "llhttpsdhandler.h"
+#include "httpcommon.h"
+#include "httpresponse.h"
+
+#include <curl/curl.h>
+#include <openssl/crypto.h>
+
BOOL gBreak = false;
BOOL gSent = false;
-class LLCrashLoggerResponder : public LLHTTPClient::Responder
+int LLCrashLogger::ssl_mutex_count = 0;
+LLCoreInt::HttpMutex ** LLCrashLogger::ssl_mutex_list = NULL;
+
+class LLCrashLoggerHandler : public LLHttpSDHandler
{
- LOG_CLASS(LLCrashLoggerResponder);
+ LOG_CLASS(LLCrashLoggerHandler);
public:
- LLCrashLoggerResponder()
- {
- }
+ LLCrashLoggerHandler() {}
protected:
- virtual void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- gBreak = true;
- }
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
- virtual void httpSuccess()
- {
- gBreak = true;
- gSent = true;
- }
};
+void LLCrashLoggerHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
+{
+ gBreak = true;
+ gSent = true;
+}
+
+void LLCrashLoggerHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
+{
+ gBreak = true;
+}
+
LLCrashLogger::LLCrashLogger() :
mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND),
mCrashInPreviousExec(false),
@@ -207,11 +214,13 @@ void LLCrashLogger::gatherFiles()
mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
if(mDebugLog.has("CAFilename"))
{
- LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
+ LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID, mDebugLog["CAFilename"].asString(), NULL);
}
else
{
- LLCurl::setCAFile(gDirUtilp->getCAFile());
+ LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
}
LL_INFOS() << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL;
@@ -220,7 +229,8 @@ void LLCrashLogger::gatherFiles()
else
{
// Figure out the filename of the second life log
- LLCurl::setCAFile(gDirUtilp->getCAFile());
+ LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log");
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
@@ -389,14 +399,23 @@ bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior)
bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout)
{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
gBreak = false;
+ httpOpts->setTimeout(timeout);
+
for(int i = 0; i < retries; ++i)
{
updateApplication(llformat("%s, try %d...", msg.c_str(), i+1));
- LLHTTPClient::post(host, data, new LLCrashLoggerResponder(), timeout);
- while(!gBreak)
+
+ LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,
+ host, data, httpOpts, LLCore::HttpHeaders::ptr_t(), new LLCrashLoggerHandler);
+
+ while(!gBreak)
{
updateApplication(); // No new message, just pump the IO
+ httpRequest->update(0L);
}
if(gSent)
{
@@ -510,14 +529,12 @@ bool LLCrashLogger::sendCrashLogs()
void LLCrashLogger::updateApplication(const std::string& message)
{
- gServicePump->pump();
- gServicePump->callback();
if (!message.empty()) LL_INFOS() << message << LL_ENDL;
}
bool LLCrashLogger::init()
{
- LLCurl::initClass(false);
+ LLCore::LLHttp::initialize();
// We assume that all the logs we're looking for reside on the current drive
gDirUtilp->initAppDirs("SecondLife");
@@ -576,16 +593,74 @@ bool LLCrashLogger::init()
return false;
}
- gServicePump = new LLPumpIO(gAPRPoolp);
- gServicePump->prime(gAPRPoolp);
- LLHTTPClient::setPump(*gServicePump);
-
+ init_curl();
+ LLCore::HttpRequest::createService();
+ LLCore::HttpRequest::startThread();
+
return true;
}
// For cleanup code common to all platforms.
void LLCrashLogger::commonCleanup()
{
+ term_curl();
LLError::logToFile(""); //close crashreport.log
LLProxy::cleanupClass();
}
+
+void LLCrashLogger::init_curl()
+{
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ ssl_mutex_count = CRYPTO_num_locks();
+ if (ssl_mutex_count > 0)
+ {
+ ssl_mutex_list = new LLCoreInt::HttpMutex *[ssl_mutex_count];
+
+ for (int i(0); i < ssl_mutex_count; ++i)
+ {
+ ssl_mutex_list[i] = new LLCoreInt::HttpMutex;
+ }
+
+ CRYPTO_set_locking_callback(ssl_locking_callback);
+ CRYPTO_set_id_callback(ssl_thread_id_callback);
+ }
+}
+
+
+void LLCrashLogger::term_curl()
+{
+ CRYPTO_set_locking_callback(NULL);
+ for (int i(0); i < ssl_mutex_count; ++i)
+ {
+ delete ssl_mutex_list[i];
+ }
+ delete[] ssl_mutex_list;
+}
+
+
+unsigned long LLCrashLogger::ssl_thread_id_callback(void)
+{
+#if LL_WINDOWS
+ return (unsigned long)GetCurrentThread();
+#else
+ return (unsigned long)pthread_self();
+#endif
+}
+
+
+void LLCrashLogger::ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */)
+{
+ if (type >= 0 && type < ssl_mutex_count)
+ {
+ if (mode & CRYPTO_LOCK)
+ {
+ ssl_mutex_list[type]->lock();
+ }
+ else
+ {
+ ssl_mutex_list[type]->unlock();
+ }
+ }
+}
+
diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h
index a06bf1d6ac..f5383daefc 100755
--- a/indra/llcrashlogger/llcrashlogger.h
+++ b/indra/llcrashlogger/llcrashlogger.h
@@ -34,6 +34,7 @@
#include "llsd.h"
#include "llcontrol.h"
#include "llcrashlock.h"
+#include "_mutex.h"
// Crash reporter behavior
const S32 CRASH_BEHAVIOR_ASK = 0;
@@ -66,6 +67,11 @@ public:
bool readMinidump(std::string minidump_path);
protected:
+ static void init_curl();
+ static void term_curl();
+ static unsigned long ssl_thread_id_callback(void);
+ static void ssl_locking_callback(int mode, int type, const char * file, int line);
+
S32 mCrashBehavior;
BOOL mCrashInPreviousExec;
std::map<std::string, std::string> mFileMap;
@@ -78,6 +84,10 @@ protected:
LLSD mDebugLog;
bool mSentCrashLogs;
LLCrashLock mKeyMaster;
+
+ static int ssl_mutex_count;
+ static LLCoreInt::HttpMutex ** ssl_mutex_list;
+
};
#endif //LLCRASHLOGGER_H
diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt
index 0a1f93bd80..68dd00d880 100755
--- a/indra/llinventory/CMakeLists.txt
+++ b/indra/llinventory/CMakeLists.txt
@@ -4,6 +4,7 @@ project(llinventory)
include(00-Common)
include(LLCommon)
+include(LLCoreHttp)
include(LLMath)
include(LLMessage)
include(LLVFS)
@@ -71,7 +72,7 @@ if (LL_TESTS)
LL_ADD_PROJECT_UNIT_TESTS(llinventory "${llinventory_TEST_SOURCE_FILES}")
#set(TEST_DEBUG on)
- set(test_libs llinventory ${LLMESSAGE_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
+ set(test_libs llinventory ${LLMESSAGE_LIBRARIES} ${LLVFS_LIBRARIES} ${LLCOREHTTP_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
LL_ADD_INTEGRATION_TEST(inventorymisc "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llparcel "" "${test_libs}")
endif (LL_TESTS)
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 0a308fbf10..78c84f366a 100755
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -14,6 +14,7 @@ include(LLAddBuildTest)
include(Python)
include(Tut)
include(Python)
+include(JsonCpp)
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
@@ -23,11 +24,10 @@ include_directories(
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
${LLVFS_INCLUDE_DIRS}
+ ${JSONCPP_INCLUDE_DIR}
)
set(llmessage_SOURCE_FILES
- llares.cpp
- llareslistener.cpp
llassetstorage.cpp
llavatarname.cpp
llavatarnamecache.cpp
@@ -38,19 +38,15 @@ set(llmessage_SOURCE_FILES
llchainio.cpp
llcircuit.cpp
llclassifiedflags.cpp
+ llcoproceduremanager.cpp
llcorehttputil.cpp
- llcurl.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
- llhttpassetstorage.cpp
- llhttpclient.cpp
- llhttpclientadapter.cpp
- llhttpconstants.cpp
llhttpnode.cpp
- llhttpsender.cpp
+ llhttpsdhandler.cpp
llinstantmessage.cpp
lliobuffer.cpp
lliohttpserver.cpp
@@ -74,11 +70,8 @@ set(llmessage_SOURCE_FILES
llpumpio.cpp
llsdappservices.cpp
llsdhttpserver.cpp
- llsdmessage.cpp
llsdmessagebuilder.cpp
llsdmessagereader.cpp
- llsdrpcclient.cpp
- llsdrpcserver.cpp
llservicebuilder.cpp
llservice.cpp
llstoredmessage.cpp
@@ -92,7 +85,6 @@ set(llmessage_SOURCE_FILES
lltransfertargetfile.cpp
lltransfertargetvfile.cpp
lltrustedmessageservice.cpp
- llurlrequest.cpp
lluseroperation.cpp
llxfer.cpp
llxfer_file.cpp
@@ -115,8 +107,6 @@ set(llmessage_SOURCE_FILES
set(llmessage_HEADER_FILES
CMakeLists.txt
- llares.h
- llareslistener.h
llassetstorage.h
llavatarname.h
llavatarnamecache.h
@@ -128,8 +118,8 @@ set(llmessage_HEADER_FILES
llcipher.h
llcircuit.h
llclassifiedflags.h
+ llcoproceduremanager.h
llcorehttputil.h
- llcurl.h
lldatapacker.h
lldbstrings.h
lldispatcher.h
@@ -139,14 +129,9 @@ set(llmessage_HEADER_FILES
llfiltersd2xmlrpc.h
llfollowcamparams.h
llhost.h
- llhttpassetstorage.h
- llhttpclient.h
- llhttpclientinterface.h
- llhttpclientadapter.h
- llhttpconstants.h
llhttpnode.h
llhttpnodeadapter.h
- llhttpsender.h
+ llhttpsdhandler.h
llinstantmessage.h
llinvite.h
lliobuffer.h
@@ -176,11 +161,8 @@ set(llmessage_HEADER_FILES
llregionhandle.h
llsdappservices.h
llsdhttpserver.h
- llsdmessage.h
llsdmessagebuilder.h
llsdmessagereader.h
- llsdrpcclient.h
- llsdrpcserver.h
llservice.h
llservicebuilder.h
llstoredmessage.h
@@ -196,7 +178,6 @@ set(llmessage_HEADER_FILES
lltransfertargetfile.h
lltransfertargetvfile.h
lltrustedmessageservice.h
- llurlrequest.h
lluseroperation.h
llvehicleparams.h
llxfer.h
@@ -226,12 +207,16 @@ target_link_libraries(
llmessage
${CURL_LIBRARIES}
${LLCOMMON_LIBRARIES}
- ${LLVFS_LIBRARES}
+ ${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
- ${CARES_LIBRARIES}
+ ${JSONCPP_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${XMLRPCEPI_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
)
# tests
@@ -243,36 +228,25 @@ if (LL_TESTS)
)
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}
${LLMATH_LIBRARIES}
+ ${CURL_LIBRARIES}
${LLCOMMON_LIBRARIES}
- ${GOOGLEMOCK_LIBRARIES}
- )
-
- LL_ADD_INTEGRATION_TEST(
- llsdmessage
- "llsdmessage.cpp"
- "${test_libs}"
- ${PYTHON_EXECUTABLE}
- "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py"
- )
-
- LL_ADD_INTEGRATION_TEST(
- llhttpclient
- "llhttpclient.cpp"
- "${test_libs}"
- ${PYTHON_EXECUTABLE}
- "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py"
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
+ ${JSONCPP_LIBRARIES}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${GOOGLEMOCK_LIBRARIES}
)
- LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")
+ #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/llares.cpp b/indra/llmessage/llares.cpp
deleted file mode 100755
index 9f90ae1544..0000000000
--- a/indra/llmessage/llares.cpp
+++ /dev/null
@@ -1,839 +0,0 @@
-/**
- * @file llares.cpp
- * @author Bryan O'Sullivan
- * @date 2007-08-15
- * @brief Wrapper for asynchronous DNS lookups.
- *
- * $LicenseInfo:firstyear=2007&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 "llares.h"
-
-#include <ares_dns.h>
-#include <ares_version.h>
-
-#include "apr_portable.h"
-#include "apr_network_io.h"
-#include "apr_poll.h"
-
-#include "llapr.h"
-#include "llareslistener.h"
-
-#if defined(LL_WINDOWS)
-#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
-# define ns_c_in 1
-# define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
-# define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
-# define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
-#else
-# include <arpa/nameser.h>
-#endif
-
-LLAres::HostResponder::~HostResponder()
-{
-}
-
-void LLAres::HostResponder::hostResult(const hostent *ent)
-{
- LL_INFOS() << "LLAres::HostResponder::hostResult not implemented" << LL_ENDL;
-}
-
-void LLAres::HostResponder::hostError(int code)
-{
- LL_INFOS() << "LLAres::HostResponder::hostError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-LLAres::NameInfoResponder::~NameInfoResponder()
-{
-}
-
-void LLAres::NameInfoResponder::nameInfoResult(const char *node,
- const char *service)
-{
- LL_INFOS() << "LLAres::NameInfoResponder::nameInfoResult not implemented"
- << LL_ENDL;
-}
-
-void LLAres::NameInfoResponder::nameInfoError(int code)
-{
- LL_INFOS() << "LLAres::NameInfoResponder::nameInfoError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-LLAres::QueryResponder::~QueryResponder()
-{
-}
-
-void LLAres::QueryResponder::queryResult(const char *buf, size_t len)
-{
- LL_INFOS() << "LLAres::QueryResponder::queryResult not implemented"
- << LL_ENDL;
-}
-
-void LLAres::QueryResponder::queryError(int code)
-{
- LL_INFOS() << "LLAres::QueryResponder::queryError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-LLAres::LLAres() :
- chan_(NULL),
- mInitSuccess(false)
-{
- if (ares_library_init( ARES_LIB_INIT_ALL ) != ARES_SUCCESS ||
- ares_init(&chan_) != ARES_SUCCESS)
- {
- LL_WARNS() << "Could not succesfully initialize ares!" << LL_ENDL;
- return;
- }
-
- mListener = boost::shared_ptr< LLAresListener >(new LLAresListener(this));
-
- mInitSuccess = true;
-}
-
-LLAres::~LLAres()
-{
- ares_destroy(chan_);
- ares_library_cleanup();
-}
-
-void LLAres::cancel()
-{
- ares_cancel(chan_);
-}
-
-static void host_callback_1_5(void *arg, int status, int timeouts,
- struct hostent *ent)
-{
- LLPointer<LLAres::HostResponder> *resp =
- (LLPointer<LLAres::HostResponder> *) arg;
-
- if (status == ARES_SUCCESS)
- {
- (*resp)->hostResult(ent);
- } else {
- (*resp)->hostError(status);
- }
-
- delete resp;
-}
-
-#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
-static void host_callback(void *arg, int status, struct hostent *ent)
-{
- host_callback_1_5(arg, status, 0, ent);
-}
-#else
-# define host_callback host_callback_1_5
-#endif
-
-void LLAres::getHostByName(const char *name, HostResponder *resp,
- int family)
-{
- ares_gethostbyname(chan_, name, family, host_callback,
- new LLPointer<LLAres::HostResponder>(resp));
-}
-
-void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
-{
- search(name, RES_SRV, resp);
-}
-
-void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
-{
- if (resp && uri.size())
- {
- LLURI* pURI = new LLURI(uri);
-
- resp->mUri = *pURI;
-
- delete pURI;
-
- if (!resp->mUri.scheme().size() || !resp->mUri.hostName().size())
- {
- return;
- }
-
- //LL_INFOS() << "LLAres::rewriteURI (" << uri << ") search: '" << "_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName() << "'" << LL_ENDL;
-
- search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), RES_SRV, resp);
-
-
- }
-}
-
-LLQueryResponder::LLQueryResponder()
- : LLAres::QueryResponder(),
- mResult(ARES_ENODATA),
- mType(RES_INVALID)
-{
-}
-
-int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
- LLPointer<LLDnsRecord> &r)
-{
- std::string rrname;
- size_t enclen;
- int ret;
-
- // RR name.
-
- ret = LLAres::expandName(pos, buf, len, rrname, enclen);
- if (ret != ARES_SUCCESS)
- {
- return ret;
- }
-
- pos += enclen;
-
- if (pos + NS_RRFIXEDSZ > buf + len)
- {
- return ARES_EBADRESP;
- }
-
- int rrtype = DNS_RR_TYPE(pos);
- int rrclass = DNS_RR_CLASS(pos);
- int rrttl = DNS_RR_TTL(pos);
- int rrlen = DNS_RR_LEN(pos);
-
- if (rrclass != ns_c_in)
- {
- return ARES_EBADRESP;
- }
-
- pos += NS_RRFIXEDSZ;
-
- if (pos + rrlen > buf + len)
- {
- return ARES_EBADRESP;
- }
-
- switch (rrtype)
- {
- case RES_A:
- r = new LLARecord(rrname, rrttl);
- break;
- case RES_NS:
- r = new LLNsRecord(rrname, rrttl);
- break;
- case RES_CNAME:
- r = new LLCnameRecord(rrname, rrttl);
- break;
- case RES_PTR:
- r = new LLPtrRecord(rrname, rrttl);
- break;
- case RES_AAAA:
- r = new LLAaaaRecord(rrname, rrttl);
- break;
- case RES_SRV:
- r = new LLSrvRecord(rrname, rrttl);
- break;
- default:
- LL_INFOS() << "LLQueryResponder::parseRR got unknown RR type " << rrtype
- << LL_ENDL;
- return ARES_EBADRESP;
- }
-
- ret = r->parse(buf, len, pos, rrlen);
-
- if (ret == ARES_SUCCESS)
- {
- pos += rrlen;
- } else {
- r = NULL;
- }
-
- return ret;
-}
-
-int LLQueryResponder::parseSection(const char *buf, size_t len,
- size_t count, const char *&pos,
- dns_rrs_t &rrs)
-{
- int ret = ARES_SUCCESS;
-
- for (size_t i = 0; i < count; i++)
- {
- LLPointer<LLDnsRecord> r;
- ret = parseRR(buf, len, pos, r);
- if (ret != ARES_SUCCESS)
- {
- break;
- }
- rrs.push_back(r);
- }
-
- return ret;
-}
-
-void LLQueryResponder::queryResult(const char *buf, size_t len)
-{
- const char *pos = buf;
- int qdcount = DNS_HEADER_QDCOUNT(pos);
- int ancount = DNS_HEADER_ANCOUNT(pos);
- int nscount = DNS_HEADER_NSCOUNT(pos);
- int arcount = DNS_HEADER_ARCOUNT(pos);
- int ret;
-
- if (qdcount == 0 || ancount + nscount + arcount == 0)
- {
- ret = ARES_ENODATA;
- goto bail;
- }
-
- pos += NS_HFIXEDSZ;
-
- for (int i = 0; i < qdcount; i++)
- {
- std::string ignore;
- size_t enclen;
-
- ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
- enclen);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- pos += enclen;
-
- if (i == 0)
- {
- int t = DNS_QUESTION_TYPE(pos);
- switch (t)
- {
- case RES_A:
- case RES_NS:
- case RES_CNAME:
- case RES_PTR:
- case RES_AAAA:
- case RES_SRV:
- mType = (LLResType) t;
- break;
- default:
- LL_INFOS() << "Cannot grok query type " << t << LL_ENDL;
- ret = ARES_EBADQUERY;
- goto bail;
- }
- }
-
- pos += NS_QFIXEDSZ;
- if (pos > buf + len)
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
- }
-
- ret = parseSection(buf, len, ancount, pos, mAnswers);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- ret = parseSection(buf, len, nscount, pos, mAuthorities);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- ret = parseSection(buf, len, arcount, pos, mAdditional);
-
-bail:
- mResult = ret;
- if (mResult == ARES_SUCCESS)
- {
- querySuccess();
- } else {
- queryError(mResult);
- }
-}
-
-void LLQueryResponder::querySuccess()
-{
- LL_INFOS() << "LLQueryResponder::queryResult not implemented" << LL_ENDL;
-}
-
-void LLAres::SrvResponder::querySuccess()
-{
- if (mType == RES_SRV)
- {
- srvResult(mAnswers);
- } else {
- srvError(ARES_EBADRESP);
- }
-}
-
-void LLAres::SrvResponder::queryError(int code)
-{
- srvError(code);
-}
-
-void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
-{
- LL_INFOS() << "LLAres::SrvResponder::srvResult not implemented" << LL_ENDL;
-
- for (size_t i = 0; i < ents.size(); i++)
- {
- const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
-
- LL_INFOS() << "[" << i << "] " << s->host() << ":" << s->port()
- << " priority " << s->priority()
- << " weight " << s->weight()
- << LL_ENDL;
- }
-}
-
-void LLAres::SrvResponder::srvError(int code)
-{
- LL_INFOS() << "LLAres::SrvResponder::srvError " << code << ": "
- << LLAres::strerror(code) << LL_ENDL;
-}
-
-static void nameinfo_callback_1_5(void *arg, int status, int timeouts,
- char *node, char *service)
-{
- LLPointer<LLAres::NameInfoResponder> *resp =
- (LLPointer<LLAres::NameInfoResponder> *) arg;
-
- if (status == ARES_SUCCESS)
- {
- (*resp)->nameInfoResult(node, service);
- } else {
- (*resp)->nameInfoError(status);
- }
-
- delete resp;
-}
-
-#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
-static void nameinfo_callback(void *arg, int status, char *node, char *service)
-{
- nameinfo_callback_1_5(arg, status, 0, node, service);
-}
-#else
-# define nameinfo_callback nameinfo_callback_1_5
-#endif
-
-void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
- NameInfoResponder *resp)
-{
- ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
- new LLPointer<NameInfoResponder>(resp));
-}
-
-static void search_callback_1_5(void *arg, int status, int timeouts,
- unsigned char *abuf, int alen)
-{
- LLPointer<LLAres::QueryResponder> *resp =
- (LLPointer<LLAres::QueryResponder> *) arg;
-
- if (status == ARES_SUCCESS)
- {
- (*resp)->queryResult((const char *) abuf, alen);
- } else {
- (*resp)->queryError(status);
- }
-
- delete resp;
-}
-
-#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
-static void search_callback(void *arg, int status, unsigned char *abuf,
- int alen)
-{
- search_callback_1_5(arg, status, 0, abuf, alen);
-}
-#else
-# define search_callback search_callback_1_5
-#endif
-
-void LLAres::search(const std::string &query, LLResType type,
- QueryResponder *resp)
-{
- ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
- new LLPointer<QueryResponder>(resp));
-}
-
-bool LLAres::process(U64 timeout)
-{
- if (!gAPRPoolp)
- {
- ll_init_apr();
- }
-
- ares_socket_t socks[ARES_GETSOCK_MAXNUM];
- apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
- apr_int32_t nsds = 0;
- int nactive = 0;
- int bitmask;
-
- bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
-
- if (bitmask == 0)
- {
- return nsds > 0;
- }
-
- apr_status_t status;
- LLAPRPool pool;
- status = pool.getStatus() ;
- ll_apr_assert_status(status);
-
- for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
- {
- if (ARES_GETSOCK_READABLE(bitmask, i))
- {
- aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
- }
- else if (ARES_GETSOCK_WRITABLE(bitmask, i))
- {
- aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
- } else {
- continue;
- }
-
- apr_socket_t *aprSock = NULL;
-
- status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
- if (status != APR_SUCCESS)
- {
- ll_apr_warn_status(status);
- return nsds > 0;
- }
-
- aprFds[nactive].desc.s = aprSock;
- aprFds[nactive].desc_type = APR_POLL_SOCKET;
- aprFds[nactive].p = pool.getAPRPool();
- aprFds[nactive].rtnevents = 0;
- aprFds[nactive].client_data = &socks[i];
-
- nactive++;
- }
-
- if (nactive > 0)
- {
- status = apr_poll(aprFds, nactive, &nsds, timeout);
-
- if (status != APR_SUCCESS && status != APR_TIMEUP)
- {
- ll_apr_warn_status(status);
- }
-
- for (int i = 0; i < nactive; i++)
- {
- int evts = aprFds[i].rtnevents;
- int ifd = (evts & (APR_POLLIN | APR_POLLERR))
- ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
- int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
- ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
-
- ares_process_fd(chan_, ifd, ofd);
- }
- }
-
- return nsds > 0;
-}
-
-bool LLAres::processAll()
-{
- bool anyProcessed = false, ret;
-
- do {
- timeval tv;
-
- ret = ares_timeout(chan_, NULL, &tv) != NULL;
-
- if (ret)
- {
- ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
- anyProcessed |= ret;
- }
- } while (ret);
-
- return anyProcessed;
-}
-
-int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
- std::string &s, size_t &enclen)
-{
- char *t;
- int ret;
- long e;
-
- ret = ares_expand_name((const unsigned char *) encoded,
- (const unsigned char *) abuf, alen, &t, &e);
- if (ret == ARES_SUCCESS)
- {
- s.assign(t);
- enclen = e;
- ares_free_string(t);
- }
- return ret;
-}
-
-const char *LLAres::strerror(int code)
-{
- return ares_strerror(code);
-}
-
-LLAres *gAres;
-
-LLAres *ll_init_ares()
-{
- if (gAres == NULL)
- {
- gAres = new LLAres();
- }
- return gAres;
-}
-
-void ll_cleanup_ares()
-{
- if (gAres != NULL)
- {
- delete gAres;
- gAres = NULL;
- }
-}
-
-LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
- unsigned ttl)
- : LLRefCount(),
- mType(type),
- mName(name),
- mTTL(ttl)
-{
-}
-
-LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
- unsigned ttl)
- : LLDnsRecord(type, name, ttl)
-{
-}
-
-int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- ret = LLAres::expandName(pos, buf, len, mHost);
- if (ret != ARES_SUCCESS)
- {
- goto bail;
- }
-
- ret = ARES_SUCCESS;
-
-bail:
- return ret;
-}
-
-LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_CNAME, name, ttl)
-{
-}
-
-LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_PTR, name, ttl)
-{
-}
-
-LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
- unsigned ttl)
- : LLDnsRecord(type, name, ttl),
-
- mSize(0)
-{
-}
-
-LLARecord::LLARecord(const std::string &name, unsigned ttl)
- : LLAddrRecord(RES_A, name, ttl)
-{
-}
-
-int LLARecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
-
- memset(&mSA, 0, sizeof(mSA));
- memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
- mSA.sin.sin_family = AF_INET6;
- mSize = sizeof(mSA.sin);
-
- ret = ARES_SUCCESS;
-
-bail:
- return ret;
-}
-
-LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
- : LLAddrRecord(RES_AAAA, name, ttl)
-{
-}
-
-int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- if (rrlen != sizeof(mSA.sin6.sin6_addr))
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
-
- memset(&mSA, 0, sizeof(mSA));
- memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
- mSA.sin6.sin6_family = AF_INET6;
- mSize = sizeof(mSA.sin6);
-
- ret = ARES_SUCCESS;
-
-bail:
- return ret;
-}
-
-LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_SRV, name, ttl),
-
- mPriority(0),
- mWeight(0),
- mPort(0)
-{
-}
-
-int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
- size_t rrlen)
-{
- int ret;
-
- if (rrlen < 6)
- {
- ret = ARES_EBADRESP;
- goto bail;
- }
-
- memcpy(&mPriority, pos, 2);
- memcpy(&mWeight, pos + 2, 2);
- memcpy(&mPort, pos + 4, 2);
-
- mPriority = ntohs(mPriority);
- mWeight = ntohs(mWeight);
- mPort = ntohs(mPort);
-
- ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
-
-bail:
- return ret;
-}
-
-LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
- : LLHostRecord(RES_NS, name, ttl)
-{
-}
-
-void LLAres::UriRewriteResponder::queryError(int code)
-{
- std::vector<std::string> uris;
- uris.push_back(mUri.asString());
- rewriteResult(uris);
-}
-
-void LLAres::UriRewriteResponder::querySuccess()
-{
- std::vector<std::string> uris;
-
- if (mType != RES_SRV)
- {
- goto bail;
- }
-
- for (size_t i = 0; i < mAnswers.size(); i++)
- {
- const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
-
- if (r->type() == RES_SRV)
- {
- // Check the domain in the response to ensure that it's
- // the same as the domain in the request, so that bad guys
- // can't forge responses that point to their own login
- // servers with their own certificates.
-
- // Hard-coding the domain to check here is a bit of a
- // hack. Hoist it to an outer caller if anyone ever needs
- // this functionality on other domains.
-
- static const std::string domain(".lindenlab.com");
- const std::string &host = r->host();
-
- std::string::size_type s = host.find(domain) + domain.length();
-
- if (s != host.length() && s != host.length() - 1)
- {
- continue;
- }
-
- LLURI uri(mUri.scheme(),
- mUri.userName(),
- mUri.password(),
- r->host(),
- mUri.defaultPort() ? r->port() : mUri.hostPort(),
- mUri.escapedPath(),
- mUri.escapedQuery());
- uris.push_back(uri.asString());
- }
- }
-
- if (!uris.empty())
- {
- goto done;
- }
-
-bail:
- uris.push_back(mUri.asString());
-
-done:
- rewriteResult(uris);
-}
-
-void LLAres::UriRewriteResponder::rewriteResult(
- const std::vector<std::string> &uris)
-{
- LL_INFOS() << "LLAres::UriRewriteResponder::rewriteResult not implemented"
- << LL_ENDL;
-
- for (size_t i = 0; i < uris.size(); i++)
- {
- LL_INFOS() << "[" << i << "] " << uris[i] << LL_ENDL;
- }
-}
diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h
deleted file mode 100755
index c727363b60..0000000000
--- a/indra/llmessage/llares.h
+++ /dev/null
@@ -1,583 +0,0 @@
-/**
- * @file llares.h
- * @author Bryan O'Sullivan
- * @date 2007-08-15
- * @brief Wrapper for asynchronous DNS lookups.
- *
- * $LicenseInfo:firstyear=2007&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_LLARES_H
-#define LL_LLARES_H
-
-#ifdef LL_WINDOWS
-// ares.h is broken on windows in that it depends on types defined in ws2tcpip.h
-// we need to include them first to work around it, but the headers issue warnings
-# pragma warning(push)
-# pragma warning(disable:4996)
-# include <winsock2.h>
-# include <ws2tcpip.h>
-# pragma warning(pop)
-#endif
-
-#ifdef LL_USESYSTEMLIBS
-# include <ares.h>
-#else
-# include <ares/ares.h>
-#endif
-
-#include "llpointer.h"
-#include "llrefcount.h"
-#include "lluri.h"
-
-#include <boost/shared_ptr.hpp>
-
-class LLQueryResponder;
-class LLAresListener;
-
-/**
- * @brief Supported DNS RR types.
- */
-enum LLResType
-{
- RES_INVALID = 0, /**< Cookie. */
- RES_A = 1, /**< "A" record. IPv4 address. */
- RES_NS = 2, /**< "NS" record. Authoritative server. */
- RES_CNAME = 5, /**< "CNAME" record. Canonical name. */
- RES_PTR = 12, /**< "PTR" record. Domain name pointer. */
- RES_AAAA = 28, /**< "AAAA" record. IPv6 Address. */
- RES_SRV = 33, /**< "SRV" record. Server Selection. */
- RES_MAX = 65536 /**< Sentinel; RR types are 16 bits wide. */
-};
-
-/**
- * @class LLDnsRecord
- * @brief Base class for all DNS RR types.
- */
-class LLDnsRecord : public LLRefCount
-{
-protected:
- friend class LLQueryResponder;
-
- LLResType mType;
- std::string mName;
- unsigned mTTL;
-
- virtual int parse(const char *buf, size_t len, const char *pos,
- size_t rrlen) = 0;
-
- LLDnsRecord(LLResType type, const std::string &name, unsigned ttl);
-
-public:
- /**
- * @brief Record name.
- */
- const std::string &name() const { return mName; }
-
- /**
- * @brief Time-to-live value, in seconds.
- */
- unsigned ttl() const { return mTTL; }
-
- /**
- * @brief RR type.
- */
- LLResType type() const { return mType; }
-};
-
-/**
- * @class LLAddrRecord
- * @brief Base class for address-related RRs.
- */
-class LLAddrRecord : public LLDnsRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLAddrRecord(LLResType type, const std::string &name, unsigned ttl);
-
- union
- {
- sockaddr sa;
- sockaddr_in sin;
- sockaddr_in6 sin6;
- } mSA;
-
- socklen_t mSize;
-
-public:
- /**
- * @brief Generic socket address.
- */
- const sockaddr &addr() const { return mSA.sa; }
-
- /**
- * @brief Size of the socket structure.
- */
- socklen_t size() const { return mSize; }
-};
-
-/**
- * @class LLARecord
- * @brief A RR, for IPv4 addresses.
- */
-class LLARecord : public LLAddrRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLARecord(const std::string &name, unsigned ttl);
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
-public:
- /**
- * @brief Socket address.
- */
- const sockaddr_in &addr_in() const { return mSA.sin; }
-};
-
-/**
- * @class LLAaaaRecord
- * @brief AAAA RR, for IPv6 addresses.
- */
-class LLAaaaRecord : public LLAddrRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLAaaaRecord(const std::string &name, unsigned ttl);
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
-public:
- /**
- * @brief Socket address.
- */
- const sockaddr_in6 &addr_in6() const { return mSA.sin6; }
-};
-
-/**
- * @class LLHostRecord
- * @brief Base class for host-related RRs.
- */
-class LLHostRecord : public LLDnsRecord
-{
-protected:
- LLHostRecord(LLResType type, const std::string &name, unsigned ttl);
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
- std::string mHost;
-
-public:
- /**
- * @brief Host name.
- */
- const std::string &host() const { return mHost; }
-};
-
-/**
- * @class LLCnameRecord
- * @brief CNAME RR.
- */
-class LLCnameRecord : public LLHostRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLCnameRecord(const std::string &name, unsigned ttl);
-};
-
-/**
- * @class LLPtrRecord
- * @brief PTR RR.
- */
-class LLPtrRecord : public LLHostRecord
-{
-protected:
- friend class LLQueryResponder;
-
- LLPtrRecord(const std::string &name, unsigned ttl);
-};
-
-/**
- * @class LLSrvRecord
- * @brief SRV RR.
- */
-class LLSrvRecord : public LLHostRecord
-{
-protected:
- U16 mPriority;
- U16 mWeight;
- U16 mPort;
-
- int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
-
-public:
- LLSrvRecord(const std::string &name, unsigned ttl);
-
- /**
- * @brief Service priority.
- */
- U16 priority() const { return mPriority; }
-
- /**
- * @brief Service weight.
- */
- U16 weight() const { return mWeight; }
-
- /**
- * @brief Port number of service.
- */
- U16 port() const { return mPort; }
-
- /**
- * @brief Functor for sorting SRV records by priority.
- */
- struct ComparePriorityLowest
- {
- bool operator()(const LLSrvRecord& lhs, const LLSrvRecord& rhs)
- {
- return lhs.mPriority < rhs.mPriority;
- }
- };
-};
-
-/**
- * @class LLNsRecord
- * @brief NS RR.
- */
-class LLNsRecord : public LLHostRecord
-{
-public:
- LLNsRecord(const std::string &name, unsigned ttl);
-};
-
-class LLQueryResponder;
-
-/**
- * @class LLAres
- * @brief Asynchronous address resolver.
- */
-class LLAres
-{
-public:
- /**
- * @class HostResponder
- * @brief Base class for responding to hostname lookups.
- * @see LLAres::getHostByName
- */
- class HostResponder : public LLRefCount
- {
- public:
- virtual ~HostResponder();
-
- virtual void hostResult(const hostent *ent);
- virtual void hostError(int code);
- };
-
- /**
- * @class NameInfoResponder
- * @brief Base class for responding to address lookups.
- * @see LLAres::getNameInfo
- */
- class NameInfoResponder : public LLRefCount
- {
- public:
- virtual ~NameInfoResponder();
-
- virtual void nameInfoResult(const char *node, const char *service);
- virtual void nameInfoError(int code);
- };
-
- /**
- * @class QueryResponder
- * @brief Base class for responding to custom searches.
- * @see LLAres::search
- */
- class QueryResponder : public LLRefCount
- {
- public:
- virtual ~QueryResponder();
-
- virtual void queryResult(const char *buf, size_t len);
- virtual void queryError(int code);
- };
-
- class SrvResponder;
- class UriRewriteResponder;
-
- LLAres();
-
- ~LLAres();
-
- /**
- * Cancel all outstanding requests. The error methods of the
- * corresponding responders will be called, with ARES_ETIMEOUT.
- */
- void cancel();
-
- /**
- * Look up the address of a host.
- *
- * @param name name of host to look up
- * @param resp responder to call with result
- * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
- */
- void getHostByName(const std::string &name, HostResponder *resp,
- int family = AF_INET) {
- getHostByName(name.c_str(), resp, family);
- }
-
- /**
- * Look up the address of a host.
- *
- * @param name name of host to look up
- * @param resp responder to call with result
- * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
- */
- void getHostByName(const char *name, HostResponder *resp,
- int family = PF_INET);
-
- /**
- * Look up the name associated with a socket address.
- *
- * @param sa socket address to look up
- * @param salen size of socket address
- * @param flags flags to use
- * @param resp responder to call with result
- */
- void getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
- NameInfoResponder *resp);
-
- /**
- * Look up SRV (service location) records for a service name.
- *
- * @param name service name (e.g. "_https._tcp.login.agni.lindenlab.com")
- * @param resp responder to call with result
- */
- void getSrvRecords(const std::string &name, SrvResponder *resp);
-
- /**
- * Rewrite a URI, using SRV (service location) records for its
- * protocol if available. If no SRV records are published, the
- * existing URI is handed to the responder.
- *
- * @param uri URI to rewrite
- * @param resp responder to call with result
- */
- void rewriteURI(const std::string &uri,
- UriRewriteResponder *resp);
-
- /**
- * Start a custom search.
- *
- * @param query query to make
- * @param type type of query to perform
- * @param resp responder to call with result
- */
- void search(const std::string &query, LLResType type,
- QueryResponder *resp);
-
- /**
- * Process any outstanding queries. This method takes an optional
- * timeout parameter (specified in microseconds). If provided, it
- * will block the calling thread for that length of time to await
- * possible responses. A timeout of zero will return immediately
- * if there are no responses or timeouts to process.
- *
- * @param timeoutUsecs number of microseconds to block before timing out
- * @return whether any responses were processed
- */
- bool process(U64 timeoutUsecs = 0);
-
- /**
- * Process all outstanding queries, blocking the calling thread
- * until all have either been responded to or timed out.
- *
- * @return whether any responses were processed
- */
- bool processAll();
-
- /**
- * Expand a DNS-encoded compressed string into a normal string.
- *
- * @param encoded the encoded name (null-terminated)
- * @param abuf the response buffer in which the string is embedded
- * @param alen the length of the response buffer
- * @param s the string into which to place the result
- * @return ARES_SUCCESS on success, otherwise an error indicator
- */
- static int expandName(const char *encoded, const char *abuf, size_t alen,
- std::string &s) {
- size_t ignore;
- return expandName(encoded, abuf, alen, s, ignore);
- }
-
- static int expandName(const char *encoded, const char *abuf, size_t alen,
- std::string &s, size_t &enclen);
-
- /**
- * Return a string describing an error code.
- */
- static const char *strerror(int code);
-
- bool isInitialized(void) { return mInitSuccess; }
-
-protected:
- ares_channel chan_;
- bool mInitSuccess;
- // boost::scoped_ptr would actually fit the requirement better, but it
- // can't handle incomplete types as boost::shared_ptr can.
- boost::shared_ptr<LLAresListener> mListener;
-};
-
-/**
- * An ordered collection of DNS resource records.
- */
-typedef std::vector<LLPointer<LLDnsRecord> > dns_rrs_t;
-
-/**
- * @class LLQueryResponder
- * @brief Base class for friendly handling of DNS query responses.
- *
- * This class parses a DNS response and represents it in a friendly
- * manner.
- *
- * @see LLDnsRecord
- * @see LLARecord
- * @see LLNsRecord
- * @see LLCnameRecord
- * @see LLPtrRecord
- * @see LLAaaaRecord
- * @see LLSrvRecord
- */
-class LLQueryResponder : public LLAres::QueryResponder
-{
-protected:
- int mResult;
- std::string mQuery;
- LLResType mType;
-
- dns_rrs_t mAnswers;
- dns_rrs_t mAuthorities;
- dns_rrs_t mAdditional;
-
- /**
- * Parse a single RR.
- */
- int parseRR(const char *buf, size_t len, const char *&pos,
- LLPointer<LLDnsRecord> &r);
- /**
- * Parse one section of a response.
- */
- int parseSection(const char *buf, size_t len,
- size_t count, const char *& pos, dns_rrs_t &rrs);
-
- void queryResult(const char *buf, size_t len);
- virtual void querySuccess();
-
-public:
- LLQueryResponder();
-
- /**
- * Indicate whether the response could be parsed successfully.
- */
- bool valid() const { return mResult == ARES_SUCCESS; }
-
- /**
- * The more detailed result of parsing the response.
- */
- int result() const { return mResult; }
-
- /**
- * Return the query embedded in the response.
- */
- const std::string &query() const { return mQuery; }
-
- /**
- * Return the contents of the "answers" section of the response.
- */
- const dns_rrs_t &answers() const { return mAnswers; }
-
- /**
- * Return the contents of the "authorities" section of the
- * response.
- */
- const dns_rrs_t &authorities() const { return mAuthorities; }
-
- /**
- * Return the contents of the "additional records" section of the
- * response.
- */
- const dns_rrs_t &additional() const { return mAdditional; }
-};
-
-/**
- * @class LLAres::SrvResponder
- * @brief Class for handling SRV query responses.
- */
-class LLAres::SrvResponder : public LLQueryResponder
-{
-public:
- friend void LLAres::getSrvRecords(const std::string &name,
- SrvResponder *resp);
- void querySuccess();
- void queryError(int code);
-
- virtual void srvResult(const dns_rrs_t &ents);
- virtual void srvError(int code);
-};
-
-/**
- * @class LLAres::UriRewriteResponder
- * @brief Class for handling URI rewrites based on SRV records.
- */
-class LLAres::UriRewriteResponder : public LLQueryResponder
-{
-protected:
- LLURI mUri;
-
-public:
- friend void LLAres::rewriteURI(const std::string &uri,
- UriRewriteResponder *resp);
- void querySuccess();
- void queryError(int code);
-
- virtual void rewriteResult(const std::vector<std::string> &uris);
-};
-
-/**
- * Singleton responder.
- */
-extern LLAres *gAres;
-
-/**
- * Set up the singleton responder. It's safe to call this more than
- * once from within a single thread, but this function is not
- * thread safe.
- */
-extern LLAres *ll_init_ares();
-extern void ll_cleanup_ares();
-
-#endif // LL_LLARES_H
diff --git a/indra/llmessage/llareslistener.cpp b/indra/llmessage/llareslistener.cpp
deleted file mode 100755
index 3d65906b98..0000000000
--- a/indra/llmessage/llareslistener.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * @file llareslistener.cpp
- * @author Nat Goodspeed
- * @date 2009-03-18
- * @brief Implementation for llareslistener.
- *
- * $LicenseInfo:firstyear=2009&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$
- */
-
-// Precompiled header
-#include "linden_common.h"
-// associated header
-#include "llareslistener.h"
-// STL headers
-// std headers
-// external library headers
-// other Linden headers
-#include "llares.h"
-#include "llerror.h"
-#include "llevents.h"
-#include "llsdutil.h"
-
-LLAresListener::LLAresListener(LLAres* llares):
- LLEventAPI("LLAres",
- "LLAres listener to request DNS operations"),
- mAres(llares)
-{
- // add() every method we want to be able to invoke via this event API.
- // Optional last parameter validates expected LLSD request structure.
- add("rewriteURI",
- "Given [\"uri\"], return on [\"reply\"] an array of alternative URIs.\n"
- "On failure, returns an array containing only the original URI, so\n"
- "failure case can be processed like success case.",
- &LLAresListener::rewriteURI,
- LLSD().with("uri", LLSD()).with("reply", LLSD()));
-}
-
-/// This UriRewriteResponder subclass packages returned URIs as an LLSD
-/// array to send back to the requester.
-class UriRewriteResponder: public LLAres::UriRewriteResponder
-{
-public:
- /**
- * Specify the request, containing the event pump name on which to send
- * the reply.
- */
- UriRewriteResponder(const LLSD& request):
- mReqID(request),
- mPumpName(request["reply"])
- {}
-
- /// Called by base class with results. This is called in both the
- /// success and error cases. On error, the calling logic passes the
- /// original URI.
- virtual void rewriteResult(const std::vector<std::string>& uris)
- {
- LLSD result;
- for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
- ui != uend; ++ui)
- {
- result.append(*ui);
- }
- // This call knows enough to avoid trying to insert a map key into an
- // LLSD array. It's there so that if, for any reason, we ever decide
- // to change the response from array to map, it will Just Start Working.
- mReqID.stamp(result);
- LLEventPumps::instance().obtain(mPumpName).post(result);
- }
-
-private:
- LLReqID mReqID;
- const std::string mPumpName;
-};
-
-void LLAresListener::rewriteURI(const LLSD& data)
-{
- if (mAres)
- {
- mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
- }
- else
- {
- LL_INFOS() << "LLAresListener::rewriteURI requested without Ares present. Ignoring: " << data << LL_ENDL;
- }
-}
diff --git a/indra/llmessage/llareslistener.h b/indra/llmessage/llareslistener.h
deleted file mode 100755
index 780dcdd9c5..0000000000
--- a/indra/llmessage/llareslistener.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @file llareslistener.h
- * @author Nat Goodspeed
- * @date 2009-03-18
- * @brief LLEventPump API for LLAres. This header doesn't actually define the
- * API; the API is defined by the pump name on which this class
- * listens, and by the expected content of LLSD it receives.
- *
- * $LicenseInfo:firstyear=2009&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$
- */
-
-#if ! defined(LL_LLARESLISTENER_H)
-#define LL_LLARESLISTENER_H
-
-#include "lleventapi.h"
-
-class LLAres;
-class LLSD;
-
-/// Listen on an LLEventPump with specified name for LLAres request events.
-class LLAresListener: public LLEventAPI
-{
-public:
- /// Bind the LLAres instance to use (e.g. gAres)
- LLAresListener(LLAres* llares);
-
-private:
- /// command["op"] == "rewriteURI"
- void rewriteURI(const LLSD& data);
-
- LLAres* mAres;
-};
-
-#endif /* ! defined(LL_LLARESLISTENER_H) */
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 61663e1982..0d8aaf2269 100755
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -290,7 +290,7 @@ LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS
LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
LLVFS *vfs, LLVFS *static_vfs)
{
- _init(msg, xfer, vfs, static_vfs, LLHost::invalid);
+ _init(msg, xfer, vfs, static_vfs, LLHost());
}
@@ -1609,3 +1609,4 @@ void LLAssetStorage::markAssetToxic( const LLUUID& uuid )
}
}
+
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 1bb4acea9e..c3d31ba84c 100755
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -27,7 +27,6 @@
#ifndef LL_LLASSETSTORAGE_H
#define LL_LLASSETSTORAGE_H
-
#include <string>
#include "lluuid.h"
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 549708097a..61f18ed63e 100755
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -30,12 +30,20 @@
#include "llcachename.h" // we wrap this system
#include "llframetimer.h"
-#include "llhttpclient.h"
#include "llsd.h"
#include "llsdserialize.h"
-
+#include "httpresponse.h"
+#include "llhttpsdhandler.h"
#include <boost/tokenizer.hpp>
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
+
#include <map>
#include <set>
@@ -90,6 +98,12 @@ namespace LLAvatarNameCache
// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
+ LLCore::HttpRequest::ptr_t sHttpRequest;
+ LLCore::HttpHeaders::ptr_t sHttpHeaders;
+ LLCore::HttpOptions::ptr_t sHttpOptions;
+ LLCore::HttpRequest::policy_t sHttpPolicy;
+ LLCore::HttpRequest::priority_t sHttpPriority;
+
//-----------------------------------------------------------------------
// Internal methods
//-----------------------------------------------------------------------
@@ -121,7 +135,12 @@ namespace LLAvatarNameCache
// Erase expired names from cache
void eraseUnrefreshed();
- bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
+ bool expirationFromCacheControl(const LLSD& headers, F64 *expires);
+
+ // This is a coroutine.
+ void requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds);
+
+ void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult);
}
/* Sample response:
@@ -163,94 +182,117 @@ namespace LLAvatarNameCache
</llsd>
*/
-class LLAvatarNameResponder : public LLHTTPClient::Responder
+// Coroutine for sending and processing avatar name cache requests.
+// Do not call directly. See documentation in lleventcoro.h and llcoro.h for
+// further explanation.
+void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds)
{
- 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;
-
-public:
- LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids)
- : mAgentIDs(agent_ids)
- { }
-
-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(getResponseHeaders());
- F64 now = LLFrameTimer::getTotalSeconds();
+ LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::instance().getName()
+ << " with url '" << url << "', requesting " << agentIds.size() << " Agent Ids" << LL_ENDL;
- const LLSD& agents = content["agents"];
- LLSD::array_const_iterator it = agents.beginArray();
- for ( ; it != agents.endArray(); ++it)
- {
- const LLSD& row = *it;
- LLUUID agent_id = row["id"].asUUID();
+ try
+ {
+ bool success = true;
- LLAvatarName av_name;
- av_name.fromLLSD(row);
+ LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("NameCache", LLAvatarNameCache::sHttpPolicy);
+ LLSD results = httpAdapter.getAndSuspend(sHttpRequest, url);
+ LLSD httpResults;
- // Use expiration time from header
- av_name.mExpires = expires;
+ LL_DEBUGS() << results << LL_ENDL;
- LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL;
- av_name.dump();
-
- // cache it and fire signals
- LLAvatarNameCache::processName(agent_id, av_name);
- }
+ if (!results.isMap())
+ {
+ LL_WARNS("AvNameCache") << " Invalid result returned from LLCoreHttpUtil::HttpCoroHandler." << LL_ENDL;
+ success = false;
+ }
+ else
+ {
+ httpResults = results["http_result"];
+ success = httpResults["success"].asBoolean();
+ if (!success)
+ {
+ LL_WARNS("AvNameCache") << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL;
+ }
+ }
- // Same logic as error response case
- const LLSD& unresolved_agents = content["bad_ids"];
- S32 num_unresolved = unresolved_agents.size();
- if (num_unresolved > 0)
- {
- LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; "
- << "expires in " << expires - now << " seconds"
- << LL_ENDL;
- it = unresolved_agents.beginArray();
- for ( ; it != unresolved_agents.endArray(); ++it)
- {
- const LLUUID& agent_id = *it;
+ if (!success)
+ { // on any sort of failure add dummy records for any agent IDs
+ // in this request that we do not have cached already
+ std::vector<LLUUID>::const_iterator it = agentIds.begin();
+ for ( ; it != agentIds.end(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+ LLAvatarNameCache::handleAgentError(agent_id);
+ }
+ return;
+ }
- LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result "
- << "failed id " << agent_id
- << LL_ENDL;
+ LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults);
- LLAvatarNameCache::handleAgentError(agent_id);
- }
- }
- LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "
- << LLAvatarNameCache::sCache.size() << " cached names"
- << LL_ENDL;
}
+ catch (std::exception e)
+ {
+ LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+ }
+}
- /*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") << 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();
- for ( ; it != mAgentIDs.end(); ++it)
- {
- const LLUUID& agent_id = *it;
- LLAvatarNameCache::handleAgentError(agent_id);
- }
- }
-};
+void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult)
+{
+
+ LLSD headers = httpResult["headers"];
+ // Pull expiration out of headers if available
+ F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(headers);
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ const LLSD& agents = data["agents"];
+ LLSD::array_const_iterator it = agents.beginArray();
+ for (; it != agents.endArray(); ++it)
+ {
+ const LLSD& row = *it;
+ LLUUID agent_id = row["id"].asUUID();
+
+ LLAvatarName av_name;
+ av_name.fromLLSD(row);
+
+ // Use expiration time from header
+ av_name.mExpires = expires;
+
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL;
+ av_name.dump();
+
+ // cache it and fire signals
+ LLAvatarNameCache::processName(agent_id, av_name);
+ }
+
+ // Same logic as error response case
+ const LLSD& unresolved_agents = data["bad_ids"];
+ S32 num_unresolved = unresolved_agents.size();
+ if (num_unresolved > 0)
+ {
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; "
+ << "expires in " << expires - now << " seconds"
+ << LL_ENDL;
+ it = unresolved_agents.beginArray();
+ for (; it != unresolved_agents.endArray(); ++it)
+ {
+ const LLUUID& agent_id = *it;
+
+ LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result "
+ << "failed id " << agent_id
+ << LL_ENDL;
+
+ LLAvatarNameCache::handleAgentError(agent_id);
+ }
+ }
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "
+ << LLAvatarNameCache::sCache.size() << " cached names"
+ << LL_ENDL;
+}
// Provide some fallback for agents that return errors
void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
@@ -353,10 +395,15 @@ void LLAvatarNameCache::requestNamesViaCapability()
}
}
- if (!url.empty())
- {
- LL_INFOS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability getting " << ids << " ids" << LL_ENDL;
- LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
+ if (!url.empty())
+ {
+ LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " << ids << " ids" << LL_ENDL;
+
+ std::string coroname =
+ LLCoros::instance().launch("LLAvatarNameCache::requestAvatarNameCache_",
+ boost::bind(&LLAvatarNameCache::requestAvatarNameCache_, url, agent_ids));
+ LL_DEBUGS("AvNameCache") << coroname << " with url '" << url << "', agent_ids.size()=" << agent_ids.size() << LL_ENDL;
+
}
}
@@ -419,11 +466,20 @@ void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI)
{
sRunning = running;
sUsePeopleAPI = usePeopleAPI;
+
+ sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
+ sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
+ sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
+ sHttpPriority = 0;
}
void LLAvatarNameCache::cleanupClass()
{
- sCache.clear();
+ sHttpRequest.reset();
+ sHttpHeaders.reset();
+ sHttpOptions.reset();
+ sCache.clear();
}
bool LLAvatarNameCache::importFile(std::istream& istr)
@@ -698,6 +754,50 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
sCache[agent_id] = av_name;
}
+#if 0
+F64 LLAvatarNameCache::nameExpirationFromHeaders(LLCore::HttpHeaders *headers)
+{
+ F64 expires = 0.0;
+ if (expirationFromCacheControl(headers, &expires))
+ {
+ return expires;
+ }
+ else
+ {
+ // With no expiration info, default to an hour
+ const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
+ F64 now = LLFrameTimer::getTotalSeconds();
+ return now + DEFAULT_EXPIRES;
+ }
+}
+
+bool LLAvatarNameCache::expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires)
+{
+ bool fromCacheControl = false;
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ // Allow the header to override the default
+ const std::string *cache_control;
+
+ cache_control = headers->find(HTTP_IN_HEADER_CACHE_CONTROL);
+
+ if (cache_control && !cache_control->empty())
+ {
+ S32 max_age = 0;
+ if (max_age_from_cache_control(*cache_control, &max_age))
+ {
+ *expires = now + (F64)max_age;
+ fromCacheControl = true;
+ }
+ }
+ LL_DEBUGS("AvNameCache")
+ << ( fromCacheControl ? "expires based on cache control " : "default expiration " )
+ << "in " << *expires - now << " seconds"
+ << LL_ENDL;
+
+ return fromCacheControl;
+}
+#else
F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)
{
F64 expires = 0.0;
@@ -742,7 +842,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *exp
return fromCacheControl;
}
-
+#endif
void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)
{
diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h
index 5a10053a69..bd2715e956 100755
--- a/indra/llmessage/llavatarnamecache.h
+++ b/indra/llmessage/llavatarnamecache.h
@@ -29,7 +29,6 @@
#define LLAVATARNAMECACHE_H
#include "llavatarname.h" // for convenience
-
#include <boost/signals2.hpp>
class LLSD;
@@ -49,7 +48,7 @@ namespace LLAvatarNameCache
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
- // On the viewer, usually a simulator capabilitity.
+ // On the viewer, usually a simulator capabilities.
// If empty, name cache will fall back to using legacy name lookup system.
void setNameLookupURL(const std::string& name_lookup_url);
@@ -90,7 +89,7 @@ namespace LLAvatarNameCache
// Compute name expiration time from HTTP Cache-Control header,
// or return default value, in seconds from epoch.
- F64 nameExpirationFromHeaders(const LLSD& headers);
+ F64 nameExpirationFromHeaders(const LLSD& headers);
void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);
}
diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp
index daf3e0b4de..66bd85f4e6 100755
--- a/indra/llmessage/llcachename.cpp
+++ b/indra/llmessage/llcachename.cpp
@@ -259,7 +259,7 @@ LLCacheName::~LLCacheName()
}
LLCacheName::Impl::Impl(LLMessageSystem* msg)
- : mMsg(msg), mUpstreamHost(LLHost::invalid)
+ : mMsg(msg), mUpstreamHost(LLHost())
{
mMsg->setHandlerFuncFast(
_PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this);
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
new file mode 100644
index 0000000000..f0fe1ab01b
--- /dev/null
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -0,0 +1,405 @@
+/**
+* @file LLCoprocedurePool.cpp
+* @author Rider Linden
+* @brief Singleton class for managing asset uploads to the sim.
+*
+* $LicenseInfo:firstyear=2015&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2015, 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 "llcoproceduremanager.h"
+#include <boost/assign.hpp>
+
+//=========================================================================
+// Map of pool sizes for known pools
+// *TODO$: When C++11 this can be initialized here as follows:
+// = {{"AIS", 25}, {"Upload", 1}}
+static std::map<std::string, U32> DefaultPoolSizes =
+ boost::assign::map_list_of
+ (std::string("Upload"), 1)
+ (std::string("AIS"), 25);
+
+#define DEFAULT_POOL_SIZE 5
+
+//=========================================================================
+class LLCoprocedurePool: private boost::noncopyable
+{
+public:
+ typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t;
+
+ LLCoprocedurePool(const std::string &name, size_t size);
+ virtual ~LLCoprocedurePool();
+
+ /// Places the coprocedure on the queue for processing.
+ ///
+ /// @param name Is used for debugging and should identify this coroutine.
+ /// @param proc Is a bound function to be executed
+ ///
+ /// @return This method returns a UUID that can be used later to cancel execution.
+ LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc);
+
+ /// Cancel a coprocedure. If the coprocedure is already being actively executed
+ /// this method calls cancelSuspendedOperation() on the associated HttpAdapter
+ /// If it has not yet been dequeued it is simply removed from the queue.
+ bool cancelCoprocedure(const LLUUID &id);
+
+ /// Requests a shutdown of the upload manager. Passing 'true' will perform
+ /// an immediate kill on the upload coroutine.
+ void shutdown(bool hardShutdown = false);
+
+ /// Returns the number of coprocedures in the queue awaiting processing.
+ ///
+ inline size_t countPending() const
+ {
+ return mPendingCoprocs.size();
+ }
+
+ /// Returns the number of coprocedures actively being processed.
+ ///
+ inline size_t countActive() const
+ {
+ return mActiveCoprocs.size();
+ }
+
+ /// Returns the total number of coprocedures either queued or in active processing.
+ ///
+ inline size_t count() const
+ {
+ return countPending() + countActive();
+ }
+
+private:
+ struct QueuedCoproc
+ {
+ typedef boost::shared_ptr<QueuedCoproc> ptr_t;
+
+ QueuedCoproc(const std::string &name, const LLUUID &id, CoProcedure_t proc) :
+ mName(name),
+ mId(id),
+ mProc(proc)
+ {}
+
+ std::string mName;
+ LLUUID mId;
+ CoProcedure_t mProc;
+ };
+
+ // we use a deque here rather than std::queue since we want to be able to
+ // iterate through the queue and potentially erase an entry from the middle.
+ typedef std::deque<QueuedCoproc::ptr_t> CoprocQueue_t;
+ typedef std::map<LLUUID, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> ActiveCoproc_t;
+
+ std::string mPoolName;
+ size_t mPoolSize;
+ CoprocQueue_t mPendingCoprocs;
+ ActiveCoproc_t mActiveCoprocs;
+ bool mShutdown;
+ LLEventStream mWakeupTrigger;
+
+ typedef std::map<std::string, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> CoroAdapterMap_t;
+ LLCore::HttpRequest::policy_t mHTTPPolicy;
+
+ CoroAdapterMap_t mCoroMapping;
+
+ void coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter);
+
+};
+
+//=========================================================================
+LLCoprocedureManager::LLCoprocedureManager()
+{
+}
+
+LLCoprocedureManager::~LLCoprocedureManager()
+{
+
+}
+
+LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::string &poolName)
+{
+ // Attempt to look up a pool size in the configuration. If found use that
+ std::string keyName = "PoolSize" + poolName;
+ int size = 0;
+
+ if (poolName.empty())
+ LL_ERRS("CoprocedureManager") << "Poolname must not be empty" << LL_ENDL;
+
+ if (mPropertyQueryFn && !mPropertyQueryFn.empty())
+ {
+ size = mPropertyQueryFn(keyName);
+ }
+
+ if (size == 0)
+ { // if not found grab the know default... if there is no known
+ // default use a reasonable number like 5.
+ std::map<std::string, U32>::iterator it = DefaultPoolSizes.find(poolName);
+ if (it == DefaultPoolSizes.end())
+ size = DEFAULT_POOL_SIZE;
+ else
+ size = (*it).second;
+
+ if (mPropertyDefineFn && !mPropertyDefineFn.empty())
+ mPropertyDefineFn(keyName, size, "Coroutine Pool size for " + poolName);
+ LL_WARNS() << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL;
+ }
+
+ poolPtr_t pool(new LLCoprocedurePool(poolName, size));
+ mPoolMap.insert(poolMap_t::value_type(poolName, pool));
+
+ if (!pool)
+ LL_ERRS("CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL;
+ return pool;
+}
+
+//-------------------------------------------------------------------------
+LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc)
+{
+ // Attempt to find the pool and enqueue the procedure. If the pool does
+ // not exist, create it.
+ poolPtr_t targetPool;
+ poolMap_t::iterator it = mPoolMap.find(pool);
+
+ if (it == mPoolMap.end())
+ {
+ targetPool = initializePool(pool);
+ }
+ else
+ {
+ targetPool = (*it).second;
+ }
+
+ return targetPool->enqueueCoprocedure(name, proc);
+}
+
+void LLCoprocedureManager::cancelCoprocedure(const LLUUID &id)
+{
+ for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it)
+ {
+ if ((*it).second->cancelCoprocedure(id))
+ return;
+ }
+ LL_INFOS() << "Coprocedure not found." << LL_ENDL;
+}
+
+void LLCoprocedureManager::shutdown(bool hardShutdown)
+{
+ for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it)
+ {
+ (*it).second->shutdown(hardShutdown);
+ }
+ mPoolMap.clear();
+}
+
+void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn)
+{
+ mPropertyQueryFn = queryfn;
+ mPropertyDefineFn = updatefn;
+}
+
+//-------------------------------------------------------------------------
+size_t LLCoprocedureManager::countPending() const
+{
+ size_t count = 0;
+ for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it)
+ {
+ count += (*it).second->countPending();
+ }
+ return count;
+}
+
+size_t LLCoprocedureManager::countPending(const std::string &pool) const
+{
+ poolMap_t::const_iterator it = mPoolMap.find(pool);
+
+ if (it == mPoolMap.end())
+ return 0;
+ return (*it).second->countPending();
+}
+
+size_t LLCoprocedureManager::countActive() const
+{
+ size_t count = 0;
+ for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it)
+ {
+ count += (*it).second->countActive();
+ }
+ return count;
+}
+
+size_t LLCoprocedureManager::countActive(const std::string &pool) const
+{
+ poolMap_t::const_iterator it = mPoolMap.find(pool);
+
+ if (it == mPoolMap.end())
+ return 0;
+ return (*it).second->countActive();
+}
+
+size_t LLCoprocedureManager::count() const
+{
+ size_t count = 0;
+ for (poolMap_t::const_iterator it = mPoolMap.begin(); it != mPoolMap.end(); ++it)
+ {
+ count += (*it).second->count();
+ }
+ return count;
+}
+
+size_t LLCoprocedureManager::count(const std::string &pool) const
+{
+ poolMap_t::const_iterator it = mPoolMap.find(pool);
+
+ if (it == mPoolMap.end())
+ return 0;
+ return (*it).second->count();
+}
+
+//=========================================================================
+LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
+ mPoolName(poolName),
+ mPoolSize(size),
+ mPendingCoprocs(),
+ mShutdown(false),
+ mWakeupTrigger("CoprocedurePool" + poolName, true),
+ mCoroMapping(),
+ mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID)
+{
+ for (size_t count = 0; count < mPoolSize; ++count)
+ {
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter( mPoolName + "Adapter", mHTTPPolicy));
+
+ std::string pooledCoro = LLCoros::instance().launch("LLCoprocedurePool("+mPoolName+")::coprocedureInvokerCoro",
+ boost::bind(&LLCoprocedurePool::coprocedureInvokerCoro, this, httpAdapter));
+
+ mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter));
+ }
+
+ LL_INFOS() << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items." << LL_ENDL;
+
+ mWakeupTrigger.post(LLSD());
+}
+
+LLCoprocedurePool::~LLCoprocedurePool()
+{
+ shutdown();
+}
+
+//-------------------------------------------------------------------------
+void LLCoprocedurePool::shutdown(bool hardShutdown)
+{
+ CoroAdapterMap_t::iterator it;
+
+ for (it = mCoroMapping.begin(); it != mCoroMapping.end(); ++it)
+ {
+ if (hardShutdown)
+ {
+ LLCoros::instance().kill((*it).first);
+ }
+ if ((*it).second)
+ {
+ (*it).second->cancelSuspendedOperation();
+ }
+ }
+
+ mShutdown = true;
+ mCoroMapping.clear();
+ mPendingCoprocs.clear();
+}
+
+//-------------------------------------------------------------------------
+LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoprocedurePool::CoProcedure_t proc)
+{
+ LLUUID id(LLUUID::generateNewID());
+
+ mPendingCoprocs.push_back(QueuedCoproc::ptr_t(new QueuedCoproc(name, id, proc)));
+ LL_INFOS() << "Coprocedure(" << name << ") enqueued with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+
+ mWakeupTrigger.post(LLSD());
+
+ return id;
+}
+
+bool LLCoprocedurePool::cancelCoprocedure(const LLUUID &id)
+{
+ // first check the active coroutines. If there, remove it and return.
+ ActiveCoproc_t::iterator itActive = mActiveCoprocs.find(id);
+ if (itActive != mActiveCoprocs.end())
+ {
+ LL_INFOS() << "Found and canceling active coprocedure with id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+ (*itActive).second->cancelSuspendedOperation();
+ mActiveCoprocs.erase(itActive);
+ return true;
+ }
+
+ for (CoprocQueue_t::iterator it = mPendingCoprocs.begin(); it != mPendingCoprocs.end(); ++it)
+ {
+ if ((*it)->mId == id)
+ {
+ LL_INFOS() << "Found and removing queued coroutine(" << (*it)->mName << ") with Id=" << id.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+ mPendingCoprocs.erase(it);
+ return true;
+ }
+ }
+
+ LL_INFOS() << "Coprocedure with Id=" << id.asString() << " was not found in pool \"" << mPoolName << "\"" << LL_ENDL;
+ return false;
+}
+
+//-------------------------------------------------------------------------
+void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ while (!mShutdown)
+ {
+ llcoro::suspendUntilEventOn(mWakeupTrigger);
+ if (mShutdown)
+ break;
+
+ while (!mPendingCoprocs.empty())
+ {
+ QueuedCoproc::ptr_t coproc = mPendingCoprocs.front();
+ mPendingCoprocs.pop_front();
+ ActiveCoproc_t::iterator itActive = mActiveCoprocs.insert(ActiveCoproc_t::value_type(coproc->mId, httpAdapter)).first;
+
+ LL_INFOS() << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+
+ try
+ {
+ coproc->mProc(httpAdapter, coproc->mId);
+ }
+ catch (std::exception &e)
+ {
+ LL_WARNS() << "Coprocedure(" << coproc->mName << ") id=" << coproc->mId.asString() <<
+ " threw an exception! Message=\"" << e.what() << "\"" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS() << "A non std::exception was thrown from " << coproc->mName << " with id=" << coproc->mId << "." << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+ }
+
+ LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+
+ mActiveCoprocs.erase(itActive);
+ }
+ }
+}
diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h
new file mode 100644
index 0000000000..497367b80c
--- /dev/null
+++ b/indra/llmessage/llcoproceduremanager.h
@@ -0,0 +1,98 @@
+/**
+* @file llcoproceduremanager.h
+* @author Rider Linden
+* @brief Singleton class for managing asset uploads to the sim.
+*
+* $LicenseInfo:firstyear=2015&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2015, 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_COPROCEDURE_MANAGER_H
+#define LL_COPROCEDURE_MANAGER_H
+
+#include "lleventcoro.h"
+#include "llcoros.h"
+#include "llcorehttputil.h"
+#include "lluuid.h"
+
+class LLCoprocedurePool;
+
+class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
+{
+ friend class LLSingleton < LLCoprocedureManager > ;
+
+public:
+ typedef boost::function<U32(const std::string &)> SettingQuery_t;
+ typedef boost::function<void(const std::string &, U32, const std::string &)> SettingUpdate_t;
+
+ typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t;
+
+ LLCoprocedureManager();
+ virtual ~LLCoprocedureManager();
+
+ /// Places the coprocedure on the queue for processing.
+ ///
+ /// @param name Is used for debugging and should identify this coroutine.
+ /// @param proc Is a bound function to be executed
+ ///
+ /// @return This method returns a UUID that can be used later to cancel execution.
+ LLUUID enqueueCoprocedure(const std::string &pool, const std::string &name, CoProcedure_t proc);
+
+ /// Cancel a coprocedure. If the coprocedure is already being actively executed
+ /// this method calls cancelYieldingOperation() on the associated HttpAdapter
+ /// If it has not yet been dequeued it is simply removed from the queue.
+ void cancelCoprocedure(const LLUUID &id);
+
+ /// Requests a shutdown of the upload manager. Passing 'true' will perform
+ /// an immediate kill on the upload coroutine.
+ void shutdown(bool hardShutdown = false);
+
+ void setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn);
+
+ /// Returns the number of coprocedures in the queue awaiting processing.
+ ///
+ size_t countPending() const;
+ size_t countPending(const std::string &pool) const;
+
+ /// Returns the number of coprocedures actively being processed.
+ ///
+ size_t countActive() const;
+ size_t countActive(const std::string &pool) const;
+
+ /// Returns the total number of coprocedures either queued or in active processing.
+ ///
+ size_t count() const;
+ size_t count(const std::string &pool) const;
+
+private:
+
+ typedef boost::shared_ptr<LLCoprocedurePool> poolPtr_t;
+ typedef std::map<std::string, poolPtr_t> poolMap_t;
+
+ poolMap_t mPoolMap;
+
+ poolPtr_t initializePool(const std::string &poolName);
+
+ SettingQuery_t mPropertyQueryFn;
+ SettingUpdate_t mPropertyDefineFn;
+};
+
+#endif
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index ee80b0fd94..d964ff7100 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -28,10 +28,18 @@
#include "linden_common.h"
#include <sstream>
-
+#include <algorithm>
+#include <iterator>
#include "llcorehttputil.h"
+#include "llhttpconstants.h"
+#include "llsd.h"
+#include "llsdjson.h"
#include "llsdserialize.h"
+#include "reader.h" // JSON
+#include "writer.h" // JSON
+#include "llvfile.h"
+#include "message.h" // for getting the port
using namespace LLCore;
@@ -39,101 +47,1178 @@ using namespace LLCore;
namespace LLCoreHttpUtil
{
+const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+
+
+void logMessageSuccess(std::string logAuth, std::string url, std::string message)
+{
+ LL_INFOS() << logAuth << " Success '" << message << "' for " << url << LL_ENDL;
+}
+
+void logMessageFail(std::string logAuth, std::string url, std::string message)
+{
+ LL_WARNS() << logAuth << " Failure '" << message << "' for " << url << LL_ENDL;
+}
+
+//=========================================================================
+/// The HttpRequestPumper is a utility class. When constructed it will poll the
+/// supplied HttpRequest once per frame until it is destroyed.
+///
+class HttpRequestPumper
+{
+public:
+ HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request);
+ ~HttpRequestPumper();
+
+private:
+ bool pollRequest(const LLSD&);
+
+ LLTempBoundListener mBoundListener;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+};
+
+
+//=========================================================================
// *TODO: Currently converts only from XML content. A mode
// to convert using fromBinary() might be useful as well. Mesh
// headers could use it.
bool responseToLLSD(HttpResponse * response, bool log, LLSD & out_llsd)
{
- // Convert response to LLSD
- BufferArray * body(response->getBody());
- if (! body || ! body->size())
- {
- return false;
- }
+ // Convert response to LLSD
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return false;
+ }
- LLCore::BufferArrayStream bas(body);
- LLSD body_llsd;
- S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log));
- if (LLSDParser::PARSE_FAILURE == parse_status){
- return false;
- }
- out_llsd = body_llsd;
- return true;
+ LLCore::BufferArrayStream bas(body);
+ LLSD body_llsd;
+ S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log));
+ if (LLSDParser::PARSE_FAILURE == parse_status){
+ return false;
+ }
+ out_llsd = body_llsd;
+ return true;
}
HttpHandle requestPostWithLLSD(HttpRequest * request,
- HttpRequest::policy_t policy_id,
- HttpRequest::priority_t priority,
- const std::string & url,
- const LLSD & body,
- HttpOptions * options,
- HttpHeaders * headers,
- HttpHandler * handler)
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const HttpOptions::ptr_t &options,
+ const HttpHeaders::ptr_t &headers,
+ HttpHandler * handler)
+{
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ BufferArray * ba = new BufferArray();
+ BufferArrayStream bas(ba);
+ LLSDSerialize::toXML(body, bas);
+
+ handle = request->requestPost(policy_id,
+ priority,
+ url,
+ ba,
+ options,
+ headers,
+ handler);
+ ba->release();
+ return handle;
+}
+
+
+HttpHandle requestPutWithLLSD(HttpRequest * request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const HttpOptions::ptr_t &options,
+ const HttpHeaders::ptr_t &headers,
+ HttpHandler * handler)
+{
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+ BufferArray * ba = new BufferArray();
+ BufferArrayStream bas(ba);
+ LLSDSerialize::toXML(body, bas);
+
+ handle = request->requestPut(policy_id,
+ priority,
+ url,
+ ba,
+ options,
+ headers,
+ handler);
+ ba->release();
+ return handle;
+}
+
+HttpHandle requestPatchWithLLSD(HttpRequest * request,
+ HttpRequest::policy_t policy_id,
+ HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const HttpOptions::ptr_t &options,
+ const HttpHeaders::ptr_t &headers,
+ HttpHandler * handler)
{
- HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+ HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- BufferArray * ba = new BufferArray();
- BufferArrayStream bas(ba);
- LLSDSerialize::toXML(body, bas);
+ BufferArray * ba = new BufferArray();
+ BufferArrayStream bas(ba);
+ LLSDSerialize::toXML(body, bas);
- handle = request->requestPost(policy_id,
- priority,
- url,
- ba,
- options,
- headers,
- handler);
- ba->release();
- return handle;
+ handle = request->requestPatch(policy_id,
+ priority,
+ url,
+ ba,
+ options,
+ headers,
+ handler);
+ ba->release();
+ return handle;
}
std::string responseToString(LLCore::HttpResponse * response)
{
- static const std::string empty("[Empty]");
-
- if (! response)
- {
- return empty;
- }
-
- BufferArray * body(response->getBody());
- if (! body || ! body->size())
- {
- return empty;
- }
-
- // Attempt to parse as LLSD regardless of content-type
- LLSD body_llsd;
- if (responseToLLSD(response, false, body_llsd))
- {
- std::ostringstream tmp;
-
- LLSDSerialize::toPrettyNotation(body_llsd, tmp);
- std::size_t temp_len(tmp.tellp());
-
- if (temp_len)
- {
- return tmp.str().substr(0, std::min(temp_len, std::size_t(1024)));
- }
- }
- else
- {
- // *TODO: More elaborate forms based on Content-Type as needed.
- char content[1024];
-
- size_t len(body->read(0, content, sizeof(content)));
- if (len)
- {
- return std::string(content, 0, len);
- }
- }
-
- // Default
- return empty;
+ static const std::string empty("[Empty]");
+
+ if (!response)
+ {
+ return empty;
+ }
+
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return empty;
+ }
+
+ // Attempt to parse as LLSD regardless of content-type
+ LLSD body_llsd;
+ if (responseToLLSD(response, false, body_llsd))
+ {
+ std::ostringstream tmp;
+
+ LLSDSerialize::toPrettyNotation(body_llsd, tmp);
+ std::size_t temp_len(tmp.tellp());
+
+ if (temp_len)
+ {
+ return tmp.str().substr(0, std::min(temp_len, std::size_t(1024)));
+ }
+ }
+ else
+ {
+ // *TODO: More elaborate forms based on Content-Type as needed.
+ char content[1024];
+
+ size_t len(body->read(0, content, sizeof(content)));
+ if (len)
+ {
+ return std::string(content, 0, len);
+ }
+ }
+
+ // Default
+ return empty;
+}
+
+//========================================================================
+
+HttpCoroHandler::HttpCoroHandler(LLEventStream &reply) :
+ mReplyPump(reply)
+{
+}
+
+void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+ LLSD result;
+
+ LLCore::HttpStatus status = response->getStatus();
+
+ if (status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_HANDLE_NOT_FOUND))
+ { // A response came in for a canceled request and we have not processed the
+ // cancel yet. Patience!
+ return;
+ }
+
+ if (!status)
+ {
+ result = LLSD::emptyMap();
+ LL_WARNS()
+ << "\n--------------------------------------------------------------------------\n"
+ << " Error[" << status.getType() << "] cannot access url '" << response->getRequestURL()
+ << "' because " << status.toString()
+ << "\n--------------------------------------------------------------------------"
+ << LL_ENDL;
+ }
+ else
+ {
+ result = this->handleSuccess(response, status);
+ }
+
+ buildStatusEntry(response, status, result);
+
+#if 1
+ // commenting out, but keeping since this can be useful for debugging
+ if (!status)
+ {
+ LLSD &httpStatus = result[HttpCoroutineAdapter::HTTP_RESULTS];
+
+ LLCore::BufferArray *body = response->getBody();
+ LLCore::BufferArrayStream bas(body);
+ LLSD::String bodyData;
+ bodyData.reserve(response->getBodySize());
+ bas >> std::noskipws;
+ bodyData.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>());
+ httpStatus["error_body"] = LLSD(bodyData);
+
+ LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL;
+ }
+#endif
+
+ mReplyPump.post(result);
+}
+
+void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result)
+{
+ LLSD httpresults = LLSD::emptyMap();
+
+ writeStatusCodes(status, response->getRequestURL(), httpresults);
+
+ LLSD httpHeaders = LLSD::emptyMap();
+ LLCore::HttpHeaders::ptr_t hdrs = response->getHeaders();
+
+ if (hdrs)
+ {
+ for (LLCore::HttpHeaders::iterator it = hdrs->begin(); it != hdrs->end(); ++it)
+ {
+ if (!(*it).second.empty())
+ {
+ httpHeaders[(*it).first] = (*it).second;
+ }
+ else
+ {
+ httpHeaders[(*it).first] = static_cast<LLSD::Boolean>(true);
+ }
+ }
+ }
+
+ httpresults[HttpCoroutineAdapter::HTTP_RESULTS_HEADERS] = httpHeaders;
+ result[HttpCoroutineAdapter::HTTP_RESULTS] = httpresults;
+}
+
+void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result)
+{
+ result[HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS] = static_cast<LLSD::Boolean>(status);
+ result[HttpCoroutineAdapter::HTTP_RESULTS_TYPE] = static_cast<LLSD::Integer>(status.getType());
+ result[HttpCoroutineAdapter::HTTP_RESULTS_STATUS] = static_cast<LLSD::Integer>(status.getStatus());
+ result[HttpCoroutineAdapter::HTTP_RESULTS_MESSAGE] = static_cast<LLSD::String>(status.getMessage());
+ result[HttpCoroutineAdapter::HTTP_RESULTS_URL] = static_cast<LLSD::String>(url);
+
+}
+
+//=========================================================================
+/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for
+/// interacting with coroutines. When the request is completed the response
+/// will be posted onto the supplied Event Pump.
+///
+/// If the LLSD retrieved from through the HTTP connection is not in the form
+/// of a LLSD::map it will be returned as in an llsd["content"] element.
+///
+/// The LLSD posted back to the coroutine will have the following additions:
+/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status
+/// +- ["status"] - The status code associated with the HTTP call
+/// +- ["success"] - Success of failure of the HTTP call and LLSD parsing.
+/// +- ["type"] - The LLCore::HttpStatus type associted with the HTTP call
+/// +- ["url"] - The URL used to make the call.
+/// +- ["headers"] - A map of name name value pairs with the HTTP headers.
+///
+class HttpCoroLLSDHandler : public HttpCoroHandler
+{
+public:
+ HttpCoroLLSDHandler(LLEventStream &reply);
+
+protected:
+ virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status);
+};
+
+//-------------------------------------------------------------------------
+HttpCoroLLSDHandler::HttpCoroLLSDHandler(LLEventStream &reply):
+ HttpCoroHandler(reply)
+{
+}
+
+
+LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status)
+{
+ LLSD result;
+
+ const bool emit_parse_errors = false;
+
+ bool parsed = !((response->getBodySize() == 0) ||
+ !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result));
+
+ if (!parsed)
+ {
+ // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
+ LLCore::HttpHeaders::ptr_t headers(response->getHeaders());
+ const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL;
+
+ if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
+ {
+ std::string thebody = LLCoreHttpUtil::responseToString(response);
+ LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
+ << " body: " << thebody << LL_ENDL;
+
+ // Replace the status with a new one indicating the failure.
+ status = LLCore::HttpStatus(499, "Failed to deserialize LLSD.");
+ }
+ }
+
+ if (result.isUndefined())
+ { // If we've gotten to this point and the result LLSD is still undefined
+ // either there was an issue deserializing the body or the response was
+ // blank. Create an empty map to hold the result either way.
+ result = LLSD::emptyMap();
+ }
+ else if (!result.isMap())
+ { // The results are not themselves a map. Move them down so that
+ // this method can return a map to the caller.
+ // *TODO: Should it always do this?
+ LLSD newResult = LLSD::emptyMap();
+ newResult[HttpCoroutineAdapter::HTTP_RESULTS_CONTENT] = result;
+ result = newResult;
+ }
+
+ return result;
+}
+
+//========================================================================
+/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for
+/// interacting with coroutines.
+///
+/// In addition to the normal "http_results" the returned LLSD will contain
+/// an entry keyed with "raw" containing the unprocessed results of the HTTP
+/// call.
+///
+class HttpCoroRawHandler : public HttpCoroHandler
+{
+public:
+ HttpCoroRawHandler(LLEventStream &reply);
+
+ virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status);
+};
+
+//-------------------------------------------------------------------------
+HttpCoroRawHandler::HttpCoroRawHandler(LLEventStream &reply):
+ HttpCoroHandler(reply)
+{
+}
+
+LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status)
+{
+ LLSD result = LLSD::emptyMap();
+
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return result;
+ }
+
+ size_t size = body->size();
+
+ LLCore::BufferArrayStream bas(body);
+
+#if 1
+ // This is the slower implementation. It is safe vis-a-vi the const_cast<> and modification
+ // of a LLSD managed array but contains an extra (potentially large) copy.
+ //
+ // *TODO: https://jira.secondlife.com/browse/MAINT-5221
+
+ LLSD::Binary data;
+ data.reserve(size);
+ bas >> std::noskipws;
+ data.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>());
+
+ result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = data;
+
+#else
+ // This is disabled because it's dangerous. See the other case for an
+ // alternate implementation.
+ // We create a new LLSD::Binary object and assign it to the result map.
+ // The LLSD has created it's own copy so we retrieve it asBinary and const cast
+ // the reference so that we can modify it.
+ // *TODO: This is potentially dangerous... but I am trying to avoid a potentially
+ // large copy.
+ result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = LLSD::Binary();
+ LLSD::Binary &data = const_cast<LLSD::Binary &>( result[HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary() );
+
+ data.reserve(size);
+ bas >> std::noskipws;
+ data.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>());
+#endif
+
+ return result;
+}
+
+//========================================================================
+/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for
+/// interacting with coroutines.
+///
+/// In addition to the normal "http_results" the returned LLSD will contain
+/// JSON entries will be converted into an LLSD map. All results are considered
+/// strings
+///
+class HttpCoroJSONHandler : public HttpCoroHandler
+{
+public:
+ HttpCoroJSONHandler(LLEventStream &reply);
+
+ virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status);
+};
+
+//-------------------------------------------------------------------------
+HttpCoroJSONHandler::HttpCoroJSONHandler(LLEventStream &reply) :
+ HttpCoroHandler(reply)
+{
+}
+
+LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status)
+{
+ LLSD result = LLSD::emptyMap();
+
+ BufferArray * body(response->getBody());
+ if (!body || !body->size())
+ {
+ return result;
+ }
+
+ LLCore::BufferArrayStream bas(body);
+ Json::Value jsonRoot;
+
+ try
+ {
+ bas >> jsonRoot;
+ }
+ catch (std::runtime_error e)
+ { // deserialization failed. Record the reason and pass back an empty map for markup.
+ status = LLCore::HttpStatus(499, std::string(e.what()));
+ return result;
+ }
+
+ // Convert the JSON structure to LLSD
+ result = LlsdFromJson(jsonRoot);
+
+ return result;
+}
+
+
+//========================================================================
+HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) :
+ mHttpRequest(request)
+{
+ mBoundListener = LLEventPumps::instance().obtain("mainloop").
+ listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1));
+}
+
+HttpRequestPumper::~HttpRequestPumper()
+{
+ if (mBoundListener.connected())
+ {
+ mBoundListener.disconnect();
+ }
+}
+
+bool HttpRequestPumper::pollRequest(const LLSD&)
+{
+ if (mHttpRequest->getStatus() != HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED))
+ {
+ mHttpRequest->update(0L);
+ }
+ return false;
+}
+
+//========================================================================
+const std::string HttpCoroutineAdapter::HTTP_RESULTS("http_result");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS("success");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_TYPE("type");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_STATUS("status");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_MESSAGE("message");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_URL("url");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_HEADERS("headers");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_CONTENT("content");
+const std::string HttpCoroutineAdapter::HTTP_RESULTS_RAW("raw");
+
+HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
+ LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) :
+ mAdapterName(name),
+ mPolicyId(policyId),
+ mPriority(priority),
+ mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID),
+ mWeakRequest(),
+ mWeakHandler()
+{
+}
+
+HttpCoroutineAdapter::~HttpCoroutineAdapter()
+{
+ cancelSuspendedOperation();
+}
+
+LLSD HttpCoroutineAdapter::postAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ return postAndSuspend_(request, url, body, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = requestPostWithLLSD(request,
+ mPolicyId, mPriority, url, body, options, headers,
+ handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::postAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::BufferArray::ptr_t rawbody,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ return postAndSuspend_(request, url, rawbody, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::postRawAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::BufferArray::ptr_t rawbody,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroRawHandler(replyPump));
+
+ return postAndSuspend_(request, url, rawbody, options, headers, httpHandler);
+}
+
+// *TODO: This functionality could be moved into the LLCore::Http library itself
+// by having the CURL layer read the file directly.
+LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, std::string fileName,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLCore::BufferArray::ptr_t fileData(new LLCore::BufferArray);
+
+ // scoping for our streams so that they go away when we no longer need them.
+ {
+ LLCore::BufferArrayStream outs(fileData.get());
+ llifstream ins(fileName.c_str(), std::iostream::binary | std::iostream::out);
+
+ if (ins.is_open())
+ {
+
+ ins.seekg(0, std::ios::beg);
+ ins >> std::noskipws;
+
+ std::copy(std::istream_iterator<U8>(ins), std::istream_iterator<U8>(),
+ std::ostream_iterator<U8>(outs));
+
+ ins.close();
+ }
+ }
+
+ return postAndSuspend(request, url, fileData, options, headers);
+}
+
+// *TODO: This functionality could be moved into the LLCore::Http library itself
+// by having the CURL layer read the file directly.
+LLSD HttpCoroutineAdapter::postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLCore::BufferArray::ptr_t fileData(new LLCore::BufferArray);
+
+ // scoping for our streams so that they go away when we no longer need them.
+ {
+ LLCore::BufferArrayStream outs(fileData.get());
+ LLVFile vfile(gVFS, assetId, assetType, LLVFile::READ);
+
+ S32 fileSize = vfile.getSize();
+ U8* fileBuffer;
+ fileBuffer = new U8[fileSize];
+ vfile.read(fileBuffer, fileSize);
+
+ outs.write((char*)fileBuffer, fileSize);
+ delete[] fileBuffer;
+ }
+
+ return postAndSuspend(request, url, fileData, options, headers);
+}
+
+LLSD HttpCoroutineAdapter::postJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+
+ {
+ LLCore::BufferArrayStream outs(rawbody.get());
+ Json::Value root = LlsdToJson(body);
+ Json::FastWriter writer;
+
+ LL_WARNS("Http::post") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL;
+
+ outs << writer.write(root);
+ }
+
+ return postAndSuspend_(request, url, rawbody, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, mPriority, url, rawbody.get(),
+ options, headers, handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::putAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ return putAndSuspend_(request, url, body, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::putJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName, true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+
+ {
+ LLCore::BufferArrayStream outs(rawbody.get());
+ Json::Value root = LlsdToJson(body);
+ Json::FastWriter writer;
+
+ LL_WARNS("Http::put") << "JSON Generates: \"" << writer.write(root) << "\"" << LL_ENDL;
+ outs << writer.write(root);
+ }
+
+ return putAndSuspend_(request, url, rawbody, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = requestPutWithLLSD(request,
+ mPolicyId, mPriority, url, body, options, headers,
+ handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLCore::BufferArray::ptr_t & rawbody,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = request->requestPut(mPolicyId, mPriority,
+ url, rawbody.get(), options, headers, handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+
+LLSD HttpCoroutineAdapter::getAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ return getAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::getRawAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroRawHandler(replyPump));
+
+ return getAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::getJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ return getAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::getAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, mPriority,
+ url, options, headers, handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+
+LLSD HttpCoroutineAdapter::deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ return deleteAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+LLSD HttpCoroutineAdapter::deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroJSONHandler(replyPump));
+
+ return deleteAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::HttpOptions::ptr_t &options,
+ LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId, mPriority,
+ url, options, headers, handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::patchAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ return patchAndSuspend_(request, url, body, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::patchAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ LLCore::HttpHandle hhandle = requestPatchWithLLSD(request,
+ mPolicyId, mPriority, url, body, options, headers,
+ handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::copyAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const std::string dest,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ if (!headers)
+ headers.reset(new LLCore::HttpHeaders);
+ headers->append(HTTP_OUT_HEADER_DESTINATION, dest);
+
+ return copyAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::copyAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ //
+ LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, mPriority, url,
+ options, headers, handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+LLSD HttpCoroutineAdapter::moveAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const std::string dest,
+ LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+ LLEventStream replyPump(mAdapterName + "Reply", true);
+ HttpCoroHandler::ptr_t httpHandler(new HttpCoroLLSDHandler(replyPump));
+
+ if (!headers)
+ headers.reset(new LLCore::HttpHeaders);
+ headers->append(HTTP_OUT_HEADER_DESTINATION, dest);
+
+ return moveAndSuspend_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::moveAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler)
+{
+ HttpRequestPumper pumper(request);
+
+ checkDefaultHeaders(headers);
+
+ // The HTTPCoroHandler does not self delete, so retrieval of a the contained
+ // pointer from the smart pointer is safe in this case.
+ //
+ LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, mPriority, url,
+ options, headers, handler.get());
+
+ if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+ }
+
+ saveState(hhandle, request, handler);
+ LLSD results = llcoro::suspendUntilEventOn(handler->getReplyPump());
+ cleanState();
+
+ return results;
+}
+
+
+void HttpCoroutineAdapter::checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers)
+{
+ if (!headers)
+ headers.reset(new LLCore::HttpHeaders);
+ if (!headers->find(HTTP_OUT_HEADER_ACCEPT))
+ {
+ headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
+ }
+ if (!headers->find(HTTP_OUT_HEADER_CONTENT_TYPE))
+ {
+ headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
+ }
+
+ if (!headers->find("X-SecondLife-UDP-Listen-Port") && gMessageSystem)
+ {
+ headers->append("X-SecondLife-UDP-Listen-Port", llformat("%d", gMessageSystem->mPort));
+ }
+}
+
+
+void HttpCoroutineAdapter::cancelSuspendedOperation()
+{
+ LLCore::HttpRequest::ptr_t request = mWeakRequest.lock();
+ HttpCoroHandler::ptr_t handler = mWeakHandler.lock();
+ if ((request) && (handler) && (mYieldingHandle != LLCORE_HTTP_HANDLE_INVALID))
+ {
+ cleanState();
+ LL_INFOS() << "Canceling yielding request!" << LL_ENDL;
+ request->requestCancel(mYieldingHandle, handler.get());
+ }
+}
+
+void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle,
+ LLCore::HttpRequest::ptr_t &request, HttpCoroHandler::ptr_t &handler)
+{
+ mWeakRequest = request;
+ mWeakHandler = handler;
+ mYieldingHandle = yieldingHandle;
+}
+
+void HttpCoroutineAdapter::cleanState()
+{
+ mWeakRequest.reset();
+ mWeakHandler.reset();
+ mYieldingHandle = LLCORE_HTTP_HANDLE_INVALID;
+}
+
+/*static*/
+LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request,
+ const std::string &url)
+{
+ LLCore::HttpStatus status = request->getStatus();
+ LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
+ " message = " << status.getMessage() << LL_ENDL;
+
+ // Mimic the status results returned from an http error that we had
+ // to wait on
+ LLSD httpresults = LLSD::emptyMap();
+
+ HttpCoroHandler::writeStatusCodes(status, url, httpresults);
+
+ LLSD errorres = LLSD::emptyMap();
+ errorres["http_result"] = httpresults;
+
+ return errorres;
+}
+
+/*static*/
+LLCore::HttpStatus HttpCoroutineAdapter::getStatusFromLLSD(const LLSD &httpResults)
+{
+ LLCore::HttpStatus::type_enum_t type = static_cast<LLCore::HttpStatus::type_enum_t>(httpResults[HttpCoroutineAdapter::HTTP_RESULTS_TYPE].asInteger());
+ short code = static_cast<short>(httpResults[HttpCoroutineAdapter::HTTP_RESULTS_STATUS].asInteger());
+
+ return LLCore::HttpStatus(type, code);
+}
+
+/*static*/
+void HttpCoroutineAdapter::callbackHttpGet(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure)
+{
+ LLCoros::instance().launch("HttpCoroutineAdapter::genericGetCoro",
+ boost::bind(&HttpCoroutineAdapter::trivialGetCoro, url, policyId, success, failure));
+}
+
+/*static*/
+void HttpCoroutineAdapter::messageHttpGet(const std::string &url, const std::string &success, const std::string &failure)
+{
+ completionCallback_t cbSuccess = (success.empty()) ? NULL :
+ static_cast<completionCallback_t>(boost::bind(&logMessageSuccess, "HttpCoroutineAdapter", url, success));
+ completionCallback_t cbFailure = (failure.empty()) ? NULL :
+ static_cast<completionCallback_t>(boost::bind(&logMessageFail, "HttpCoroutineAdapter", url, failure));
+ callbackHttpGet(url, cbSuccess, cbFailure);
+}
+
+/*static*/
+void HttpCoroutineAdapter::trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure)
+{
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericGetCoro", policyId));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+
+ LL_INFOS("HttpCoroutineAdapter", "genericGetCoro") << "Generic GET for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (failure)
+ {
+ failure(httpResults);
+ }
+ }
+ else
+ {
+ if (success)
+ {
+ success(result);
+ }
+ }
}
+/*static*/
+void HttpCoroutineAdapter::callbackHttpPost(const std::string &url, LLCore::HttpRequest::policy_t policyId, const LLSD &postData, completionCallback_t success, completionCallback_t failure)
+{
+ LLCoros::instance().launch("HttpCoroutineAdapter::genericPostCoro",
+ boost::bind(&HttpCoroutineAdapter::trivialPostCoro, url, policyId, postData, success, failure));
+}
+
+/*static*/
+void HttpCoroutineAdapter::messageHttpPost(const std::string &url, const LLSD &postData, const std::string &success, const std::string &failure)
+{
+ completionCallback_t cbSuccess = (success.empty()) ? NULL :
+ static_cast<completionCallback_t>(boost::bind(&logMessageSuccess, "HttpCoroutineAdapter", url, success));
+ completionCallback_t cbFailure = (failure.empty()) ? NULL :
+ static_cast<completionCallback_t>(boost::bind(&logMessageFail, "HttpCoroutineAdapter", url, failure));
+
+ callbackHttpPost(url, postData, cbSuccess, cbFailure);
+}
+
+/*static*/
+void HttpCoroutineAdapter::trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure)
+{
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", policyId));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+
+ LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ // If a failure routine is provided do it.
+ if (failure)
+ {
+ failure(httpResults);
+ }
+ }
+ else
+ {
+ // If a success routine is provided do it.
+ if (success)
+ {
+ success(result);
+ }
+ }
+}
+
+
} // end namespace LLCoreHttpUtil
diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h
index d40172bc7a..9328427c34 100644
--- a/indra/llmessage/llcorehttputil.h
+++ b/indra/llmessage/llcorehttputil.h
@@ -36,9 +36,15 @@
#include "httpheaders.h"
#include "httpoptions.h"
#include "httphandler.h"
+#include "llhttpconstants.h" // *TODO: move to llcorehttp
#include "bufferarray.h"
#include "bufferstream.h"
#include "llsd.h"
+#include "llevents.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llassettype.h"
+#include "lluuid.h"
///
/// The base llcorehttp library implements many HTTP idioms
@@ -51,6 +57,7 @@
///
namespace LLCoreHttpUtil
{
+ extern const F32 HTTP_REQUEST_EXPIRY_SECS;
/// Attempt to convert a response object's contents to LLSD.
/// It is expected that the response body will be of non-zero
@@ -101,15 +108,572 @@ std::string responseToString(LLCore::HttpResponse * response);
/// a now-useless HttpHandler object.
///
LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request,
- LLCore::HttpRequest::policy_t policy_id,
- LLCore::HttpRequest::priority_t priority,
- const std::string & url,
- const LLSD & body,
- LLCore::HttpOptions * options,
- LLCore::HttpHeaders * headers,
- LLCore::HttpHandler * handler);
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const LLCore::HttpOptions::ptr_t &options,
+ const LLCore::HttpHeaders::ptr_t &headers,
+ LLCore::HttpHandler * handler);
-} // end namespace LLCoreHttpUtil
+inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const LLCore::HttpOptions::ptr_t & options,
+ const LLCore::HttpHeaders::ptr_t & headers,
+ LLCore::HttpHandler * handler)
+{
+ return requestPostWithLLSD(request.get(), policy_id, priority,
+ url, body, options, headers, handler);
+}
+
+inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpHandler * handler)
+{
+ LLCore::HttpOptions::ptr_t options;
+ LLCore::HttpHeaders::ptr_t headers;
+
+ return requestPostWithLLSD(request.get(), policy_id, priority,
+ url, body, options, headers, handler);
+}
+
+
+/// Issue a standard HttpRequest::requestPut() call but using
+/// and LLSD object as the request body. Conventions are the
+/// same as with that method. Caller is expected to provide
+/// an HttpHeaders object with a correct 'Content-Type:' header.
+/// One will not be provided by this call.
+///
+/// @return If request is successfully issued, the
+/// HttpHandle representing the request.
+/// On error, LLCORE_HTTP_HANDLE_INVALID
+/// is returned and caller can fetch detailed
+/// status with the getStatus() method on the
+/// request object. In case of error, no
+/// request is queued and caller may need to
+/// perform additional cleanup such as freeing
+/// a now-useless HttpHandler object.
+///
+LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const LLCore::HttpOptions::ptr_t &options,
+ const LLCore::HttpHeaders::ptr_t &headers,
+ LLCore::HttpHandler * handler);
+
+inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const LLCore::HttpOptions::ptr_t & options,
+ const LLCore::HttpHeaders::ptr_t & headers,
+ LLCore::HttpHandler * handler)
+{
+ return requestPutWithLLSD(request.get(), policy_id, priority,
+ url, body, options, headers, handler);
+}
+
+inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpHandler * handler)
+{
+ LLCore::HttpOptions::ptr_t options;
+ LLCore::HttpHeaders::ptr_t headers;
+
+ return requestPutWithLLSD(request.get(), policy_id, priority,
+ url, body, options, headers, handler);
+}
+
+/// Issue a standard HttpRequest::requestPatch() call but using
+/// and LLSD object as the request body. Conventions are the
+/// same as with that method. Caller is expected to provide
+/// an HttpHeaders object with a correct 'Content-Type:' header.
+/// One will not be provided by this call.
+///
+/// @return If request is successfully issued, the
+/// HttpHandle representing the request.
+/// On error, LLCORE_HTTP_HANDLE_INVALID
+/// is returned and caller can fetch detailed
+/// status with the getStatus() method on the
+/// request object. In case of error, no
+/// request is queued and caller may need to
+/// perform additional cleanup such as freeing
+/// a now-useless HttpHandler object.
+///
+LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const LLCore::HttpOptions::ptr_t &options,
+ const LLCore::HttpHeaders::ptr_t &headers,
+ LLCore::HttpHandler * handler);
+
+inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ const LLCore::HttpOptions::ptr_t & options,
+ const LLCore::HttpHeaders::ptr_t & headers,
+ LLCore::HttpHandler * handler)
+{
+ return requestPatchWithLLSD(request.get(), policy_id, priority,
+ url, body, options, headers, handler);
+}
+
+inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request,
+ LLCore::HttpRequest::policy_t policy_id,
+ LLCore::HttpRequest::priority_t priority,
+ const std::string & url,
+ const LLSD & body,
+ LLCore::HttpHandler * handler)
+{
+ LLCore::HttpOptions::ptr_t options;
+ LLCore::HttpHeaders::ptr_t headers;
+
+ return requestPatchWithLLSD(request.get(), policy_id, priority,
+ url, body, options, headers, handler);
+}
+
+//=========================================================================
+/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for
+/// interacting with coroutines. When the request is completed the response
+/// will be posted onto the supplied Event Pump.
+///
+/// The LLSD posted back to the coroutine will have the following additions:
+/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status
+/// +- ["status"] - The status code associated with the HTTP call
+/// +- ["success"] - Success of failure of the HTTP call and LLSD parsing.
+/// +- ["type"] - The LLCore::HttpStatus type associted with the HTTP call
+/// +- ["url"] - The URL used to make the call.
+/// +- ["headers"] - A map of name name value pairs with the HTTP headers.
+///
+class HttpCoroHandler : public LLCore::HttpHandler
+{
+public:
+
+ typedef boost::shared_ptr<HttpCoroHandler> ptr_t;
+ typedef boost::weak_ptr<HttpCoroHandler> wptr_t;
+
+ HttpCoroHandler(LLEventStream &reply);
+
+ static void writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result);
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+ inline LLEventStream &getReplyPump()
+ {
+ return mReplyPump;
+ }
+
+protected:
+ /// this method may modify the status value
+ virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) = 0;
+
+private:
+ void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result);
+ LLEventStream &mReplyPump;
+};
+
+//=========================================================================
+/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine
+/// interaction.
+///
+/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After
+/// any application specific setup call the post, put or get method. The request
+/// will be automatically pumped and the method will return with an LLSD describing
+/// the result of the operation. See HttpCoroHandler for a description of the
+/// decoration done to the returned LLSD.
+///
+/// Posting through the adapter will automatically add the following headers to
+/// the request if they have not been previously specified in a supplied
+/// HttpHeaders object:
+/// "Accept=application/llsd+xml"
+/// "X-SecondLife-UDP-Listen-Port=###"
+///
+class HttpCoroutineAdapter
+{
+public:
+ static const std::string HTTP_RESULTS;
+ static const std::string HTTP_RESULTS_SUCCESS;
+ static const std::string HTTP_RESULTS_TYPE;
+ static const std::string HTTP_RESULTS_STATUS;
+ static const std::string HTTP_RESULTS_MESSAGE;
+ static const std::string HTTP_RESULTS_URL;
+ static const std::string HTTP_RESULTS_HEADERS;
+ static const std::string HTTP_RESULTS_CONTENT;
+ static const std::string HTTP_RESULTS_RAW;
+
+ typedef boost::shared_ptr<HttpCoroutineAdapter> ptr_t;
+ typedef boost::weak_ptr<HttpCoroutineAdapter> wptr_t;
+
+ HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId,
+ LLCore::HttpRequest::priority_t priority = 0L);
+ ~HttpCoroutineAdapter();
+
+ /// Execute a Post transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::BufferArray::ptr_t rawbody,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ LLSD postAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postAndSuspend(request, url, rawbody,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ LLSD postRawAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::BufferArray::ptr_t rawbody,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+
+ LLSD postRawAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postRawAndSuspend(request, url, rawbody,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, std::string fileName,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, std::string fileName,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postFileAndSuspend(request, url, fileName,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+
+ LLSD postFileAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLUUID assetId, LLAssetType::EType assetType,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postFileAndSuspend(request, url, assetId, assetType,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ LLSD postJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD postJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return postJsonAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+
+
+ /// Execute a Put transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+
+ LLSD putAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t headers)
+ {
+ return putAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ LLSD putJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD putJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return putJsonAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ /// Execute a Get transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ ///
+ LLSD getAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD getAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return getAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
+
+ LLSD getRawAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD getRawAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return getRawAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
+
+ /// These methods have the same behavior as @getAndSuspend() however they are
+ /// expecting the server to return the results formatted in a JSON string.
+ /// On a successful GET call the JSON results will be converted into LLSD
+ /// before being returned to the caller.
+ LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD getJsonAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return getJsonAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
+
+
+ /// Execute a DELETE transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD deleteAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t headers)
+ {
+ return deleteAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
+
+ /// These methods have the same behavior as @deleteAndSuspend() however they are
+ /// expecting the server to return any results formatted in a JSON string.
+ /// On a successful DELETE call the JSON results will be converted into LLSD
+ /// before being returned to the caller.
+ LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD deleteJsonAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, LLCore::HttpHeaders::ptr_t headers)
+ {
+ return deleteJsonAndSuspend(request, url,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ headers);
+ }
+
+
+ /// Execute a PATCH transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD patchAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return patchAndSuspend(request, url, body,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ /// Execute a COPY transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: The destination is passed through the HTTP pipe as a header
+ /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination");
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const std::string dest,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD copyAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const std::string & dest,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return copyAndSuspend(request, url, dest,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ /// Execute a MOVE transaction on the supplied URL and yield execution of
+ /// the coroutine until a result is available.
+ ///
+ /// @Note: The destination is passed through the HTTP pipe in the headers.
+ /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination");
+ ///
+ /// @Note: the request's smart pointer is passed by value so that it will
+ /// not be deallocated during the yield.
+ LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t request,
+ const std::string & url, const std::string dest,
+ LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+ LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+ LLSD moveAndSuspend(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const std::string & dest,
+ LLCore::HttpHeaders::ptr_t &headers)
+ {
+ return moveAndSuspend(request, url, dest,
+ LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+ }
+
+ ///
+ void cancelSuspendedOperation();
+
+ static LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults);
+
+ /// The convenience routines below can be provided with callback functors
+ /// which will be invoked in the case of success or failure. These callbacks
+ /// should match this form.
+ /// @sa callbackHttpGet
+ /// @sa callbackHttpPost
+ typedef boost::function<void(const LLSD &)> completionCallback_t;
+
+ static void callbackHttpGet(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success = NULL, completionCallback_t failure = NULL);
+ static void callbackHttpGet(const std::string &url, completionCallback_t success = NULL, completionCallback_t failure = NULL)
+ {
+ callbackHttpGet(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, success, failure);
+ }
+ static void callbackHttpPost(const std::string &url, LLCore::HttpRequest::policy_t policyId, const LLSD &postData, completionCallback_t success = NULL, completionCallback_t failure = NULL);
+ static void callbackHttpPost(const std::string &url, const LLSD &postData, completionCallback_t success = NULL, completionCallback_t failure = NULL)
+ {
+ callbackHttpPost(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, postData, success, failure);
+ }
+
+ /// Generic Get and post routines for HTTP via coroutines.
+ /// These static methods do all required setup for the GET or POST operation.
+ /// When the operation completes successfully they will put the success message in the log at INFO level,
+ /// If the operation fails the failure message is written to the log at WARN level.
+ ///
+ static void messageHttpGet(const std::string &url, const std::string &success = std::string(), const std::string &failure = std::string());
+ static void messageHttpPost(const std::string &url, const LLSD &postData, const std::string &success, const std::string &failure);
+
+
+private:
+ static LLSD buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, const std::string &url);
+
+ void saveState(LLCore::HttpHandle yieldingHandle, LLCore::HttpRequest::ptr_t &request,
+ HttpCoroHandler::ptr_t &handler);
+ void cleanState();
+
+ LLSD postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD postAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::BufferArray::ptr_t &rawbody,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD putAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLCore::BufferArray::ptr_t & rawbody,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD getAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::HttpOptions::ptr_t &options,
+ LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler);
+
+ LLSD deleteAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, LLCore::HttpOptions::ptr_t &options,
+ LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler);
+
+ LLSD patchAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url, const LLSD & body,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD copyAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ LLSD moveAndSuspend_(LLCore::HttpRequest::ptr_t &request,
+ const std::string & url,
+ LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+ HttpCoroHandler::ptr_t &handler);
+
+ static void trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure);
+ static void trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure);
+
+ void checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers);
+
+ std::string mAdapterName;
+ LLCore::HttpRequest::priority_t mPriority;
+ LLCore::HttpRequest::policy_t mPolicyId;
+
+ LLCore::HttpHandle mYieldingHandle;
+ LLCore::HttpRequest::wptr_t mWeakRequest;
+ HttpCoroHandler::wptr_t mWeakHandler;
+};
+
+
+} // end namespace LLCoreHttpUtil
#endif // LL_LLCOREHTTPUTIL_H
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
deleted file mode 100755
index 73df47b933..0000000000
--- a/indra/llmessage/llcurl.cpp
+++ /dev/null
@@ -1,2038 +0,0 @@
-/**
- * @file llcurl.cpp
- * @author Zero / Donovan
- * @date 2006-10-15
- * @brief Implementation of wrapper around libcurl.
- *
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010-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$
- */
-
-#if LL_WINDOWS
-#define SAFE_SSL 1
-#elif LL_DARWIN
-#define SAFE_SSL 1
-#else
-#define SAFE_SSL 1
-#endif
-
-#include "linden_common.h"
-
-#include "llcurl.h"
-
-#include <algorithm>
-#include <iomanip>
-#include <curl/curl.h>
-#if SAFE_SSL
-#include <openssl/crypto.h>
-#endif
-
-#include "llbufferstream.h"
-#include "llproxy.h"
-#include "llsdserialize.h"
-#include "llstl.h"
-#include "llstring.h"
-#include "llthread.h"
-#include "lltimer.h"
-
-//////////////////////////////////////////////////////////////////////////////
-/*
- The trick to getting curl to do keep-alives is to reuse the
- same easy handle for the requests. It appears that curl
- keeps a pool of connections alive for each easy handle, but
- doesn't share them between easy handles. Therefore it is
- important to keep a pool of easy handles and reuse them,
- rather than create and destroy them with each request. This
- code does this.
-
- Furthermore, it would behoove us to keep track of which
- hosts an easy handle was used for and pick an easy handle
- that matches the next request. This code does not current
- do this.
- */
-
-//////////////////////////////////////////////////////////////////////////////
-
-static const U32 EASY_HANDLE_POOL_SIZE = 5;
-static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
-static const S32 CURL_REQUEST_TIMEOUT = 120; // seconds per operation
-static const S32 CURL_CONNECT_TIMEOUT = 30; //seconds to wait for a connection
-static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
-
-// DEBUG //
-S32 gCurlEasyCount = 0;
-S32 gCurlMultiCount = 0;
-
-//////////////////////////////////////////////////////////////////////////////
-
-//static
-std::vector<LLMutex*> LLCurl::sSSLMutex;
-std::string LLCurl::sCAPath;
-std::string LLCurl::sCAFile;
-LLCurlThread* LLCurl::sCurlThread = NULL ;
-LLMutex* LLCurl::sHandleMutexp = NULL ;
-S32 LLCurl::sTotalHandles = 0 ;
-bool LLCurl::sNotQuitting = true;
-F32 LLCurl::sCurlRequestTimeOut = 120.f; //seonds
-S32 LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined).
-CURL* LLCurl::sCurlTemplateStandardHandle = NULL;
-
-void check_curl_code(CURLcode code)
-{
- if (code != CURLE_OK)
- {
- // linux appears to throw a curl error once per session for a bad initialization
- // at a pretty random time (when enabling cookies).
- LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;
- }
-}
-
-void check_curl_multi_code(CURLMcode code)
-{
- if (code != CURLM_OK)
- {
- // linux appears to throw a curl error once per session for a bad initialization
- // at a pretty random time (when enabling cookies).
- LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;
- }
-}
-
-//static
-void LLCurl::setCAPath(const std::string& path)
-{
- sCAPath = path;
-}
-
-//static
-void LLCurl::setCAFile(const std::string& file)
-{
- sCAFile = file;
-}
-
-//static
-std::string LLCurl::getVersionString()
-{
- return std::string(curl_version());
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-LLCurl::Responder::Responder()
- : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)
-{
-}
-
-LLCurl::Responder::~Responder()
-{
- LL_CHECK_MEMORY
-}
-
-// virtual
-void LLCurl::Responder::httpFailure()
-{
- LL_WARNS("curl") << dumpResponse() << LL_ENDL;
-}
-
-std::string LLCurl::Responder::dumpResponse() const
-{
- 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::httpSuccess()
-{
-}
-
-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(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
-{
- LLBufferStream istr(channels, buffer.get());
- 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)))
- {
- LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] "
- << "(" << mReason << ") body: " << debug_body << LL_ENDL;
- }
-
- httpCompleted();
-}
-
-// virtual
-void LLCurl::Responder::httpCompleted()
-{
- if (isGoodStatus())
- {
- httpSuccess();
- }
- else
- {
- httpFailure();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-std::set<CURL*> LLCurl::Easy::sFreeHandles;
-std::set<CURL*> LLCurl::Easy::sActiveHandles;
-LLMutex* LLCurl::Easy::sHandleMutexp = NULL ;
-
-//static
-CURL* LLCurl::Easy::allocEasyHandle()
-{
- llassert(LLCurl::getCurlThread()) ;
-
- CURL* ret = NULL;
-
- LLMutexLock lock(sHandleMutexp) ;
-
- if (sFreeHandles.empty())
- {
- ret = LLCurl::newEasyHandle();
- }
- else
- {
- ret = *(sFreeHandles.begin());
- sFreeHandles.erase(ret);
- curl_easy_reset(ret);
- }
-
- if (ret)
- {
- sActiveHandles.insert(ret);
- }
-
- return ret;
-}
-
-//static
-void LLCurl::Easy::releaseEasyHandle(CURL* handle)
-{
- static const S32 MAX_NUM_FREE_HANDLES = 32 ;
-
- if (!handle)
- {
- return ; //handle allocation failed.
- //LL_ERRS() << "handle cannot be NULL!" << LL_ENDL;
- }
-
- LLMutexLock lock(sHandleMutexp) ;
- if (sActiveHandles.find(handle) != sActiveHandles.end())
- {
- LL_CHECK_MEMORY
- sActiveHandles.erase(handle);
- LL_CHECK_MEMORY
- if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES)
- {
- sFreeHandles.insert(handle);
- LL_CHECK_MEMORY
- }
- else
- {
- LLCurl::deleteEasyHandle(handle) ;
- LL_CHECK_MEMORY
- }
- }
- else
- {
- LL_ERRS() << "Invalid handle." << LL_ENDL;
- }
-}
-
-//static
-void LLCurl::Easy::deleteAllActiveHandles()
-{
- LLMutexLock lock(sHandleMutexp) ;
- LL_CHECK_MEMORY
- for (std::set<CURL*>::iterator activeHandle = sActiveHandles.begin(); activeHandle != sActiveHandles.end(); ++activeHandle)
- {
- CURL* curlHandle = *activeHandle;
- LLCurl::deleteEasyHandle(curlHandle);
- LL_CHECK_MEMORY
- }
-
- sFreeHandles.clear();
-}
-
-//static
-void LLCurl::Easy::deleteAllFreeHandles()
-{
- LLMutexLock lock(sHandleMutexp) ;
- LL_CHECK_MEMORY
- for (std::set<CURL*>::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle)
- {
- CURL* curlHandle = *freeHandle;
- LLCurl::deleteEasyHandle(curlHandle);
- LL_CHECK_MEMORY
- }
-
- sFreeHandles.clear();
-}
-
-LLCurl::Easy::Easy()
- : mHeaders(NULL),
- mCurlEasyHandle(NULL)
-{
- mErrorBuffer[0] = 0;
-}
-
-LLCurl::Easy* LLCurl::Easy::getEasy()
-{
- Easy* easy = new Easy();
- easy->mCurlEasyHandle = allocEasyHandle();
-
- if (!easy->mCurlEasyHandle)
- {
- // this can happen if we have too many open files (fails in c-ares/ares_init.c)
- LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: "
- << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
- delete easy;
- return NULL;
- }
-
- // Enable a brief cache period for now. This was zero for the longest time
- // which caused some routers grief and generated unneeded traffic. For the
- // threaded resolver, we're using system resolution libraries and non-zero values
- // are preferred. The c-ares resolver is another matter and it might not
- // track server changes as well.
- CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_code(result);
- result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- check_curl_code(result);
-
- ++gCurlEasyCount;
- return easy;
-}
-
-LLCurl::Easy::~Easy()
-{
- releaseEasyHandle(mCurlEasyHandle);
- --gCurlEasyCount;
- curl_slist_free_all(mHeaders);
- LL_CHECK_MEMORY
- for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
- LL_CHECK_MEMORY
- if (mResponder && LLCurl::sNotQuitting) //aborted
- {
- // 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;
-}
-
-void LLCurl::Easy::resetState()
-{
- curl_easy_reset(mCurlEasyHandle);
-
- if (mHeaders)
- {
- curl_slist_free_all(mHeaders);
- mHeaders = NULL;
- }
-
- mRequest.str("");
- mRequest.clear();
-
- mOutput.reset();
-
- mInput.str("");
- mInput.clear();
-
- mErrorBuffer[0] = 0;
-
- mHeaderOutput.str("");
- mHeaderOutput.clear();
-}
-
-void LLCurl::Easy::setErrorBuffer()
-{
- setopt(CURLOPT_ERRORBUFFER, &mErrorBuffer);
-}
-
-const char* LLCurl::Easy::getErrorBuffer()
-{
- return mErrorBuffer;
-}
-
-void LLCurl::Easy::setCA()
-{
- if (!sCAPath.empty())
- {
- setoptString(CURLOPT_CAPATH, sCAPath);
- }
- if (!sCAFile.empty())
- {
- setoptString(CURLOPT_CAINFO, sCAFile);
- }
-}
-
-void LLCurl::Easy::setHeaders()
-{
- setopt(CURLOPT_HTTPHEADER, mHeaders);
-}
-
-void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
-{
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload));
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime));
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));
-}
-
-S32 LLCurl::Easy::report(CURLcode code)
-{
- S32 responseCode = 0;
- std::string responseReason;
-
- if (code == CURLE_OK)
- {
- check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode));
- //*TODO: get reason from first line of mHeaderOutput
- }
- else
- {
- responseCode = HTTP_INTERNAL_ERROR;
- responseReason = strerror(code) + " : " + mErrorBuffer;
- setopt(CURLOPT_FRESH_CONNECT, TRUE);
- }
-
- if (mResponder)
- {
- mResponder->setResult(responseCode, responseReason);
- mResponder->completedRaw(mChannels, mOutput);
- mResponder = NULL;
- }
-
- resetState();
- return responseCode;
-}
-
-// Note: these all assume the caller tracks the value (i.e. keeps it persistant)
-void LLCurl::Easy::setopt(CURLoption option, S32 value)
-{
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
- check_curl_code(result);
-}
-
-void LLCurl::Easy::setopt(CURLoption option, void* value)
-{
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
- check_curl_code(result);
-}
-
-void LLCurl::Easy::setopt(CURLoption option, char* value)
-{
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value);
- check_curl_code(result);
-}
-
-// Note: this copies the string so that the caller does not have to keep it around
-void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
-{
- char* tstring = new char[value.length()+1];
- strcpy(tstring, value.c_str());
- mStrings.push_back(tstring);
- CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring);
- 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)
-{
- if (str)
- {
- mHeaders = curl_slist_append(mHeaders, str);
- if (!mHeaders)
- {
- LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL;
- }
- }
-}
-
-size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
-{
- LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
-
- S32 n = size * nmemb;
- S32 startpos = (S32)easy->getInput().tellg();
- easy->getInput().seekg(0, std::ios::end);
- S32 endpos = (S32)easy->getInput().tellg();
- easy->getInput().seekg(startpos, std::ios::beg);
- S32 maxn = endpos - startpos;
- n = llmin(n, maxn);
- easy->getInput().read((char*)data, n);
-
- return n;
-}
-
-size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data)
-{
- LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
-
- S32 n = size * nmemb;
- easy->getOutput()->append(easy->getChannels().in(), (const U8*)data, n);
-
- return n;
-}
-
-size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data)
-{
- LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
-
- size_t n = size * nmemb;
- easy->getHeaderOutput().write((const char*)data, n);
-
- return n;
-}
-
-void LLCurl::Easy::prepRequest(const std::string& url,
- const std::vector<std::string>& headers,
- ResponderPtr responder, S32 time_out, bool post)
-{
- resetState();
-
- if (post) setoptString(CURLOPT_ENCODING, "");
-
- //setopt(CURLOPT_VERBOSE, 1); // useful for debugging
- setopt(CURLOPT_NOSIGNAL, 1);
- setopt(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
-
- // Set the CURL options for either Socks or HTTP proxy
- LLProxy::getInstance()->applyProxySettings(this);
-
- mOutput.reset(new LLBufferArray);
- mOutput->setThreaded(true);
- setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
- setopt(CURLOPT_WRITEDATA, (void*)this);
-
- setopt(CURLOPT_READFUNCTION, (void*)&curlReadCallback);
- setopt(CURLOPT_READDATA, (void*)this);
-
- setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback);
- setopt(CURLOPT_HEADERDATA, (void*)this);
-
- // Allow up to five redirects
- if (responder && responder->followRedir())
- {
- setopt(CURLOPT_FOLLOWLOCATION, 1);
- setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS);
- }
-
- setErrorBuffer();
- setCA();
-
- setopt(CURLOPT_SSL_VERIFYPEER, true);
-
- //don't verify host name so urls with scrubbed host names will work (improves DNS performance)
- setopt(CURLOPT_SSL_VERIFYHOST, 0);
- setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));
- setopt(CURLOPT_CONNECTTIMEOUT, CURL_CONNECT_TIMEOUT);
-
- setoptString(CURLOPT_URL, url);
-
- mResponder = responder;
-
- if (!post)
- {
- // *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)
- {
- slist_append((*iter).c_str());
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////
-LLCurl::Multi::Multi(F32 idle_time_out)
- : mQueued(0),
- mErrorCount(0),
- mState(STATE_READY),
- mDead(FALSE),
- mValid(TRUE),
- mMutexp(NULL),
- mDeletionMutexp(NULL),
- mEasyMutexp(NULL)
-{
- mCurlMultiHandle = LLCurl::newMultiHandle();
- if (!mCurlMultiHandle)
- {
- LL_WARNS() << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;
- mCurlMultiHandle = LLCurl::newMultiHandle();
- }
-
- //llassert_always(mCurlMultiHandle);
-
- if(mCurlMultiHandle)
- {
- if(LLCurl::getCurlThread()->getThreaded())
- {
- mMutexp = new LLMutex(NULL) ;
- mDeletionMutexp = new LLMutex(NULL) ;
- mEasyMutexp = new LLMutex(NULL) ;
- }
- LLCurl::getCurlThread()->addMulti(this) ;
-
- mIdleTimeOut = idle_time_out ;
- if(mIdleTimeOut < LLCurl::sCurlRequestTimeOut)
- {
- mIdleTimeOut = LLCurl::sCurlRequestTimeOut ;
- }
-
- ++gCurlMultiCount;
-}
-}
-
-LLCurl::Multi::~Multi()
-{
- cleanup(true) ;
-
- delete mDeletionMutexp ;
- mDeletionMutexp = NULL ;
-}
-
-void LLCurl::Multi::cleanup(bool deleted)
-{
- if(!mCurlMultiHandle)
- {
- return ; //nothing to clean.
- }
- llassert_always(deleted || !mValid) ;
-
- LLMutexLock lock(mDeletionMutexp);
-
-
- // Clean up active
- for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
- iter != mEasyActiveList.end(); ++iter)
- {
- Easy* easy = *iter;
- LL_CHECK_MEMORY
- check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
- LL_CHECK_MEMORY
- if(deleted)
- {
- easy->mResponder = NULL ; //avoid triggering mResponder.
- LL_CHECK_MEMORY
- }
- delete easy;
- LL_CHECK_MEMORY
- }
- mEasyActiveList.clear();
- mEasyActiveMap.clear();
-
- LL_CHECK_MEMORY
-
- // Clean up freed
- for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
- mEasyFreeList.clear();
-
- LL_CHECK_MEMORY
-
- check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle));
- mCurlMultiHandle = NULL ;
-
- LL_CHECK_MEMORY
-
- delete mMutexp ;
- mMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- delete mEasyMutexp ;
- mEasyMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- mQueued = 0 ;
- mState = STATE_COMPLETED;
-
- --gCurlMultiCount;
-
- return ;
-}
-
-void LLCurl::Multi::lock()
-{
- if(mMutexp)
- {
- mMutexp->lock() ;
- }
-}
-
-void LLCurl::Multi::unlock()
-{
- if(mMutexp)
- {
- mMutexp->unlock() ;
- }
-}
-
-void LLCurl::Multi::markDead()
-{
- {
- LLMutexLock lock(mDeletionMutexp) ;
-
- if(mCurlMultiHandle != NULL)
- {
- mDead = TRUE ;
- LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ;
-
- return;
- }
- }
-
- //not valid, delete it.
- delete this;
-}
-
-void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state)
-{
- lock() ;
- mState = state ;
- unlock() ;
-
- if(mState == STATE_READY)
- {
- LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_NORMAL) ;
- }
-}
-
-LLCurl::Multi::ePerformState LLCurl::Multi::getState()
-{
- return mState;
-}
-
-bool LLCurl::Multi::isCompleted()
-{
- return STATE_COMPLETED == getState() ;
-}
-
-bool LLCurl::Multi::waitToComplete()
-{
- if(!isValid())
- {
- return true ;
- }
-
- if(!mMutexp) //not threaded
- {
- doPerform() ;
- return true ;
- }
-
- bool completed = (STATE_COMPLETED == mState) ;
- if(!completed)
- {
- LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_HIGH) ;
- }
-
- return completed;
-}
-
-CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
-{
- LLMutexLock lock(mMutexp) ;
-
- CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue);
- return curlmsg;
-}
-
-//return true if dead
-bool LLCurl::Multi::doPerform()
-{
- LLMutexLock lock(mDeletionMutexp) ;
-
- bool dead = mDead ;
-
- if(mDead)
- {
- setState(STATE_COMPLETED);
- mQueued = 0 ;
- }
- else if(getState() != STATE_COMPLETED)
- {
- setState(STATE_PERFORMING);
-
- S32 q = 0;
- for (S32 call_count = 0;
- call_count < MULTI_PERFORM_CALL_REPEAT;
- call_count++)
- {
- LLMutexLock lock(mMutexp) ;
-
- //WARNING: curl_multi_perform will block for many hundreds of milliseconds
- // NEVER call this from the main thread, and NEVER allow the main thread to
- // wait on a mutex held by this thread while curl_multi_perform is executing
- CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
- if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
- {
- check_curl_multi_code(code);
-
- break;
- }
- }
-
- mQueued = q;
- setState(STATE_COMPLETED) ;
- mIdleTimer.reset() ;
- }
- else if(!mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it.
- {
- dead = true ;
- }
- else if(mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut - 1.f) //idle for too long, mark it invalid.
- {
- mValid = FALSE ;
- }
-
- return dead ;
-}
-
-S32 LLCurl::Multi::process()
-{
- if(!isValid())
- {
- return 0 ;
- }
-
- waitToComplete() ;
-
- if (getState() != STATE_COMPLETED)
- {
- return 0;
- }
-
- CURLMsg* msg;
- int msgs_in_queue;
-
- S32 processed = 0;
- while ((msg = info_read(&msgs_in_queue)))
- {
- ++processed;
- if (msg->msg == CURLMSG_DONE)
- {
- S32 response = 0;
- Easy* easy = NULL ;
-
- {
- LLMutexLock lock(mEasyMutexp) ;
- easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle);
- if (iter != mEasyActiveMap.end())
- {
- easy = iter->second;
- }
- }
-
- if(easy)
- {
- response = easy->report(msg->data.result);
- removeEasy(easy);
- }
- else
- {
- response = HTTP_INTERNAL_ERROR;
- //*TODO: change to LL_WARNS()
- LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL;
- }
- if (response >= 400)
- {
- // failure of some sort, inc mErrorCount for debugging and flagging multi for destruction
- ++mErrorCount;
- }
- }
- }
-
- setState(STATE_READY);
-
- return processed;
-}
-
-LLCurl::Easy* LLCurl::Multi::allocEasy()
-{
- Easy* easy = 0;
-
- if (mEasyFreeList.empty())
- {
- easy = Easy::getEasy();
- }
- else
- {
- LLMutexLock lock(mEasyMutexp) ;
- easy = *(mEasyFreeList.begin());
- mEasyFreeList.erase(easy);
- }
- if (easy)
- {
- LLMutexLock lock(mEasyMutexp) ;
- mEasyActiveList.insert(easy);
- mEasyActiveMap[easy->getCurlHandle()] = easy;
- }
- return easy;
-}
-
-bool LLCurl::Multi::addEasy(Easy* easy)
-{
- LLMutexLock lock(mMutexp) ;
- CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
- check_curl_multi_code(mcode);
- //if (mcode != CURLM_OK)
- //{
- // LL_WARNS() << "Curl Error: " << curl_multi_strerror(mcode) << LL_ENDL;
- // return false;
- //}
- return true;
-}
-
-void LLCurl::Multi::easyFree(Easy* easy)
-{
- if(mEasyMutexp)
- {
- mEasyMutexp->lock() ;
- }
-
- mEasyActiveList.erase(easy);
- mEasyActiveMap.erase(easy->getCurlHandle());
-
- if (mEasyFreeList.size() < EASY_HANDLE_POOL_SIZE)
- {
- mEasyFreeList.insert(easy);
-
- if(mEasyMutexp)
- {
- mEasyMutexp->unlock() ;
- }
-
- easy->resetState();
- }
- else
- {
- if(mEasyMutexp)
- {
- mEasyMutexp->unlock() ;
- }
- delete easy;
- }
-}
-
-void LLCurl::Multi::removeEasy(Easy* easy)
-{
- {
- LLMutexLock lock(mMutexp) ;
- check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
- }
- easyFree(easy);
-}
-
-//------------------------------------------------------------
-//LLCurlThread
-LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) :
- LLQueuedThread::QueuedRequest(handle, LLQueuedThread::PRIORITY_NORMAL, FLAG_AUTO_COMPLETE),
- mMulti(multi),
- mCurlThread(curl_thread)
-{
-}
-
-LLCurlThread::CurlRequest::~CurlRequest()
-{
- if(mMulti)
- {
- mCurlThread->deleteMulti(mMulti) ;
- mMulti = NULL ;
- }
-}
-
-bool LLCurlThread::CurlRequest::processRequest()
-{
- bool completed = true ;
- if(mMulti)
- {
- completed = mCurlThread->doMultiPerform(mMulti) ;
-
- if(!completed)
- {
- setPriority(LLQueuedThread::PRIORITY_LOW) ;
- }
- }
-
- return completed ;
-}
-
-void LLCurlThread::CurlRequest::finishRequest(bool completed)
-{
- if(mMulti->isDead())
- {
- mCurlThread->deleteMulti(mMulti) ;
- }
- else
- {
- mCurlThread->cleanupMulti(mMulti) ; //being idle too long, remove the request.
- }
-
- mMulti = NULL ;
-}
-
-LLCurlThread::LLCurlThread(bool threaded) :
- LLQueuedThread("curlthread", threaded)
-{
-}
-
-//virtual
-LLCurlThread::~LLCurlThread()
-{
-}
-
-S32 LLCurlThread::update(F32 max_time_ms)
-{
- return LLQueuedThread::update(max_time_ms);
-}
-
-void LLCurlThread::addMulti(LLCurl::Multi* multi)
-{
- multi->mHandle = generateHandle() ;
-
- CurlRequest* req = new CurlRequest(multi->mHandle, multi, this) ;
-
- if (!addRequest(req))
- {
- LL_WARNS() << "curl request added when the thread is quitted" << LL_ENDL;
- }
-}
-
-void LLCurlThread::killMulti(LLCurl::Multi* multi)
-{
- if(!multi)
- {
- return ;
- }
-
-
- multi->markDead() ;
-}
-
-//private
-bool LLCurlThread::doMultiPerform(LLCurl::Multi* multi)
-{
- return multi->doPerform() ;
-}
-
-//private
-void LLCurlThread::deleteMulti(LLCurl::Multi* multi)
-{
- delete multi ;
-}
-
-//private
-void LLCurlThread::cleanupMulti(LLCurl::Multi* multi)
-{
- multi->cleanup() ;
- if(multi->isDead()) //check if marked dead during cleaning up.
- {
- deleteMulti(multi) ;
- }
-}
-
-//------------------------------------------------------------
-
-//static
-std::string LLCurl::strerror(CURLcode errorcode)
-{
- return std::string(curl_easy_strerror(errorcode));
-}
-
-////////////////////////////////////////////////////////////////////////////
-// For generating a simple request for data
-// using one multi and one easy per request
-
-LLCurlRequest::LLCurlRequest() :
- mActiveMulti(NULL),
- mActiveRequestCount(0)
-{
- mProcessing = FALSE;
-}
-
-LLCurlRequest::~LLCurlRequest()
-{
- //stop all Multi handle background threads
- for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
- {
- LLCurl::getCurlThread()->killMulti(*iter) ;
- }
- mMultiSet.clear() ;
-}
-
-void LLCurlRequest::addMulti()
-{
- LLCurl::Multi* multi = new LLCurl::Multi();
- if(!multi->isValid())
- {
- LLCurl::getCurlThread()->killMulti(multi) ;
- mActiveMulti = NULL ;
- mActiveRequestCount = 0 ;
- return;
- }
-
- mMultiSet.insert(multi);
- mActiveMulti = multi;
- mActiveRequestCount = 0;
-}
-
-LLCurl::Easy* LLCurlRequest::allocEasy()
-{
- if (!mActiveMulti ||
- mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT ||
- mActiveMulti->mErrorCount > 0)
- {
- addMulti();
- }
- if(!mActiveMulti)
- {
- return NULL ;
- }
-
- //llassert_always(mActiveMulti);
- ++mActiveRequestCount;
- LLCurl::Easy* easy = mActiveMulti->allocEasy();
- return easy;
-}
-
-bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
-{
- llassert_always(mActiveMulti);
-
- if (mProcessing)
- {
- LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL;
- }
- bool res = mActiveMulti->addEasy(easy);
- return res;
-}
-
-void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
-{
- getByteRange(url, headers_t(), 0, -1, responder);
-}
-
-// Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
-// the remainder of the file if not.
-bool LLCurlRequest::getByteRange(const std::string& url,
- const headers_t& headers,
- S32 offset, S32 length,
- LLCurl::ResponderPtr responder)
-{
- llassert(LLCurl::sNotQuitting);
- LLCurl::Easy* easy = allocEasy();
- if (!easy)
- {
- return false;
- }
- easy->prepRequest(url, headers, responder);
- easy->setopt(CURLOPT_HTTPGET, 1);
- if (length > 0)
- {
- 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("bytes=%d-", offset);
- easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
- }
- easy->setHeaders();
- bool res = addEasy(easy);
- return res;
-}
-
-bool LLCurlRequest::post(const std::string& url,
- const headers_t& headers,
- const LLSD& data,
- LLCurl::ResponderPtr responder, S32 time_out)
-{
- llassert(LLCurl::sNotQuitting);
- LLCurl::Easy* easy = allocEasy();
- if (!easy)
- {
- return false;
- }
- easy->prepRequest(url, headers, responder, time_out);
-
- LLSDSerialize::toXML(data, easy->getInput());
- S32 bytes = easy->getInput().str().length();
-
- easy->setopt(CURLOPT_POST, 1);
- easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
- easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-
- easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
- easy->setHeaders();
-
- LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
- bool res = addEasy(easy);
- return res;
-}
-
-bool LLCurlRequest::post(const std::string& url,
- const headers_t& headers,
- const std::string& data,
- LLCurl::ResponderPtr responder, S32 time_out)
-{
- llassert(LLCurl::sNotQuitting);
- LLCurl::Easy* easy = allocEasy();
- if (!easy)
- {
- return false;
- }
- easy->prepRequest(url, headers, responder, time_out);
-
- easy->getInput().write(data.data(), data.size());
- S32 bytes = easy->getInput().str().length();
-
- easy->setopt(CURLOPT_POST, 1);
- easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
- easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-
- easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
- easy->setHeaders();
-
- LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
- bool res = addEasy(easy);
- return res;
-}
-
-// Note: call once per frame
-S32 LLCurlRequest::process()
-{
- S32 res = 0;
-
- mProcessing = TRUE;
- for (curlmulti_set_t::iterator iter = mMultiSet.begin();
- iter != mMultiSet.end(); )
- {
- curlmulti_set_t::iterator curiter = iter++;
- LLCurl::Multi* multi = *curiter;
-
- if(!multi->isValid())
- {
- if(multi == mActiveMulti)
- {
- mActiveMulti = NULL ;
- mActiveRequestCount = 0 ;
- }
- mMultiSet.erase(curiter) ;
- LLCurl::getCurlThread()->killMulti(multi) ;
- continue ;
- }
-
- S32 tres = multi->process();
- res += tres;
- if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
- {
- mMultiSet.erase(curiter);
- LLCurl::getCurlThread()->killMulti(multi);
- }
- }
- mProcessing = FALSE;
- return res;
-}
-
-S32 LLCurlRequest::getQueued()
-{
- S32 queued = 0;
- for (curlmulti_set_t::iterator iter = mMultiSet.begin();
- iter != mMultiSet.end(); )
- {
- curlmulti_set_t::iterator curiter = iter++;
- LLCurl::Multi* multi = *curiter;
-
- if(!multi->isValid())
- {
- if(multi == mActiveMulti)
- {
- mActiveMulti = NULL ;
- mActiveRequestCount = 0 ;
- }
- LLCurl::getCurlThread()->killMulti(multi);
- mMultiSet.erase(curiter) ;
- continue ;
- }
-
- queued += multi->mQueued;
- if (multi->getState() != LLCurl::Multi::STATE_READY)
- {
- ++queued;
- }
- }
- return queued;
-}
-
-LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :
- LLCurlRequest(),
- mConcurrency(concurrency),
- mInQueue(0),
- mMutex(NULL),
- mHandleCounter(1),
- mTotalIssuedRequests(0),
- mTotalReceivedBits(0)
-{
- mGlobalTimer.reset();
-}
-
-LLCurlTextureRequest::~LLCurlTextureRequest()
-{
- mRequestMap.clear();
-
- for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
- {
- delete *iter;
- }
- mCachedRequests.clear();
-}
-
-//return 0: success
-// > 0: cached handle
-U32 LLCurlTextureRequest::getByteRange(const std::string& url,
- const headers_t& headers,
- S32 offset, S32 length, U32 pri,
- LLCurl::ResponderPtr responder, F32 delay_time)
-{
- U32 ret_val = 0;
- bool success = false;
-
- if(mInQueue < mConcurrency && delay_time < 0.f)
- {
- success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);
- }
-
- LLMutexLock lock(&mMutex);
-
- if(success)
- {
- mInQueue++;
- mTotalIssuedRequests++;
- }
- else
- {
- request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
- if(delay_time > 0.f)
- {
- request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
- }
-
- mCachedRequests.insert(request);
- mRequestMap[mHandleCounter] = request;
- ret_val = mHandleCounter;
- mHandleCounter++;
-
- if(!mHandleCounter)
- {
- mHandleCounter = 1;
- }
- }
-
- return ret_val;
-}
-
-void LLCurlTextureRequest::completeRequest(S32 received_bytes)
-{
- LLMutexLock lock(&mMutex);
-
- llassert_always(mInQueue > 0);
-
- mInQueue--;
- mTotalReceivedBits += received_bytes * 8;
-}
-
-void LLCurlTextureRequest::nextRequests()
-{
- if(mCachedRequests.empty() || mInQueue >= mConcurrency)
- {
- return;
- }
-
- F32 cur_time = mGlobalTimer.getElapsedTimeF32();
-
- req_queue_t::iterator iter;
- {
- LLMutexLock lock(&mMutex);
- iter = mCachedRequests.begin();
- }
- while(1)
- {
- request_t* request = *iter;
- if(request->mStartTime < cur_time)
- {
- if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
- {
- break;
- }
-
- LLMutexLock lock(&mMutex);
- ++iter;
- mInQueue++;
- mTotalIssuedRequests++;
- mCachedRequests.erase(request);
- mRequestMap.erase(request->mHandle);
- delete request;
-
- if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
- {
- break;
- }
- }
- else
- {
- LLMutexLock lock(&mMutex);
- ++iter;
- if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
- {
- break;
- }
- }
- }
-
- return;
-}
-
-void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
-{
- if(!handle)
- {
- return;
- }
-
- LLMutexLock lock(&mMutex);
-
- std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
- if(iter != mRequestMap.end())
- {
- request_t* req = iter->second;
-
- if(req->mPriority != pri)
- {
- mCachedRequests.erase(req);
- req->mPriority = pri;
- mCachedRequests.insert(req);
- }
- }
-}
-
-void LLCurlTextureRequest::removeRequest(U32 handle)
-{
- if(!handle)
- {
- return;
- }
-
- LLMutexLock lock(&mMutex);
-
- std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
- if(iter != mRequestMap.end())
- {
- request_t* req = iter->second;
- mRequestMap.erase(iter);
- mCachedRequests.erase(req);
- delete req;
- }
-}
-
-bool LLCurlTextureRequest::isWaiting(U32 handle)
-{
- if(!handle)
- {
- return false;
- }
-
- LLMutexLock lock(&mMutex);
- return mRequestMap.find(handle) != mRequestMap.end();
-}
-
-U32 LLCurlTextureRequest::getTotalReceivedBits()
-{
- LLMutexLock lock(&mMutex);
-
- U32 bits = mTotalReceivedBits;
- mTotalReceivedBits = 0;
- return bits;
-}
-
-U32 LLCurlTextureRequest::getTotalIssuedRequests()
-{
- LLMutexLock lock(&mMutex);
- return mTotalIssuedRequests;
-}
-
-S32 LLCurlTextureRequest::getNumRequests()
-{
- LLMutexLock lock(&mMutex);
- return mInQueue;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// For generating one easy request
-// associated with a single multi request
-
-LLCurlEasyRequest::LLCurlEasyRequest()
- : mRequestSent(false),
- mResultReturned(false)
-{
- mMulti = new LLCurl::Multi();
-
- if(mMulti->isValid())
- {
- mEasy = mMulti->allocEasy();
- if (mEasy)
- {
- mEasy->setErrorBuffer();
- mEasy->setCA();
- // Set proxy settings if configured to do so.
- LLProxy::getInstance()->applyProxySettings(mEasy);
- }
-}
- else
- {
- LLCurl::getCurlThread()->killMulti(mMulti) ;
- mEasy = NULL ;
- mMulti = NULL ;
- }
-}
-
-LLCurlEasyRequest::~LLCurlEasyRequest()
-{
- LLCurl::getCurlThread()->killMulti(mMulti) ;
-}
-
-void LLCurlEasyRequest::setopt(CURLoption option, S32 value)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(option, value);
- }
-}
-
-void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value)
-{
- if (isValid() && mEasy)
- {
- mEasy->setoptString(option, value);
- }
-}
-
-void LLCurlEasyRequest::setPost(char* postdata, S32 size)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_POST, 1);
- mEasy->setopt(CURLOPT_POSTFIELDS, postdata);
- mEasy->setopt(CURLOPT_POSTFIELDSIZE, size);
- }
-}
-
-void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_HEADERDATA, userdata); // aka CURLOPT_WRITEHEADER
- }
-}
-
-void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_WRITEDATA, userdata);
- }
-}
-
-void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_READDATA, userdata);
- }
-}
-
-void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)
-{
- if (isValid() && mEasy)
- {
- mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);
- mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata);
- }
-}
-
-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)
- {
- mEasy->slist_append(str);
- }
-}
-
-void LLCurlEasyRequest::sendRequest(const std::string& url)
-{
- llassert_always(!mRequestSent);
- mRequestSent = true;
- LL_DEBUGS() << url << LL_ENDL;
- if (isValid() && mEasy)
- {
- mEasy->setHeaders();
- mEasy->setoptString(CURLOPT_URL, url);
- mMulti->addEasy(mEasy);
- }
-}
-
-void LLCurlEasyRequest::requestComplete()
-{
- llassert_always(mRequestSent);
- mRequestSent = false;
- if (isValid() && mEasy)
- {
- mMulti->removeEasy(mEasy);
- }
-}
-
-// Usage: Call getRestult until it returns false (no more messages)
-bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
-{
- if(!isValid())
- {
- return false ;
- }
- if (!mMulti->isCompleted())
- { //we're busy, try again later
- return false;
- }
- mMulti->setState(LLCurl::Multi::STATE_READY) ;
-
- if (!mEasy)
- {
- // Special case - we failed to initialize a curl_easy (can happen if too many open files)
- // Act as though the request failed to connect
- if (mResultReturned)
- {
- return false;
- }
- else
- {
- *result = CURLE_FAILED_INIT;
- mResultReturned = true;
- return true;
- }
- }
- // In theory, info_read might return a message with a status other than CURLMSG_DONE
- // In practice for all messages returned, msg == CURLMSG_DONE
- // Ignore other messages just in case
- while(1)
- {
- S32 q;
- CURLMsg* curlmsg = info_read(&q, info);
- if (curlmsg)
- {
- if (curlmsg->msg == CURLMSG_DONE)
- {
- *result = curlmsg->data.result;
- return true;
- }
- // else continue
- }
- else
- {
- return false;
- }
- }
-}
-
-// private
-CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info)
-{
- if (mEasy)
- {
- CURLMsg* curlmsg = mMulti->info_read(q);
- if (curlmsg && curlmsg->msg == CURLMSG_DONE)
- {
- if (info)
- {
- mEasy->getTransferInfo(info);
- }
- }
- return curlmsg;
- }
- return NULL;
-}
-
-std::string LLCurlEasyRequest::getErrorString()
-{
- return isValid() && mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-#if SAFE_SSL
-//static
-void LLCurl::ssl_locking_callback(int mode, int type, const char *file, int line)
-{
- if (mode & CRYPTO_LOCK)
- {
- LLCurl::sSSLMutex[type]->lock();
- }
- else
- {
- LLCurl::sSSLMutex[type]->unlock();
- }
-}
-
-//static
-unsigned long LLCurl::ssl_thread_id(void)
-{
- return LLThread::currentID();
-}
-#endif
-
-void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool multi_threaded)
-{
- sCurlRequestTimeOut = curl_reuest_timeout ; //seconds
- sMaxHandles = max_number_handles ; //max number of handles, (multi handles and easy handles combined).
-
- // Do not change this "unless you are familiar with and mean to control
- // internal operations of libcurl"
- // - http://curl.haxx.se/libcurl/c/curl_global_init.html
- CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
-
- check_curl_code(code);
-
-#if SAFE_SSL
- S32 mutex_count = CRYPTO_num_locks();
- for (S32 i=0; i<mutex_count; i++)
- {
- sSSLMutex.push_back(new LLMutex(NULL));
- }
- CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
- CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
-#endif
-
- sCurlThread = new LLCurlThread(multi_threaded) ;
- if(multi_threaded)
- {
- sHandleMutexp = new LLMutex(NULL) ;
- Easy::sHandleMutexp = new LLMutex(NULL) ;
- }
-}
-
-void LLCurl::cleanupClass()
-{
- sNotQuitting = false; //set quitting
-
- //shut down curl thread
- while(1)
- {
- if(!sCurlThread->update(1)) //finish all tasks
- {
- break ;
- }
- }
- LL_CHECK_MEMORY
- sCurlThread->shutdown() ;
- LL_CHECK_MEMORY
- delete sCurlThread ;
- sCurlThread = NULL ;
- LL_CHECK_MEMORY
-
-#if SAFE_SSL
- CRYPTO_set_locking_callback(NULL);
- for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
- sSSLMutex.clear();
-#endif
-
- LL_CHECK_MEMORY
- Easy::deleteAllFreeHandles();
- LL_CHECK_MEMORY
- Easy::deleteAllActiveHandles();
- LL_CHECK_MEMORY
-
- // Free the template easy handle
- curl_easy_cleanup(sCurlTemplateStandardHandle);
- sCurlTemplateStandardHandle = NULL;
- LL_CHECK_MEMORY
-
- delete Easy::sHandleMutexp ;
- Easy::sHandleMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- delete sHandleMutexp ;
- sHandleMutexp = NULL ;
-
- LL_CHECK_MEMORY
-
- // removed as per https://jira.secondlife.com/browse/SH-3115
- //llassert(Easy::sActiveHandles.empty());
-}
-
-//static
-CURLM* LLCurl::newMultiHandle()
-{
- llassert(sNotQuitting);
-
- LLMutexLock lock(sHandleMutexp) ;
-
- if(sTotalHandles + 1 > sMaxHandles)
- {
- LL_WARNS() << "no more handles available." << LL_ENDL ;
- return NULL ; //failed
- }
- sTotalHandles++;
-
- CURLM* ret = curl_multi_init() ;
- if(!ret)
- {
- LL_WARNS() << "curl_multi_init failed." << LL_ENDL ;
- }
-
- return ret ;
-}
-
-//static
-CURLMcode LLCurl::deleteMultiHandle(CURLM* handle)
-{
- if(handle)
- {
- LLMutexLock lock(sHandleMutexp) ;
- sTotalHandles-- ;
- return curl_multi_cleanup(handle) ;
- }
- return CURLM_OK ;
-}
-
-//static
-CURL* LLCurl::newEasyHandle()
-{
- llassert(sNotQuitting);
- LLMutexLock lock(sHandleMutexp) ;
-
- if(sTotalHandles + 1 > sMaxHandles)
- {
- LL_WARNS() << "no more handles available." << LL_ENDL ;
- return NULL ; //failed
- }
- sTotalHandles++;
-
- CURL* ret = createStandardCurlHandle();
- if(!ret)
- {
- LL_WARNS() << "failed to create curl handle." << LL_ENDL ;
- }
-
- return ret ;
-}
-
-//static
-void LLCurl::deleteEasyHandle(CURL* handle)
-{
- if(handle)
- {
- LLMutexLock lock(sHandleMutexp) ;
- LL_CHECK_MEMORY
- curl_easy_cleanup(handle) ;
- LL_CHECK_MEMORY
- sTotalHandles-- ;
- }
-}
-
-const unsigned int LLCurl::MAX_REDIRECTS = 5;
-
-// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
-void LLCurlFF::check_easy_code(CURLcode code)
-{
- check_curl_code(code);
-}
-void LLCurlFF::check_multi_code(CURLMcode code)
-{
- check_curl_multi_code(code);
-}
-
-
-// Static
-CURL* LLCurl::createStandardCurlHandle()
-{
- if (sCurlTemplateStandardHandle == NULL)
- { // Late creation of the template curl handle
- sCurlTemplateStandardHandle = curl_easy_init();
- if (sCurlTemplateStandardHandle == NULL)
- {
- LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL;
- }
- else
- {
- CURLcode result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_NOSIGNAL, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_NOPROGRESS, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_ENCODING, "");
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_AUTOREFERER, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_FOLLOWLOCATION, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_SSL_VERIFYPEER, 1);
- check_curl_code(result);
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_SSL_VERIFYHOST, 0);
- check_curl_code(result);
-
- // The Linksys WRT54G V5 router has an issue with frequent
- // DNS lookups from LAN machines. If they happen too often,
- // like for every HTTP request, the router gets annoyed after
- // about 700 or so requests and starts issuing TCP RSTs to
- // new connections. Reuse the DNS lookups for even a few
- // seconds and no RSTs.
- result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_code(result);
- }
- }
-
- return curl_easy_duphandle(sCurlTemplateStandardHandle);
-}
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
deleted file mode 100755
index 385d9fffa8..0000000000
--- a/indra/llmessage/llcurl.h
+++ /dev/null
@@ -1,556 +0,0 @@
-/**
- * @file llcurl.h
- * @author Zero / Donovan
- * @date 2006-10-15
- * @brief A wrapper around libcurl.
- *
- * $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_LLCURL_H
-#define LL_LLCURL_H
-
-#include "linden_common.h"
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <boost/intrusive_ptr.hpp>
-#include <curl/curl.h> // TODO: remove dependency
-
-#include "llbuffer.h"
-#include "llhttpconstants.h"
-#include "lliopipe.h"
-#include "llsd.h"
-#include "llqueuedthread.h"
-#include "llframetimer.h"
-#include "llpointer.h"
-#include "llsingleton.h"
-
-class LLMutex;
-class LLCurlThread;
-
-// For whatever reason, this is not typedef'd in curl.h
-typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
-
-class LLCurl
-{
- LOG_CLASS(LLCurl);
-
-public:
- class Easy;
- class Multi;
-
- struct TransferInfo
- {
- TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
- F64 mSizeDownload;
- F64 mTotalTime;
- F64 mSpeedDownload;
- };
-
- class Responder : public LLThreadSafeRefCount
- {
- //LOG_CLASS(Responder);
- public:
-
- Responder();
- virtual ~Responder();
-
- virtual bool followRedir()
- {
- return false;
- }
-
- /**
- * @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(
- 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
- */
-
-
- // 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:
- * httpSuccess(), or
- * httpFailure()
- */
-
- 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;
-
-
- /**
- * @ brief Set certificate authority file used to verify HTTPS certs.
- */
- static void setCAFile(const std::string& file);
-
- /**
- * @ brief Set certificate authority path used to verify HTTPS certs.
- */
- static void setCAPath(const std::string& path);
-
- /**
- * @ brief Return human-readable string describing libcurl version.
- */
- static std::string getVersionString();
-
- /**
- * @ brief Get certificate authority file used to verify HTTPS certs.
- */
- static const std::string& getCAFile() { return sCAFile; }
-
- /**
- * @ brief Get certificate authority path used to verify HTTPS certs.
- */
- static const std::string& getCAPath() { return sCAPath; }
-
- /**
- * @ brief Initialize LLCurl class
- */
- static void initClass(F32 curl_reuest_timeout = 120.f, S32 max_number_handles = 256, bool multi_threaded = false);
-
- /**
- * @ brief Cleanup LLCurl class
- */
- static void cleanupClass();
-
- /**
- * @ brief curl error code -> string
- */
- static std::string strerror(CURLcode errorcode);
-
- // For OpenSSL callbacks
- static std::vector<LLMutex*> sSSLMutex;
-
- // OpenSSL callbacks
- static void ssl_locking_callback(int mode, int type, const char *file, int line);
- static unsigned long ssl_thread_id(void);
-
- static LLCurlThread* getCurlThread() { return sCurlThread ;}
-
- static CURLM* newMultiHandle() ;
- static CURLMcode deleteMultiHandle(CURLM* handle) ;
- static CURL* newEasyHandle() ;
- static void deleteEasyHandle(CURL* handle) ;
-
- static CURL* createStandardCurlHandle();
-
-private:
- static std::string sCAPath;
- static std::string sCAFile;
- static const unsigned int MAX_REDIRECTS;
- static LLCurlThread* sCurlThread;
-
- static LLMutex* sHandleMutexp ;
- static S32 sTotalHandles ;
- static S32 sMaxHandles;
- static CURL* sCurlTemplateStandardHandle;
-public:
- static bool sNotQuitting;
- static F32 sCurlRequestTimeOut;
-};
-
-class LLCurl::Easy
-{
- LOG_CLASS(Easy);
-
-private:
- Easy();
-
-public:
- static Easy* getEasy();
- ~Easy();
-
- CURL* getCurlHandle() const { return mCurlEasyHandle; }
-
- void setErrorBuffer();
- void setCA();
-
- void setopt(CURLoption option, S32 value);
- // These assume the setter does not free value!
- void setopt(CURLoption option, void* value);
- void setopt(CURLoption option, char* value);
- // 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();
-
- 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);
-
- const char* getErrorBuffer();
-
- std::stringstream& getInput() { return mInput; }
- std::stringstream& getHeaderOutput() { return mHeaderOutput; }
- LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
- const LLChannelDescriptors& getChannels() { return mChannels; }
-
- void resetState();
-
- static CURL* allocEasyHandle();
- static void releaseEasyHandle(CURL* handle);
-
-private:
- friend class LLCurl;
- friend class LLCurl::Multi;
-
- CURL* mCurlEasyHandle;
- struct curl_slist* mHeaders;
-
- std::stringstream mRequest;
- LLChannelDescriptors mChannels;
- LLIOPipe::buffer_ptr_t mOutput;
- std::stringstream mInput;
- std::stringstream mHeaderOutput;
- char mErrorBuffer[CURL_ERROR_SIZE];
-
- // Note: char*'s not strings since we pass pointers to curl
- std::vector<char*> mStrings;
-
- LLCurl::ResponderPtr mResponder;
-
- static std::set<CURL*> sFreeHandles;
- static std::set<CURL*> sActiveHandles;
- static LLMutex* sHandleMutexp ;
-
- static void deleteAllActiveHandles();
- static void deleteAllFreeHandles();
-};
-
-class LLCurl::Multi
-{
- LOG_CLASS(Multi);
-
- friend class LLCurlThread ;
-
-private:
- ~Multi();
-
- void markDead() ;
- bool doPerform();
-
-public:
-
- typedef enum
- {
- STATE_READY=0,
- STATE_PERFORMING=1,
- STATE_COMPLETED=2
- } ePerformState;
-
- Multi(F32 idle_time_out = 0.f);
-
- LLCurl::Easy* allocEasy();
- bool addEasy(LLCurl::Easy* easy);
- void removeEasy(LLCurl::Easy* easy);
-
- void lock() ;
- void unlock() ;
-
- void setState(ePerformState state) ;
- ePerformState getState() ;
-
- bool isCompleted() ;
- bool isValid() {return mCurlMultiHandle != NULL && mValid;}
- bool isDead() {return mDead;}
-
- bool waitToComplete() ;
-
- S32 process();
-
- CURLMsg* info_read(S32* msgs_in_queue);
-
- S32 mQueued;
- S32 mErrorCount;
-
-private:
- void easyFree(LLCurl::Easy*);
- void cleanup(bool deleted = false) ;
-
- CURLM* mCurlMultiHandle;
-
- typedef std::set<LLCurl::Easy*> easy_active_list_t;
- easy_active_list_t mEasyActiveList;
- typedef std::map<CURL*, LLCurl::Easy*> easy_active_map_t;
- easy_active_map_t mEasyActiveMap;
- typedef std::set<LLCurl::Easy*> easy_free_list_t;
- easy_free_list_t mEasyFreeList;
-
- LLQueuedThread::handle_t mHandle ;
- ePerformState mState;
-
- BOOL mDead ;
- BOOL mValid ;
- LLMutex* mMutexp ;
- LLMutex* mDeletionMutexp ;
- LLMutex* mEasyMutexp ;
- LLFrameTimer mIdleTimer ;
- F32 mIdleTimeOut;
-};
-
-class LLCurlThread : public LLQueuedThread
-{
-public:
-
- class CurlRequest : public LLQueuedThread::QueuedRequest
- {
- protected:
- virtual ~CurlRequest(); // use deleteRequest()
-
- public:
- CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread);
-
- /*virtual*/ bool processRequest();
- /*virtual*/ void finishRequest(bool completed);
-
- private:
- // input
- LLCurl::Multi* mMulti;
- LLCurlThread* mCurlThread;
- };
- friend class CurlRequest;
-
-public:
- LLCurlThread(bool threaded = true) ;
- virtual ~LLCurlThread() ;
-
- S32 update(F32 max_time_ms);
-
- void addMulti(LLCurl::Multi* multi) ;
- void killMulti(LLCurl::Multi* multi) ;
-
-private:
- bool doMultiPerform(LLCurl::Multi* multi) ;
- void deleteMulti(LLCurl::Multi* multi) ;
- void cleanupMulti(LLCurl::Multi* multi) ;
-} ;
-
-
-class LLCurlRequest
-{
-public:
- typedef std::vector<std::string> headers_t;
-
- LLCurlRequest();
- ~LLCurlRequest();
-
- void get(const std::string& url, LLCurl::ResponderPtr responder);
- bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
- bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
- bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
-
- S32 process();
- S32 getQueued();
-
-private:
- void addMulti();
- LLCurl::Easy* allocEasy();
- bool addEasy(LLCurl::Easy* easy);
-
-private:
- typedef std::set<LLCurl::Multi*> curlmulti_set_t;
- curlmulti_set_t mMultiSet;
- LLCurl::Multi* mActiveMulti;
- S32 mActiveRequestCount;
- BOOL mProcessing;
-};
-
-//for texture fetch only
-class LLCurlTextureRequest : public LLCurlRequest
-{
-public:
- LLCurlTextureRequest(S32 concurrency);
- ~LLCurlTextureRequest();
-
- U32 getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder, F32 delay_time = -1.f);
- void nextRequests();
- void completeRequest(S32 received_bytes);
-
- void updatePriority(U32 handle, U32 pri);
- void removeRequest(U32 handle);
-
- U32 getTotalReceivedBits();
- U32 getTotalIssuedRequests();
- S32 getNumRequests();
- bool isWaiting(U32 handle);
-
-private:
- LLMutex mMutex;
- S32 mConcurrency;
- S32 mInQueue; //request currently in queue.
- U32 mHandleCounter;
- U32 mTotalIssuedRequests;
- U32 mTotalReceivedBits;
-
- typedef struct _request_t
- {
- _request_t(U32 handle, const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder) :
- mHandle(handle), mUrl(url), mHeaders(headers), mOffset(offset), mLength(length), mPriority(pri), mResponder(responder), mStartTime(0.f)
- {}
-
- U32 mHandle;
- std::string mUrl;
- LLCurlRequest::headers_t mHeaders;
- S32 mOffset;
- S32 mLength;
- LLCurl::ResponderPtr mResponder;
- U32 mPriority;
- F32 mStartTime; //start time to issue this request
- } request_t;
-
- struct request_compare
- {
- bool operator()(const request_t* lhs, const request_t* rhs) const
- {
- if(lhs->mPriority != rhs->mPriority)
- {
- return lhs->mPriority > rhs->mPriority; // higher priority in front of queue (set)
- }
- else
- {
- return (U32)lhs < (U32)rhs;
- }
- }
- };
-
- typedef std::set<request_t*, request_compare> req_queue_t;
- req_queue_t mCachedRequests;
- std::map<S32, request_t*> mRequestMap;
-
- LLFrameTimer mGlobalTimer;
-};
-
-class LLCurlEasyRequest
-{
-public:
- LLCurlEasyRequest();
- ~LLCurlEasyRequest();
- void setopt(CURLoption option, S32 value);
- void setoptString(CURLoption option, const std::string& value);
- void setPost(char* postdata, S32 size);
- void setHeaderCallback(curl_header_callback callback, void* userdata);
- 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();
- bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
- std::string getErrorString();
- bool isCompleted() {return mMulti->isCompleted() ;}
- bool wait() { return mMulti->waitToComplete(); }
- bool isValid() {return mMulti && mMulti->isValid(); }
-
- LLCurl::Easy* getEasy() const { return mEasy; }
-
-private:
- CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info);
-
-private:
- LLCurl::Multi* mMulti;
- LLCurl::Easy* mEasy;
- bool mRequestSent;
- bool mResultReturned;
-};
-
-// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
-namespace LLCurlFF
-{
- void check_easy_code(CURLcode code);
- void check_multi_code(CURLMcode code);
-}
-
-#endif // LL_LLCURL_H
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index 52b60a176e..92fcd38d3b 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -26,616 +26,989 @@
#include "llexperiencecache.h"
#include "llavatarname.h"
-#include "llframetimer.h"
-#include "llhttpclient.h"
#include "llsdserialize.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "lleventfilter.h"
+#include "llcoproceduremanager.h"
+#include "lldir.h"
#include <set>
#include <map>
-#include "boost/tokenizer.hpp"
+#include <boost/tokenizer.hpp>
+#include <boost/concept_check.hpp>
-
-namespace LLExperienceCache
+//=========================================================================
+namespace LLExperienceCacheImpl
{
+ void mapKeys(const LLSD& legacyKeys);
+ F64 getErrorRetryDeltaTime(S32 status, LLSD headers);
+ bool maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age);
+
+ static const std::string PRIVATE_KEY = "private_id";
+ static const std::string EXPERIENCE_ID = "public_id";
+
+ static const std::string MAX_AGE("max-age");
+ static const boost::char_separator<char> EQUALS_SEPARATOR("=");
+ static const boost::char_separator<char> COMMA_SEPARATOR(",");
+ // *TODO$: this seems to be tied to mapKeys which is used by bootstrap.... but I don't think that bootstrap is used.
typedef std::map<LLUUID, LLUUID> KeyMap;
KeyMap privateToPublicKeyMap;
+}
- void mapKeys(const LLSD& legacyKeys);
+//=========================================================================
+const std::string LLExperienceCache::PRIVATE_KEY = "private_id";
+const std::string LLExperienceCache::MISSING = "DoesNotExist";
+
+const std::string LLExperienceCache::AGENT_ID = "agent_id";
+const std::string LLExperienceCache::GROUP_ID = "group_id";
+const std::string LLExperienceCache::EXPERIENCE_ID = "public_id";
+const std::string LLExperienceCache::NAME = "name";
+const std::string LLExperienceCache::PROPERTIES = "properties";
+const std::string LLExperienceCache::EXPIRES = "expiration";
+const std::string LLExperienceCache::DESCRIPTION = "description";
+const std::string LLExperienceCache::QUOTA = "quota";
+const std::string LLExperienceCache::MATURITY = "maturity";
+const std::string LLExperienceCache::METADATA = "extended_metadata";
+const std::string LLExperienceCache::SLURL = "slurl";
+
+// should be in sync with experience-api/experiences/models.py
+const int LLExperienceCache::PROPERTY_INVALID = 1 << 0;
+const int LLExperienceCache::PROPERTY_PRIVILEGED = 1 << 3;
+const int LLExperienceCache::PROPERTY_GRID = 1 << 4;
+const int LLExperienceCache::PROPERTY_PRIVATE = 1 << 5;
+const int LLExperienceCache::PROPERTY_DISABLED = 1 << 6;
+const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7;
+
+// default values
+const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0;
+const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes
+const int LLExperienceCache::SEARCH_PAGE_SIZE = 30;
+
+//=========================================================================
+LLExperienceCache::LLExperienceCache():
+ mShutdown(false)
+{
+}
- std::string sLookupURL;
+LLExperienceCache::~LLExperienceCache()
+{
- typedef std::map<LLUUID, std::string> ask_queue_t;
- ask_queue_t sAskQueue;
+}
- typedef std::map<LLUUID, F64> pending_queue_t;
- pending_queue_t sPendingQueue;
+void LLExperienceCache::initSingleton()
+{
+ mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
- cache_t sCache;
- int sMaximumLookups = 10;
+ LL_INFOS("ExperienceCache") << "Loading " << mCacheFileName << LL_ENDL;
+ llifstream cache_stream(mCacheFileName.c_str());
- LLFrameTimer sRequestTimer;
+ if (cache_stream.is_open())
+ {
+ cache_stream >> (*this);
+ }
- // Periodically clean out expired entries from the cache
- LLFrameTimer sEraseExpiredTimer;
+ LLCoros::instance().launch("LLExperienceCache::idleCoro",
+ boost::bind(&LLExperienceCache::idleCoro, this));
- // May have multiple callbacks for a single ID, which are
- // represented as multiple slots bound to the signal.
- // Avoid copying signals via pointers.
- typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
- signal_map_t sSignalMap;
+}
+void LLExperienceCache::cleanup()
+{
+ LL_INFOS("ExperienceCache") << "Saving " << mCacheFileName << LL_ENDL;
+
+ llofstream cache_stream(mCacheFileName.c_str());
+ if (cache_stream.is_open())
+ {
+ cache_stream << (*this);
+ }
+ mShutdown = true;
+}
+//-------------------------------------------------------------------------
+void LLExperienceCache::importFile(std::istream& istr)
+{
+ LLSD data;
+ S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
+ if (parse_count < 1) return;
- bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
- void eraseExpired();
+ LLSD experiences = data["experiences"];
- void processExperience( const LLUUID& public_key, const LLSD& experience )
- {
- sCache[public_key]=experience;
- LLSD & row = sCache[public_key];
+ LLUUID public_key;
+ LLSD::map_const_iterator it = experiences.beginMap();
+ for (; it != experiences.endMap(); ++it)
+ {
+ public_key.set(it->first);
+ mCache[public_key] = it->second;
+ }
- if(row.has(EXPIRES))
- {
- row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds();
- }
+ LL_DEBUGS("ExperienceCache") << "importFile() loaded " << mCache.size() << LL_ENDL;
+}
- if(row.has(EXPERIENCE_ID))
- {
- sPendingQueue.erase(row[EXPERIENCE_ID].asUUID());
- }
+void LLExperienceCache::exportFile(std::ostream& ostr) const
+{
+ LLSD experiences;
- //signal
- signal_map_t::iterator sig_it = sSignalMap.find(public_key);
- if (sig_it != sSignalMap.end())
- {
- callback_signal_t* signal = sig_it->second;
- (*signal)(experience);
+ cache_t::const_iterator it = mCache.begin();
+ for (; it != mCache.end(); ++it)
+ {
+ if (!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() ||
+ it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID))
+ continue;
- sSignalMap.erase(public_key);
+ experiences[it->first.asString()] = it->second;
+ }
- delete signal;
- }
- }
+ LLSD data;
+ data["experiences"] = experiences;
- void initClass( )
- {
- }
+ LLSDSerialize::toPrettyXML(data, ostr);
+}
+
+// *TODO$: Rider: This method does not seem to be used... it may be useful in testing.
+void LLExperienceCache::bootstrap(const LLSD& legacyKeys, int initialExpiration)
+{
+ LLExperienceCacheImpl::mapKeys(legacyKeys);
+ LLSD::array_const_iterator it = legacyKeys.beginArray();
+ for (/**/; it != legacyKeys.endArray(); ++it)
+ {
+ LLSD experience = *it;
+ if (experience.has(EXPERIENCE_ID))
+ {
+ if (!experience.has(EXPIRES))
+ {
+ experience[EXPIRES] = initialExpiration;
+ }
+ processExperience(experience[EXPERIENCE_ID].asUUID(), experience);
+ }
+ else
+ {
+ LL_WARNS("ExperienceCache")
+ << "Skipping bootstrap entry which is missing " << EXPERIENCE_ID
+ << LL_ENDL;
+ }
+ }
+}
+
+LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found)
+{
+ if (private_key.isNull())
+ return LLUUID::null;
+
+ LLExperienceCacheImpl::KeyMap::const_iterator it = LLExperienceCacheImpl::privateToPublicKeyMap.find(private_key);
+ if (it == LLExperienceCacheImpl::privateToPublicKeyMap.end())
+ {
+ if (null_if_not_found)
+ {
+ return LLUUID::null;
+ }
+ return private_key;
+ }
+ LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL;
+ return it->second;
+}
- const cache_t& getCached()
+//=========================================================================
+void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD& experience)
+{
+ LL_INFOS("ExperienceCache") << "Processing experience \"" << experience[NAME] << "\" with key " << public_key.asString() << LL_ENDL;
+
+ mCache[public_key]=experience;
+ LLSD & row = mCache[public_key];
+
+ if(row.has(EXPIRES))
{
- return sCache;
+ row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds();
}
- void setMaximumLookups( int maximumLookups)
+ if(row.has(EXPERIENCE_ID))
{
- sMaximumLookups = maximumLookups;
+ mPendingQueue.erase(row[EXPERIENCE_ID].asUUID());
}
- void bootstrap(const LLSD& legacyKeys, int initialExpiration)
+ //signal
+ signal_map_t::iterator sig_it = mSignalMap.find(public_key);
+ if (sig_it != mSignalMap.end())
{
- mapKeys(legacyKeys);
- LLSD::array_const_iterator it = legacyKeys.beginArray();
- for(/**/; it != legacyKeys.endArray(); ++it)
- {
- LLSD experience = *it;
- if(experience.has(EXPERIENCE_ID))
- {
- if(!experience.has(EXPIRES))
- {
- experience[EXPIRES] = initialExpiration;
- }
- processExperience(experience[EXPERIENCE_ID].asUUID(), experience);
- }
- else
- {
- LL_WARNS("ExperienceCache")
- << "Skipping bootstrap entry which is missing " << EXPERIENCE_ID
- << LL_ENDL;
- }
- }
+ signal_ptr signal = sig_it->second;
+ (*signal)(experience);
+
+ mSignalMap.erase(public_key);
}
+}
+
+const LLExperienceCache::cache_t& LLExperienceCache::getCached()
+{
+ return mCache;
+}
+void LLExperienceCache::requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string url, RequestQueue_t requests)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ //LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ LLSD headers = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+ // build dummy entries for the failed requests
+ for (RequestQueue_t::const_iterator it = requests.begin(); it != requests.end(); ++it)
+ {
+ LLSD exp = get(*it);
+ //leave the properties alone if we already have a cache entry for this xp
+ if (exp.isUndefined())
+ {
+ exp[PROPERTIES] = PROPERTY_INVALID;
+ }
+ exp[EXPIRES] = now + LLExperienceCacheImpl::getErrorRetryDeltaTime(status, headers);
+ exp[EXPERIENCE_ID] = *it;
+ exp["key_type"] = EXPERIENCE_ID;
+ exp["uuid"] = *it;
+ exp["error"] = (LLSD::Integer)status.getType();
+ exp[QUOTA] = DEFAULT_QUOTA;
+
+ processExperience(*it, exp);
+ }
+ return;
+ }
+
+ LLSD experiences = result["experience_keys"];
+
+ for (LLSD::array_const_iterator it = experiences.beginArray();
+ it != experiences.endArray(); ++it)
+ {
+ const LLSD& row = *it;
+ LLUUID public_key = row[EXPERIENCE_ID].asUUID();
+
+ LL_DEBUGS("ExperienceCache") << "Received result for " << public_key
+ << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL;
+
+ processExperience(public_key, row);
+ }
+
+ LLSD error_ids = result["error_ids"];
+
+ for (LLSD::array_const_iterator errIt = error_ids.beginArray();
+ errIt != error_ids.endArray(); ++errIt)
+ {
+ LLUUID id = errIt->asUUID();
+ LLSD exp;
+ exp[EXPIRES] = DEFAULT_EXPIRATION;
+ exp[EXPERIENCE_ID] = id;
+ exp[PROPERTIES] = PROPERTY_INVALID;
+ exp[MISSING] = true;
+ exp[QUOTA] = DEFAULT_QUOTA;
+
+ processExperience(id, exp);
+ LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL;
+ }
+}
- bool expirationFromCacheControl(LLSD headers, F64 *expires)
+
+void LLExperienceCache::requestExperiences()
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ std::string urlBase = mCapability("GetExperienceInfo");
+ if (urlBase.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Experience capability." << LL_ENDL;
+ return;
+ }
+
+ if (*urlBase.rbegin() != '/')
+ {
+ urlBase += "/";
+ }
+ urlBase += "id/";
+
+
+ F64 now = LLFrameTimer::getTotalSeconds();
+
+ const U32 EXP_URL_SEND_THRESHOLD = 3000;
+ const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH;
+
+ std::ostringstream ostr;
+ ostr << urlBase << "?page_size=" << PAGE_SIZE;
+ RequestQueue_t requests;
+
+ while (!mRequestQueue.empty())
+ {
+ RequestQueue_t::iterator it = mRequestQueue.begin();
+ LLUUID key = (*it);
+ mRequestQueue.erase(it);
+ requests.insert(key);
+
+ ostr << "&" << EXPERIENCE_ID << "=" << key.asString();
+ mPendingQueue[key] = now;
+
+ if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD))
+ { // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself.
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "RequestExperiences",
+ boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, ostr.str(), requests) );
+
+ ostr.str(std::string());
+ ostr << urlBase << "?page_size=" << PAGE_SIZE;
+ requests.clear();
+ }
+ }
+
+}
+
+
+bool LLExperienceCache::isRequestPending(const LLUUID& public_key)
+{
+ bool isPending = false;
+ const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
+
+ PendingQueue_t::const_iterator it = mPendingQueue.find(public_key);
+
+ if(it != mPendingQueue.end())
{
- // Allow the header to override the default
- LLSD cache_control_header = headers["cache-control"];
- if (cache_control_header.isDefined())
- {
- S32 max_age = 0;
- std::string cache_control = cache_control_header.asString();
- if (max_age_from_cache_control(cache_control, &max_age))
- {
- LL_WARNS("ExperienceCache")
- << "got EXPIRES from headers, max_age " << max_age
- << LL_ENDL;
- F64 now = LLFrameTimer::getTotalSeconds();
- *expires = now + (F64)max_age;
- return true;
- }
- }
- return false;
+ F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
+ isPending = (it->second > expire_time);
}
+ return isPending;
+}
+
+void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t queryfn)
+{
+ mCapability = queryfn;
+}
+
+
+void LLExperienceCache::idleCoro()
+{
+ const F32 SECS_BETWEEN_REQUESTS = 0.5f;
+ const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
+
+ LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL;
+ LLEventTimeout timeout;
+
+ do
+ {
+ timeout.eventAfter(SECS_BETWEEN_REQUESTS, LLSD());
+ llcoro::suspendUntilEventOn(timeout);
+
+ if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
+ {
+ eraseExpired();
+ }
+
+ if (!mRequestQueue.empty())
+ {
+ requestExperiences();
+ }
- static const std::string MAX_AGE("max-age");
- static const boost::char_separator<char> EQUALS_SEPARATOR("=");
- static const boost::char_separator<char> COMMA_SEPARATOR(",");
+ } while (!mShutdown);
- bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age)
+ // The coroutine system will likely be shut down by the time we get to this point
+ // (or at least no further cycling will occur on it since the user has decided to quit.)
+}
+
+void LLExperienceCache::erase(const LLUUID& key)
+{
+ cache_t::iterator it = mCache.find(key);
+
+ if(it != mCache.end())
{
- // Split the string on "," to get a list of directives
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- tokenizer directives(cache_control, COMMA_SEPARATOR);
+ mCache.erase(it);
+ }
+}
- tokenizer::iterator token_it = directives.begin();
- for ( ; token_it != directives.end(); ++token_it)
- {
- // Tokens may have leading or trailing whitespace
- std::string token = *token_it;
- LLStringUtil::trim(token);
+void LLExperienceCache::eraseExpired()
+{
+ F64 now = LLFrameTimer::getTotalSeconds();
+ cache_t::iterator it = mCache.begin();
+ while (it != mCache.end())
+ {
+ cache_t::iterator cur = it;
+ LLSD& exp = cur->second;
+ ++it;
+
+ //LL_INFOS("ExperienceCache") << "Testing experience \"" << exp[NAME] << "\" with exp time " << exp[EXPIRES].asReal() << "(now = " << now << ")" << LL_ENDL;
- if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0)
+ if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now)
+ {
+ if(!exp.has(EXPERIENCE_ID))
{
- // ...this token starts with max-age, so let's chop it up by "="
- tokenizer subtokens(token, EQUALS_SEPARATOR);
- tokenizer::iterator subtoken_it = subtokens.begin();
-
- // Must have a token
- if (subtoken_it == subtokens.end()) return false;
- std::string subtoken = *subtoken_it;
-
- // Must exactly equal "max-age"
- LLStringUtil::trim(subtoken);
- if (subtoken != MAX_AGE) return false;
-
- // Must have another token
- ++subtoken_it;
- if (subtoken_it == subtokens.end()) return false;
- subtoken = *subtoken_it;
-
- // Must be a valid integer
- // *NOTE: atoi() returns 0 for invalid values, so we have to
- // check the string first.
- // *TODO: Do servers ever send "0000" for zero? We don't handle it
- LLStringUtil::trim(subtoken);
- if (subtoken == "0")
+ LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ;
+ mCache.erase(cur);
+ }
+ else
+ {
+ LLUUID id = exp[EXPERIENCE_ID].asUUID();
+ LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null;
+ if(private_key.notNull() || !exp.has("DoesNotExist"))
{
- *max_age = 0;
- return true;
+ fetch(id, true);
}
- S32 val = atoi( subtoken.c_str() );
- if (val > 0 && val < S32_MAX)
+ else
{
- *max_age = val;
- return true;
+ LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ;
+ mCache.erase(cur);
}
- return false;
}
}
- return false;
}
-
-
- void importFile(std::istream& istr)
+}
+
+bool LLExperienceCache::fetch(const LLUUID& key, bool refresh/* = true*/)
+{
+ if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end()))
{
- LLSD data;
- S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
- if(parse_count < 1) return;
-
- LLSD experiences = data["experiences"];
-
- LLUUID public_key;
- LLSD::map_const_iterator it = experiences.beginMap();
- for(; it != experiences.endMap() ; ++it)
- {
- public_key.set(it->first);
- sCache[public_key]=it->second;
- }
+ LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL;
- LL_DEBUGS("ExperienceCache") << "importFile() loaded " << sCache.size() << LL_ENDL;
+ mRequestQueue.insert(key);
+ return true;
}
+ return false;
+}
- void exportFile(std::ostream& ostr)
+void LLExperienceCache::insert(const LLSD& experience_data)
+{
+ if(experience_data.has(EXPERIENCE_ID))
{
- LLSD experiences;
-
- cache_t::const_iterator it =sCache.begin();
- for( ; it != sCache.end() ; ++it)
- {
- if(!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() ||
- it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID))
- continue;
-
- experiences[it->first.asString()] = it->second;
- }
+ processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data);
+ }
+ else
+ {
+ LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL;
+ }
+}
- LLSD data;
- data["experiences"] = experiences;
+const LLSD& LLExperienceCache::get(const LLUUID& key)
+{
+ static const LLSD empty;
+
+ if(key.isNull())
+ return empty;
+ cache_t::const_iterator it = mCache.find(key);
- LLSDSerialize::toPrettyXML(data, ostr);
+ if (it != mCache.end())
+ {
+ return it->second;
}
+ fetch(key);
- class LLExperienceResponder : public LLHTTPClient::Responder
- {
- public:
- LLExperienceResponder(const ask_queue_t& keys)
- :mKeys(keys)
- {
+ return empty;
+}
- }
+void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::ExperienceGetFn_t slot)
+{
+ if(key.isNull())
+ return;
- /*virtual*/ void httpCompleted()
- {
- LLSD experiences = getContent()["experience_keys"];
- LLSD::array_const_iterator it = experiences.beginArray();
- for( /**/ ; it != experiences.endArray(); ++it)
- {
- const LLSD& row = *it;
- LLUUID public_key = row[EXPERIENCE_ID].asUUID();
+ cache_t::const_iterator it = mCache.find(key);
+ if (it != mCache.end())
+ {
+ // ...name already exists in cache, fire callback now
+ callback_signal_t signal;
+ signal.connect(slot);
+
+ signal(it->second);
+ return;
+ }
+ fetch(key);
- LL_DEBUGS("ExperienceCache") << "Received result for " << public_key
- << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL ;
+ signal_ptr signal = signal_ptr(new callback_signal_t());
+
+ std::pair<signal_map_t::iterator, bool> result = mSignalMap.insert(signal_map_t::value_type(key, signal));
+ if (!result.second)
+ signal = (*result.first).second;
+ signal->connect(slot);
+}
- processExperience(public_key, row);
- }
+//=========================================================================
+void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Fetch Associated",
+ boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, objectId, itemId, fn));
+}
- LLSD error_ids = getContent()["error_ids"];
- LLSD::array_const_iterator errIt = error_ids.beginArray();
- for( /**/ ; errIt != error_ids.endArray() ; ++errIt )
- {
- LLUUID id = errIt->asUUID();
- LLSD exp;
- exp[EXPIRES]=DEFAULT_EXPIRATION;
- exp[EXPERIENCE_ID] = id;
- exp[PROPERTIES]=PROPERTY_INVALID;
- exp[MISSING]=true;
- exp[QUOTA] = DEFAULT_QUOTA;
-
- processExperience(id, exp);
- LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL ;
- }
+void LLExperienceCache::fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID objectId, LLUUID itemId, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+ std::string url = mCapability("GetMetadata");
+
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL;
+ return;
+ }
+
+ LLSD fields;
+ fields.append("experience");
+ LLSD data;
+ data["object-id"] = objectId;
+ data["item-id"] = itemId;
+ data["fields"] = fields;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, data);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if ((!status) || (!result.has("experience")))
+ {
+ LLSD failure;
+ if (!status)
+ {
+ failure["error"] = (LLSD::Integer)status.getType();
+ failure["message"] = status.getMessage();
+ }
+ else
+ {
+ failure["error"] = -1;
+ failure["message"] = "no experience";
+ }
+ if (fn && !fn.empty())
+ fn(failure);
+ return;
+ }
+
+ LLUUID expId = result["experience"].asUUID();
+ get(expId, fn);
+}
- LL_DEBUGS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL;
- }
+//-------------------------------------------------------------------------
+void LLExperienceCache::findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Search Name",
+ boost::bind(&LLExperienceCache::findExperienceByNameCoro, this, _1, text, page, fn));
+}
- /*virtual*/ void httpFailure()
- {
- LL_WARNS("ExperienceCache") << "Request failed "<<getStatus()<<" "<<getReason()<< LL_ENDL;
- // We're going to construct a dummy record and cache it for a while,
- // either briefly for a 503 Service Unavailable, or longer for other
- // errors.
- F64 retry_timestamp = errorRetryTimestamp(getStatus());
-
-
- // Add dummy records for all agent IDs in this request
- ask_queue_t::const_iterator it = mKeys.begin();
- for ( ; it != mKeys.end(); ++it)
- {
+void LLExperienceCache::findExperienceByNameCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, std::string text, int page, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+ std::ostringstream url;
- LLSD exp = get(it->first);
- //leave the properties alone if we already have a cache entry for this xp
- if(exp.isUndefined())
- {
- exp[PROPERTIES]=PROPERTY_INVALID;
- }
- exp[EXPIRES]=retry_timestamp;
- exp[EXPERIENCE_ID] = it->first;
- exp["key_type"] = it->second;
- exp["uuid"] = it->first;
- exp["error"] = (LLSD::Integer)getStatus();
- exp[QUOTA] = DEFAULT_QUOTA;
-
- LLExperienceCache::processExperience(it->first, exp);
- }
- }
+ url << mCapability("FindExperienceByName") << "?page=" << page << "&page_size=" << SEARCH_PAGE_SIZE << "&query=" << LLURI::escape(text);
- // Return time to retry a request that generated an error, based on
- // error type and headers. Return value is seconds-since-epoch.
- F64 errorRetryTimestamp(S32 status)
- {
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url.str());
- // Retry-After takes priority
- LLSD retry_after = getResponseHeaders()["retry-after"];
- if (retry_after.isDefined())
- {
- // We only support the delta-seconds type
- S32 delta_seconds = retry_after.asInteger();
- if (delta_seconds > 0)
- {
- // ...valid delta-seconds
- return F64(delta_seconds);
- }
- }
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- // If no Retry-After, look for Cache-Control max-age
- F64 expires = 0.0;
- if (LLExperienceCache::expirationFromCacheControl(getResponseHeaders(), &expires))
- {
- return expires;
- }
+ if (!status)
+ {
+ fn(LLSD());
+ return;
+ }
- // No information in header, make a guess
- if (status == 503)
- {
- // ...service unavailable, retry soon
- const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
- return SERVICE_UNAVAILABLE_DELAY;
- }
- else if (status == 499)
- {
- // ...we were probably too busy, retry quickly
- const F64 BUSY_DELAY = 10.0; // 10 seconds
- return BUSY_DELAY;
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
- }
- else
- {
- // ...other unexpected error
- const F64 DEFAULT_DELAY = 3600.0; // 1 hour
- return DEFAULT_DELAY;
- }
- }
+ const LLSD& experiences = result["experience_keys"];
+ for (LLSD::array_const_iterator it = experiences.beginArray(); it != experiences.endArray(); ++it)
+ {
+ insert(*it);
+ }
- private:
- ask_queue_t mKeys;
- };
+ fn(result);
+}
- void requestExperiences()
- {
- if(sAskQueue.empty() || sLookupURL.empty())
- return;
+//-------------------------------------------------------------------------
+void LLExperienceCache::getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Group Experiences",
+ boost::bind(&LLExperienceCache::getGroupExperiencesCoro, this, _1, groupId, fn));
+}
- F64 now = LLFrameTimer::getTotalSeconds();
+void LLExperienceCache::getGroupExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID groupId, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
- const U32 EXP_URL_SEND_THRESHOLD = 3000;
- const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD/UUID_STR_LENGTH;
+ // search for experiences owned by the current group
+ std::string url = mCapability("GroupExperiences");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Group Experiences capability" << LL_ENDL;
+ return;
+ }
- std::ostringstream ostr;
+ url += "?" + groupId.asString();
- ask_queue_t keys;
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
- ostr << sLookupURL << "?page_size=" << PAGE_SIZE;
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ fn(LLSD());
+ return;
+ }
- int request_count = 0;
- while(!sAskQueue.empty() && request_count < sMaximumLookups)
- {
- ask_queue_t::iterator it = sAskQueue.begin();
- const LLUUID& key = it->first;
- const std::string& key_type = it->second;
+ const LLSD& experienceIds = result["experience_ids"];
+ fn(experienceIds);
+}
- ostr << '&' << key_type << '=' << key.asString() ;
-
- keys[key]=key_type;
- request_count++;
+//-------------------------------------------------------------------------
+void LLExperienceCache::getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn)
+{
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Region Experiences",
+ boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, regioncaps, false, LLSD(), fn));
+}
- sPendingQueue[key] = now;
-
- if(ostr.tellp() > EXP_URL_SEND_THRESHOLD)
- {
- LL_DEBUGS("ExperienceCache") << "requestExperiences() query: " << ostr.str() << LL_ENDL;
- LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
- ostr.clear();
- ostr.str(sLookupURL);
- ostr << "?page_size=" << PAGE_SIZE;
- keys.clear();
- }
- sAskQueue.erase(it);
- }
+void LLExperienceCache::setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn)
+{
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Region Experiences",
+ boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, regioncaps, true, experiences, fn));
+}
- if(ostr.tellp() > sLookupURL.size())
- {
- LL_DEBUGS("ExperienceCache") << "requestExperiences() query 2: " << ostr.str() << LL_ENDL;
- LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
- }
- }
+void LLExperienceCache::regionExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter,
+ CapabilityQuery_t regioncaps, bool update, LLSD experiences, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+
+ // search for experiences owned by the current group
+ std::string url = regioncaps("RegionExperiences");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
+ return;
+ }
+
+ LLSD result;
+ if (update)
+ result = httpAdapter->postAndSuspend(httpRequest, url, experiences);
+ else
+ result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+// fn(LLSD());
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ fn(result);
- bool isRequestPending(const LLUUID& public_key)
- {
- bool isPending = false;
- const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
+}
- pending_queue_t::const_iterator it = sPendingQueue.find(public_key);
+//-------------------------------------------------------------------------
+void LLExperienceCache::getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString();
+
+ permissionInvoker_fn invoker(boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, LLCore::HttpOptions::ptr_t(), LLCore::HttpHeaders::ptr_t()));
+
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Preferences Set",
+ boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, invoker, url, fn));
+}
- if(it != sPendingQueue.end())
- {
- F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
- isPending = (it->second > expire_time);
- }
+void LLExperienceCache::setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ std::string url = mCapability("ExperiencePreferences");
+ if (url.empty())
+ return;
+ LLSD permData;
+ LLSD data;
+ permData["permission"] = permission;
+ data[experienceId.asString()] = permData;
+
+ permissionInvoker_fn invoker(boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndSuspend), _1, _2, _3, data, LLCore::HttpOptions::ptr_t(), LLCore::HttpHeaders::ptr_t()));
+
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Preferences Set",
+ boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, invoker, url, fn));
+}
- return isPending;
- }
+void LLExperienceCache::forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+ std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString();
- void setLookupURL( const std::string& lookup_url )
- {
- sLookupURL = lookup_url;
- if(!sLookupURL.empty())
- {
- sLookupURL += "id/";
- }
- }
- bool hasLookupURL()
- {
- return !sLookupURL.empty();
- }
+ permissionInvoker_fn invoker(boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, LLCore::HttpOptions::ptr_t(), LLCore::HttpHeaders::ptr_t()));
- void idle()
- {
- const F32 SECS_BETWEEN_REQUESTS = 0.1f;
- if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
- {
- return;
- }
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "Preferences Set",
+ boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, invoker, url, fn));
+}
- // Must be large relative to above
- const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
- if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
- {
- eraseExpired();
- }
+void LLExperienceCache::experiencePermissionCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, permissionInvoker_fn invokerfn, std::string url, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+ // search for experiences owned by the current group
- if(!sAskQueue.empty())
- {
- requestExperiences();
- }
- }
+ LLSD result = invokerfn(httpAdapter, httpRequest, url);
- void erase( const LLUUID& key )
- {
- cache_t::iterator it = sCache.find(key);
-
- if(it != sCache.end())
- {
- sCache.erase(it);
- }
- }
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
- void eraseExpired()
- {
- F64 now = LLFrameTimer::getTotalSeconds();
- cache_t::iterator it = sCache.begin();
- while (it != sCache.end())
- {
- cache_t::iterator cur = it;
- LLSD& exp = cur->second;
- ++it;
+ if (status)
+ {
+ fn(result);
+ }
+}
- if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now)
- {
- if(!exp.has(EXPERIENCE_ID))
- {
- LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ;
- sCache.erase(cur);
- }
- else
- {
- LLUUID id = exp[EXPERIENCE_ID].asUUID();
- LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null;
- if(private_key.notNull() || !exp.has("DoesNotExist"))
- {
- fetch(id, true);
- }
- else
- {
- LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ;
- sCache.erase(cur);
- }
- }
- }
- }
- }
+//-------------------------------------------------------------------------
+void LLExperienceCache::getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "IsAdmin",
+ boost::bind(&LLExperienceCache::getExperienceAdminCoro, this, _1, experienceId, fn));
+}
-
- bool fetch( const LLUUID& key, bool refresh/* = true*/ )
- {
- if(!key.isNull() && !isRequestPending(key) && (refresh || sCache.find(key)==sCache.end()))
- {
- LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL ;
- sAskQueue[key]=EXPERIENCE_ID;
+void LLExperienceCache::getExperienceAdminCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID experienceId, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
- return true;
- }
- return false;
- }
+ std::string url = mCapability("IsExperienceAdmin");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
+ return;
+ }
+ url += "?experience_id=" + experienceId.asString();
- void insert(const LLSD& experience_data )
- {
- if(experience_data.has(EXPERIENCE_ID))
- {
- processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data);
- }
- else
- {
- LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL;
- }
- }
- static LLSD empty;
- const LLSD& get(const LLUUID& key)
- {
- if(key.isNull()) return empty;
- cache_t::const_iterator it = sCache.find(key);
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+// LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+// LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- if (it != sCache.end())
- {
- return it->second;
- }
+ fn(result);
+}
- fetch(key);
+//-------------------------------------------------------------------------
+void LLExperienceCache::updateExperience(LLSD updateData, ExperienceGetFn_t fn)
+{
+ if (mCapability.empty())
+ {
+ LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
+ return;
+ }
+
+ LLCoprocedureManager::instance().enqueueCoprocedure("ExpCache", "IsAdmin",
+ boost::bind(&LLExperienceCache::updateExperienceCoro, this, _1, updateData, fn));
+}
- return empty;
- }
- void get( const LLUUID& key, callback_slot_t slot )
- {
- if(key.isNull()) return;
+void LLExperienceCache::updateExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLSD updateData, ExperienceGetFn_t fn)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
- cache_t::const_iterator it = sCache.find(key);
- if (it != sCache.end())
- {
- // ...name already exists in cache, fire callback now
- callback_signal_t signal;
- signal.connect(slot);
-
- signal(it->second);
- return;
- }
+ std::string url = mCapability("UpdateExperience");
+ if (url.empty())
+ {
+ LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
+ return;
+ }
- fetch(key);
+ updateData.erase(LLExperienceCache::QUOTA);
+ updateData.erase(LLExperienceCache::EXPIRES);
+ updateData.erase(LLExperienceCache::AGENT_ID);
- // always store additional callback, even if request is pending
- signal_map_t::iterator sig_it = sSignalMap.find(key);
- if (sig_it == sSignalMap.end())
- {
- // ...new callback for this id
- callback_signal_t* signal = new callback_signal_t();
- signal->connect(slot);
- sSignalMap[key] = signal;
- }
- else
- {
- // ...existing callback, bind additional slot
- callback_signal_t* signal = sig_it->second;
- signal->connect(slot);
- }
- }
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, updateData);
+ fn(result);
}
-
-void LLExperienceCache::mapKeys( const LLSD& legacyKeys )
+//=========================================================================
+void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys)
{
LLSD::array_const_iterator exp = legacyKeys.beginArray();
- for(/**/ ; exp != legacyKeys.endArray() ; ++exp)
+ for (/**/; exp != legacyKeys.endArray(); ++exp)
{
- if(exp->has(LLExperienceCache::EXPERIENCE_ID) && exp->has(LLExperienceCache::PRIVATE_KEY))
+ if (exp->has(LLExperienceCacheImpl::EXPERIENCE_ID) && exp->has(LLExperienceCacheImpl::PRIVATE_KEY))
{
- privateToPublicKeyMap[(*exp)[LLExperienceCache::PRIVATE_KEY].asUUID()]=(*exp)[LLExperienceCache::EXPERIENCE_ID].asUUID();
+ LLExperienceCacheImpl::privateToPublicKeyMap[(*exp)[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] =
+ (*exp)[LLExperienceCacheImpl::EXPERIENCE_ID].asUUID();
}
}
}
-
-LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found)
+// Return time to retry a request that generated an error, based on
+// error type and headers. Return value is seconds-since-epoch.
+F64 LLExperienceCacheImpl::getErrorRetryDeltaTime(S32 status, LLSD headers)
{
- if (private_key.isNull())
- return LLUUID::null;
- KeyMap::const_iterator it=privateToPublicKeyMap.find(private_key);
- if(it == privateToPublicKeyMap.end())
+ // Retry-After takes priority
+ LLSD retry_after = headers["retry-after"];
+ if (retry_after.isDefined())
+ {
+ // We only support the delta-seconds type
+ S32 delta_seconds = retry_after.asInteger();
+ if (delta_seconds > 0)
+ {
+ // ...valid delta-seconds
+ return F64(delta_seconds);
+ }
+ }
+
+ // If no Retry-After, look for Cache-Control max-age
+ // Allow the header to override the default
+ LLSD cache_control_header = headers["cache-control"];
+ if (cache_control_header.isDefined())
+ {
+ S32 max_age = 0;
+ std::string cache_control = cache_control_header.asString();
+ if (LLExperienceCacheImpl::maxAgeFromCacheControl(cache_control, &max_age))
+ {
+ LL_WARNS("ExperienceCache")
+ << "got EXPIRES from headers, max_age " << max_age
+ << LL_ENDL;
+ return (F64)max_age;
+ }
+ }
+
+ // No information in header, make a guess
+ if (status == 503)
+ {
+ // ...service unavailable, retry soon
+ const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
+ return SERVICE_UNAVAILABLE_DELAY;
+ }
+ else if (status == 499)
+ {
+ // ...we were probably too busy, retry quickly
+ const F64 BUSY_DELAY = 10.0; // 10 seconds
+ return BUSY_DELAY;
+
+ }
+ else
+ {
+ // ...other unexpected error
+ const F64 DEFAULT_DELAY = 3600.0; // 1 hour
+ return DEFAULT_DELAY;
+ }
+}
+
+bool LLExperienceCacheImpl::maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age)
+{
+ // Split the string on "," to get a list of directives
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ tokenizer directives(cache_control, COMMA_SEPARATOR);
+
+ tokenizer::iterator token_it = directives.begin();
+ for ( ; token_it != directives.end(); ++token_it)
{
- if(null_if_not_found)
+ // Tokens may have leading or trailing whitespace
+ std::string token = *token_it;
+ LLStringUtil::trim(token);
+
+ if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0)
{
- return LLUUID::null;
+ // ...this token starts with max-age, so let's chop it up by "="
+ tokenizer subtokens(token, EQUALS_SEPARATOR);
+ tokenizer::iterator subtoken_it = subtokens.begin();
+
+ // Must have a token
+ if (subtoken_it == subtokens.end()) return false;
+ std::string subtoken = *subtoken_it;
+
+ // Must exactly equal "max-age"
+ LLStringUtil::trim(subtoken);
+ if (subtoken != MAX_AGE) return false;
+
+ // Must have another token
+ ++subtoken_it;
+ if (subtoken_it == subtokens.end()) return false;
+ subtoken = *subtoken_it;
+
+ // Must be a valid integer
+ // *NOTE: atoi() returns 0 for invalid values, so we have to
+ // check the string first.
+ // *TODO: Do servers ever send "0000" for zero? We don't handle it
+ LLStringUtil::trim(subtoken);
+ if (subtoken == "0")
+ {
+ *max_age = 0;
+ return true;
+ }
+ S32 val = atoi( subtoken.c_str() );
+ if (val > 0 && val < S32_MAX)
+ {
+ *max_age = val;
+ return true;
+ }
+ return false;
}
- return private_key;
}
- LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL;
- return it->second;
+ return false;
}
+
+
+
+
diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h
index e669ee888e..1002b33f80 100644
--- a/indra/llmessage/llexperiencecache.h
+++ b/indra/llmessage/llexperiencecache.h
@@ -30,75 +30,155 @@
#define LL_LLEXPERIENCECACHE_H
#include "linden_common.h"
+#include "llsingleton.h"
+#include "llframetimer.h"
+#include "llsd.h"
+#include "llcorehttputil.h"
#include <boost/signals2.hpp>
+#include <boost/function.hpp>
class LLSD;
class LLUUID;
-
-namespace LLExperienceCache
+class LLExperienceCache: public LLSingleton < LLExperienceCache >
{
- const std::string PRIVATE_KEY = "private_id";
- const std::string MISSING = "DoesNotExist";
-
- const std::string AGENT_ID = "agent_id";
- const std::string GROUP_ID = "group_id";
- const std::string EXPERIENCE_ID = "public_id";
- const std::string NAME = "name";
- const std::string PROPERTIES = "properties";
- const std::string EXPIRES = "expiration";
- const std::string DESCRIPTION = "description";
- const std::string QUOTA = "quota";
- const std::string MATURITY = "maturity";
- const std::string METADATA = "extended_metadata";
- const std::string SLURL = "slurl";
-
-
- // should be in sync with experience-api/experiences/models.py
- const int PROPERTY_INVALID = 1 << 0;
- const int PROPERTY_PRIVILEGED = 1 << 3;
- const int PROPERTY_GRID = 1 << 4;
- const int PROPERTY_PRIVATE = 1 << 5;
- const int PROPERTY_DISABLED = 1 << 6;
- const int PROPERTY_SUSPENDED = 1 << 7;
-
-
- // default values
- const static F64 DEFAULT_EXPIRATION = 600.0;
- const static S32 DEFAULT_QUOTA = 128; // this is megabytes
-
- // Callback types for get() below
- typedef boost::signals2::signal<void (const LLSD& experience)>
- callback_signal_t;
- typedef callback_signal_t::slot_type callback_slot_t;
+ friend class LLSingleton < LLExperienceCache > ;
+
+public:
+ typedef boost::function<std::string(const std::string &)> CapabilityQuery_t;
+ typedef boost::function<void(const LLSD &)> ExperienceGetFn_t;
+
+ void setCapabilityQuery(CapabilityQuery_t queryfn);
+ void cleanup();
+
+ //-------------------------------------------
+ // Cache methods
+ void erase(const LLUUID& key);
+ bool fetch(const LLUUID& key, bool refresh = false);
+ void insert(const LLSD& experience_data);
+ const LLSD& get(const LLUUID& key);
+ void get(const LLUUID& key, ExperienceGetFn_t slot); // If name information is in cache, callback will be called immediately.
+
+ bool isRequestPending(const LLUUID& public_key);
+
+ //-------------------------------------------
+ void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn);
+ void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn);
+ void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn);
+
+ // the Get/Set Region Experiences take a CapabilityQuery to get the capability since
+ // the region being queried may not be the region that the agent is standing on.
+ void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn);
+ void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn);
+
+ void getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
+ void setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn);
+ void forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
+
+ void getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn);
+
+ void updateExperience(LLSD updateData, ExperienceGetFn_t fn);
+ //-------------------------------------------
+ static const std::string NAME; // "name"
+ static const std::string EXPERIENCE_ID; // "public_id"
+ static const std::string AGENT_ID; // "agent_id"
+ static const std::string GROUP_ID; // "group_id"
+ static const std::string PROPERTIES; // "properties"
+ static const std::string EXPIRES; // "expiration"
+ static const std::string DESCRIPTION; // "description"
+ static const std::string QUOTA; // "quota"
+ static const std::string MATURITY; // "maturity"
+ static const std::string METADATA; // "extended_metadata"
+ static const std::string SLURL; // "slurl"
+
+ static const std::string MISSING; // "DoesNotExist"
+
+ // should be in sync with experience-api/experiences/models.py
+ static const int PROPERTY_INVALID; // 1 << 0
+ static const int PROPERTY_PRIVILEGED; // 1 << 3
+ static const int PROPERTY_GRID; // 1 << 4
+ static const int PROPERTY_PRIVATE; // 1 << 5
+ static const int PROPERTY_DISABLED; // 1 << 6
+ static const int PROPERTY_SUSPENDED; // 1 << 7
+
+private:
+ LLExperienceCache();
+ virtual ~LLExperienceCache();
+
+ virtual void initSingleton();
+
+ typedef boost::function<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLCore::HttpRequest::ptr_t, std::string)> permissionInvoker_fn;
+
+ // Callback types for get()
+ typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t;
+ typedef boost::shared_ptr<callback_signal_t> signal_ptr;
+ // May have multiple callbacks for a single ID, which are
+ // represented as multiple slots bound to the signal.
+ // Avoid copying signals via pointers.
+ typedef std::map<LLUUID, signal_ptr> signal_map_t;
typedef std::map<LLUUID, LLSD> cache_t;
-
-
- void setLookupURL(const std::string& lookup_url);
- bool hasLookupURL();
-
- void setMaximumLookups(int maximumLookups);
-
- void idle();
- void exportFile(std::ostream& ostr);
- void importFile(std::istream& istr);
- void initClass();
- void bootstrap(const LLSD& legacyKeys, int initialExpiration);
- void erase(const LLUUID& key);
- bool fetch(const LLUUID& key, bool refresh=false);
- void insert(const LLSD& experience_data);
- const LLSD& get(const LLUUID& key);
-
- // If name information is in cache, callback will be called immediately.
- void get(const LLUUID& key, callback_slot_t slot);
+ typedef std::set<LLUUID> RequestQueue_t;
+ typedef std::map<LLUUID, F64> PendingQueue_t;
+ //--------------------------------------------
+ static const std::string PRIVATE_KEY; // "private_id"
+
+ // default values
+ static const F64 DEFAULT_EXPIRATION; // 600.0
+ static const S32 DEFAULT_QUOTA; // 128 this is megabytes
+ static const int SEARCH_PAGE_SIZE;
+
+//--------------------------------------------
+ void processExperience(const LLUUID& public_key, const LLSD& experience);
+
+//--------------------------------------------
+ cache_t mCache;
+ signal_map_t mSignalMap;
+ RequestQueue_t mRequestQueue;
+ PendingQueue_t mPendingQueue;
+
+ LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache
+ CapabilityQuery_t mCapability;
+ std::string mCacheFileName;
+ bool mShutdown;
+
+ void idleCoro();
+ void eraseExpired();
+ void requestExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, RequestQueue_t);
+ void requestExperiences();
+
+ void fetchAssociatedExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID, LLUUID, ExperienceGetFn_t);
+ void findExperienceByNameCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, std::string, int, ExperienceGetFn_t);
+ void getGroupExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLUUID , ExperienceGetFn_t);
+ void regionExperiencesCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, CapabilityQuery_t regioncaps, bool update, LLSD experiences, ExperienceGetFn_t fn);
+ void experiencePermissionCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, permissionInvoker_fn invokerfn, std::string url, ExperienceGetFn_t fn);
+ void getExperienceAdminCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLUUID experienceId, ExperienceGetFn_t fn);
+ void updateExperienceCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, LLSD updateData, ExperienceGetFn_t fn);
+
+ void bootstrap(const LLSD& legacyKeys, int initialExpiration);
+ void exportFile(std::ostream& ostr) const;
+ void importFile(std::istream& istr);
+
+ //
const cache_t& getCached();
// maps an experience private key to the experience id
LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false);
+ //=====================================================================
+ inline friend std::ostream &operator << (std::ostream &os, const LLExperienceCache &cache)
+ {
+ cache.exportFile(os);
+ return os;
+ }
+
+ inline friend std::istream &operator >> (std::istream &is, LLExperienceCache &cache)
+ {
+ cache.importFile(is);
+ return is;
+ }
};
#endif // LL_LLEXPERIENCECACHE_H
diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp
index 63c15f0d5e..ae5c2ecf69 100755
--- a/indra/llmessage/llhost.cpp
+++ b/indra/llmessage/llhost.cpp
@@ -41,8 +41,6 @@
#include <arpa/inet.h>
#endif
-LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
-
LLHost::LLHost(const std::string& ip_and_port)
{
std::string::size_type colon_index = ip_and_port.find(":");
diff --git a/indra/llmessage/llhost.h b/indra/llmessage/llhost.h
index 0cf52a4151..79cad4b123 100755
--- a/indra/llmessage/llhost.h
+++ b/indra/llmessage/llhost.h
@@ -40,9 +40,8 @@ class LLHost {
protected:
U32 mPort;
U32 mIP;
+ std::string mUntrustedSimCap;
public:
-
- static LLHost invalid;
// CREATORS
LLHost()
@@ -89,13 +88,17 @@ public:
// READERS
U32 getAddress() const { return mIP; }
U32 getPort() const { return mPort; }
- BOOL isOk() const { return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); }
+ bool isOk() const { return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); }
+ bool isInvalid() { return (mIP == INVALID_HOST_IP_ADDRESS) || (mPort == INVALID_PORT); }
size_t hash() const { return (mIP << 16) | (mPort & 0xffff); }
std::string getString() const;
std::string getIPString() const;
std::string getHostName() const;
std::string getIPandPort() const;
+ std::string getUntrustedSimulatorCap() const { return mUntrustedSimCap; }
+ void setUntrustedSimulatorCap(const std::string &capurl) { mUntrustedSimCap = capurl; }
+
friend std::ostream& operator<< (std::ostream& os, const LLHost &hh);
// This operator is not well defined. does it expect a
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
deleted file mode 100755
index e202154445..0000000000
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ /dev/null
@@ -1,1454 +0,0 @@
-/**
- * @file llhttpassetstorage.cpp
- * @brief Subclass capable of loading asset data to/from an external
- * source. Currently, a web server accessed via curl
- *
- * $LicenseInfo:firstyear=2003&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 "llhttpassetstorage.h"
-
-#include <sys/stat.h>
-
-#include "indra_constants.h"
-#include "message.h"
-#include "llproxy.h"
-#include "llvfile.h"
-#include "llvfs.h"
-#include "llxfer.h"
-
-#ifdef LL_USESYSTEMLIBS
-# include <zlib.h>
-#else
-# include "zlib/zlib.h"
-#endif
-
-const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset";
-
-const U32 MAX_RUNNING_REQUESTS = 1;
-
-// Try for 30 minutes for now.
-const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f;
-
-const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096;
-
-/////////////////////////////////////////////////////////////////////////////////
-// LLTempAssetData
-// An asset not stored on central asset store, but on a simulator node somewhere.
-/////////////////////////////////////////////////////////////////////////////////
-struct LLTempAssetData
-{
- LLUUID mAssetID;
- LLUUID mAgentID;
- std::string mHostName;
-};
-
-/////////////////////////////////////////////////////////////////////////////////
-// LLHTTPAssetRequest
-/////////////////////////////////////////////////////////////////////////////////
-
-class LLHTTPAssetRequest : public LLAssetRequest
-{
-public:
- LLHTTPAssetRequest(LLHTTPAssetStorage *asp, const LLUUID &uuid,
- LLAssetType::EType type, LLAssetStorage::ERequestType rt,
- const std::string& url, CURLM *curl_multi);
- virtual ~LLHTTPAssetRequest();
-
- void setupCurlHandle();
- void cleanupCurlHandle();
-
- void prepareCompressedUpload();
- void finishCompressedUpload();
- size_t readCompressedData(void* data, size_t size);
-
- static size_t curlCompressedUploadCallback(
- void *data, size_t size, size_t nmemb, void *user_data);
-
- virtual LLSD getTerseDetails() const;
- virtual LLSD getFullDetails() const;
-
-public:
- LLHTTPAssetStorage *mAssetStoragep;
-
- CURL *mCurlHandle;
- CURLM *mCurlMultiHandle;
- std::string mURLBuffer;
- struct curl_slist *mHTTPHeaders;
- LLVFile *mVFile;
- LLUUID mTmpUUID;
- LLAssetStorage::ERequestType mRequestType;
-
- bool mZInitialized;
- z_stream mZStream;
- char* mZInputBuffer;
- bool mZInputExhausted;
-
- FILE *mFP;
-};
-
-
-LLHTTPAssetRequest::LLHTTPAssetRequest(LLHTTPAssetStorage *asp,
- const LLUUID &uuid,
- LLAssetType::EType type,
- LLAssetStorage::ERequestType rt,
- const std::string& url,
- CURLM *curl_multi)
- : LLAssetRequest(uuid, type),
- mZInitialized(false)
-{
- memset(&mZStream, 0, sizeof(mZStream)); // we'll initialize this later, but for now zero the whole C-style struct to avoid debug/coverity noise
- mAssetStoragep = asp;
- mCurlHandle = NULL;
- mCurlMultiHandle = curl_multi;
- mVFile = NULL;
- mRequestType = rt;
- mHTTPHeaders = NULL;
- mFP = NULL;
- mZInputBuffer = NULL;
- mZInputExhausted = false;
-
- mURLBuffer = url;
-}
-
-LLHTTPAssetRequest::~LLHTTPAssetRequest()
-{
- // Cleanup/cancel the request
- if (mCurlHandle)
- {
- curl_multi_remove_handle(mCurlMultiHandle, mCurlHandle);
- cleanupCurlHandle();
- }
- if (mHTTPHeaders)
- {
- curl_slist_free_all(mHTTPHeaders);
- }
- delete mVFile;
- finishCompressedUpload();
-}
-
-// virtual
-LLSD LLHTTPAssetRequest::getTerseDetails() const
-{
- LLSD sd = LLAssetRequest::getTerseDetails();
-
- sd["url"] = mURLBuffer;
-
- return sd;
-}
-
-// virtual
-LLSD LLHTTPAssetRequest::getFullDetails() const
-{
- LLSD sd = LLAssetRequest::getFullDetails();
-
- if (mCurlHandle)
- {
- long curl_response = -1;
- long curl_connect = -1;
- double curl_total_time = -1.0f;
- double curl_size_upload = -1.0f;
- double curl_size_download = -1.0f;
- double curl_content_length_upload = -1.0f;
- double curl_content_length_download = -1.0f;
- long curl_request_size = -1;
- const char* curl_content_type = NULL;
-
- curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CODE, &curl_response);
- curl_easy_getinfo(mCurlHandle, CURLINFO_HTTP_CONNECTCODE, &curl_connect);
- curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &curl_total_time);
- curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_UPLOAD, &curl_size_upload);
- curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &curl_size_download);
- curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_UPLOAD, &curl_content_length_upload);
- curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &curl_content_length_download);
- curl_easy_getinfo(mCurlHandle, CURLINFO_REQUEST_SIZE, &curl_request_size);
- curl_easy_getinfo(mCurlHandle, CURLINFO_CONTENT_TYPE, &curl_content_type);
-
- sd["curl_response_code"] = (int) curl_response;
- sd["curl_http_connect_code"] = (int) curl_connect;
- sd["curl_total_time"] = curl_total_time;
- sd["curl_size_upload"] = curl_size_upload;
- sd["curl_size_download"] = curl_size_download;
- sd["curl_content_length_upload"] = curl_content_length_upload;
- sd["curl_content_length_download"] = curl_content_length_download;
- sd["curl_request_size"] = (int) curl_request_size;
- if (curl_content_type)
- {
- sd["curl_content_type"] = curl_content_type;
- }
- else
- {
- sd["curl_content_type"] = "";
- }
- }
-
- sd["temp_id"] = mTmpUUID;
- sd["request_type"] = LLAssetStorage::getRequestName(mRequestType);
- sd["z_initialized"] = mZInitialized;
- sd["z_input_exhausted"] = mZInputExhausted;
-
- S32 file_size = -1;
- if (mFP)
- {
- struct stat file_stat;
- int file_desc = fileno(mFP);
- if ( fstat(file_desc, &file_stat) == 0)
- {
- file_size = file_stat.st_size;
- }
- }
- sd["file_size"] = file_size;
-
- return sd;
-}
-
-
-void LLHTTPAssetRequest::setupCurlHandle()
-{
- // *NOTE: Similar code exists in mapserver/llcurlutil.cpp JC
- mCurlHandle = LLCurl::newEasyHandle();
- llassert_always(mCurlHandle != NULL) ;
-
- // Apply proxy settings if configured to do so
- LLProxy::getInstance()->applyProxySettings(mCurlHandle);
-
- curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
- curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt(mCurlHandle, CURLOPT_URL, mURLBuffer.c_str());
- curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
- if (LLAssetStorage::RT_DOWNLOAD == mRequestType)
- {
- curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
- // only do this on downloads, as uploads
- // to some apache configs (like our test grids)
- // mistakenly claim the response is gzip'd if the resource
- // name ends in .gz, even though in a PUT, the response is
- // just plain HTML saying "created"
- }
- /* Remove the Pragma: no-cache header that libcurl inserts by default;
- we want the cached version, if possible. */
- if (mZInitialized)
- {
- curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, "");
- // disable use of proxy, which can't handle chunked transfers
- }
- mHTTPHeaders = curl_slist_append(mHTTPHeaders, "Pragma:");
-
- // bug in curl causes DNS to be cached for too long a time, 0 sets it to never cache DNS results internally (to curl)
- curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
-
- // resist the temptation to explicitly add the Transfer-Encoding: chunked
- // header here - invokes a libCURL bug
- curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mHTTPHeaders);
- if (mAssetStoragep)
- {
- // Set the appropriate pending upload or download flag
- mAssetStoragep->addRunningRequest(mRequestType, this);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetRequest::setupCurlHandle - No asset storage associated with this request!" << LL_ENDL;
- }
-}
-
-void LLHTTPAssetRequest::cleanupCurlHandle()
-{
- LLCurl::deleteEasyHandle(mCurlHandle);
- if (mAssetStoragep)
- {
- // Terminating a request. Thus upload or download is no longer pending.
- mAssetStoragep->removeRunningRequest(mRequestType, this);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetRequest::~LLHTTPAssetRequest - No asset storage associated with this request!" << LL_ENDL;
- }
- mCurlHandle = NULL;
-}
-
-void LLHTTPAssetRequest::prepareCompressedUpload()
-{
- mZStream.next_in = Z_NULL;
- mZStream.avail_in = 0;
- mZStream.zalloc = Z_NULL;
- mZStream.zfree = Z_NULL;
- mZStream.opaque = Z_NULL;
-
- int r = deflateInit2(&mZStream,
- 1, // compression level
- Z_DEFLATED, // the only method defined
- 15 + 16, // the default windowBits + gzip header flag
- 8, // the default memLevel
- Z_DEFAULT_STRATEGY);
-
- if (r != Z_OK)
- {
- LL_ERRS() << "LLHTTPAssetRequest::prepareCompressedUpload defalateInit2() failed" << LL_ENDL;
- }
-
- mZInitialized = true;
- mZInputBuffer = new char[COMPRESSED_INPUT_BUFFER_SIZE];
- mZInputExhausted = false;
-
- mVFile = new LLVFile(gAssetStorage->mVFS,
- getUUID(), getType(), LLVFile::READ);
-}
-
-void LLHTTPAssetRequest::finishCompressedUpload()
-{
- if (mZInitialized)
- {
- LL_INFOS() << "LLHTTPAssetRequest::finishCompressedUpload: "
- << "read " << mZStream.total_in << " byte asset file, "
- << "uploaded " << mZStream.total_out << " byte compressed asset"
- << LL_ENDL;
-
- deflateEnd(&mZStream);
- delete[] mZInputBuffer;
- }
-}
-
-size_t LLHTTPAssetRequest::readCompressedData(void* data, size_t size)
-{
- llassert(mZInitialized);
-
- mZStream.next_out = (Bytef*)data;
- mZStream.avail_out = size;
-
- while (mZStream.avail_out > 0)
- {
- if (mZStream.avail_in == 0 && !mZInputExhausted)
- {
- S32 to_read = llmin(COMPRESSED_INPUT_BUFFER_SIZE,
- (S32)(mVFile->getSize() - mVFile->tell()));
-
- if ( to_read > 0 )
- {
- mVFile->read((U8*)mZInputBuffer, to_read); /*Flawfinder: ignore*/
- mZStream.next_in = (Bytef*)mZInputBuffer;
- mZStream.avail_in = mVFile->getLastBytesRead();
- }
-
- mZInputExhausted = mZStream.avail_in == 0;
- }
-
- int r = deflate(&mZStream,
- mZInputExhausted ? Z_FINISH : Z_NO_FLUSH);
-
- if (r == Z_STREAM_END || r < 0 || mZInputExhausted)
- {
- if (r < 0)
- {
- LL_WARNS() << "LLHTTPAssetRequest::readCompressedData: deflate returned error code "
- << (S32) r << LL_ENDL;
- }
- break;
- }
- }
-
- return size - mZStream.avail_out;
-}
-
-//static
-size_t LLHTTPAssetRequest::curlCompressedUploadCallback(
- void *data, size_t size, size_t nmemb, void *user_data)
-{
- size_t num_read = 0;
-
- if (gAssetStorage)
- {
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
- if (req)
- {
- num_read = req->readCompressedData(data, size * nmemb);
- }
- }
-
- return num_read;
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-// LLHTTPAssetStorage
-/////////////////////////////////////////////////////////////////////////////////
-
-
-LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, LLVFS *static_vfs,
- const LLHost &upstream_host,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name)
- : LLAssetStorage(msg, xfer, vfs, static_vfs, upstream_host)
-{
- _init(web_host, local_web_host, host_name);
-}
-
-LLHTTPAssetStorage::LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs,
- LLVFS *static_vfs,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name)
- : LLAssetStorage(msg, xfer, vfs, static_vfs)
-{
- _init(web_host, local_web_host, host_name);
-}
-
-void LLHTTPAssetStorage::_init(const std::string& web_host, const std::string& local_web_host, const std::string& host_name)
-{
- mBaseURL = web_host;
- mLocalBaseURL = local_web_host;
- mHostName = host_name;
-
- // curl_global_init moved to LLCurl::initClass()
-
- mCurlMultiHandle = LLCurl::newMultiHandle() ;
- llassert_always(mCurlMultiHandle != NULL) ;
-}
-
-LLHTTPAssetStorage::~LLHTTPAssetStorage()
-{
- LLCurl::deleteMultiHandle(mCurlMultiHandle);
- mCurlMultiHandle = NULL;
-
- // curl_global_cleanup moved to LLCurl::initClass()
-}
-
-// storing data is simpler than getting it, so we just overload the whole method
-void LLHTTPAssetStorage::storeAssetData(
- const LLUUID& uuid,
- LLAssetType::EType type,
- LLAssetStorage::LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file,
- bool is_priority,
- bool store_local,
- const LLUUID& requesting_agent_id,
- bool user_waiting,
- F64Seconds timeout)
-{
- if (mVFS->getExists(uuid, type)) // VFS treats nonexistant and zero-length identically
- {
- LLAssetRequest *req = new LLAssetRequest(uuid, type);
- req->mUpCallback = callback;
- req->mUserData = user_data;
- req->mRequestingAgentID = requesting_agent_id;
- req->mIsUserWaiting = user_waiting;
- req->mTimeout = timeout;
-
- // LLAssetStorage metric: Successful Request
- S32 size = mVFS->getSize(uuid, type);
- const char *message;
- if( store_local )
- {
- message = "Added to local upload queue";
- }
- else
- {
- message = "Added to upload queue";
- }
- reportMetric( uuid, type, LLStringUtil::null, requesting_agent_id, size, MR_OKAY, __FILE__, __LINE__, message );
-
- // this will get picked up and transmitted in checkForTimeouts
- if(store_local)
- {
- mPendingLocalUploads.push_back(req);
- }
- else if(is_priority)
- {
- mPendingUploads.push_front(req);
- }
- else
- {
- mPendingUploads.push_back(req);
- }
- }
- else
- {
- LL_WARNS() << "AssetStorage: attempt to upload non-existent vfile " << uuid << ":" << LLAssetType::lookup(type) << LL_ENDL;
- if (callback)
- {
- // LLAssetStorage metric: Zero size VFS
- reportMetric( uuid, type, LLStringUtil::null, requesting_agent_id, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" );
- callback(uuid, user_data, LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE, LL_EXSTAT_NONEXISTENT_FILE);
- }
- }
-}
-
-// virtual
-void LLHTTPAssetStorage::storeAssetData(
- const std::string& filename,
- const LLUUID& asset_id,
- LLAssetType::EType asset_type,
- LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file,
- bool is_priority,
- bool user_waiting,
- F64Seconds timeout)
-{
- LL_INFOS() << "LLAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL;
-
- LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;
-
- legacy->mUpCallback = callback;
- legacy->mUserData = user_data;
-
- FILE *fp = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
- S32 size = 0;
- if (fp)
- {
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- }
-
- if( size )
- {
- LLVFile file(mVFS, asset_id, asset_type, LLVFile::WRITE);
-
- file.setMaxSize(size);
-
- const S32 buf_size = 65536;
- U8 copy_buf[buf_size];
- while ((size = (S32)fread(copy_buf, 1, buf_size, fp)))
- {
- file.write(copy_buf, size);
- }
- fclose(fp);
-
- // if this upload fails, the caller needs to setup a new tempfile for us
- if (temp_file)
- {
- LLFile::remove(filename);
- }
-
- // LLAssetStorage metric: Success not needed; handled in the overloaded method here:
- storeAssetData(
- asset_id,
- asset_type,
- legacyStoreDataCallback,
- (void**)legacy,
- temp_file,
- is_priority,
- false,
- LLUUID::null,
- user_waiting,
- timeout);
- }
- else // !size
- {
- if( fp )
- {
- // LLAssetStorage metric: Zero size
- reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" );
- fclose( fp );
- }
- else
- {
- // LLAssetStorage metric: Missing File
- reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_FILE_NONEXIST, __FILE__, __LINE__, "The file didn't exist" );
- }
- if (callback)
- {
- callback(LLUUID::null, user_data, LL_ERR_CANNOT_OPEN_FILE, LL_EXSTAT_BLOCKED_FILE);
- }
- delete legacy;
- }
-}
-
-// virtual
-LLSD LLHTTPAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt,
- LLAssetType::EType asset_type,
- const std::string& detail_prefix) const
-{
- LLSD sd = LLAssetStorage::getPendingDetails(rt, asset_type, detail_prefix);
- const request_list_t* running = getRunningList(rt);
- if (running)
- {
- // Loop through the pending requests sd, and add extra info about its running status.
- S32 num_pending = sd["requests"].size();
- S32 i;
- for (i = 0; i < num_pending; ++i)
- {
- LLSD& pending = sd["requests"][i];
- // See if this pending request is running.
- const LLAssetRequest* req = findRequest(running,
- LLAssetType::lookup(pending["type"].asString()),
- pending["asset_id"]);
- if (req)
- {
- // Keep the detail_url so we don't have to rebuild it.
- LLURI detail_url = pending["detail"];
- pending = req->getTerseDetails();
- pending["detail"] = detail_url;
- pending["is_running"] = true;
- }
- else
- {
- pending["is_running"] = false;
- }
- }
- }
- return sd;
-}
-
-// virtual
-LLSD LLHTTPAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id) const
-{
- // Look for this asset in the running list first.
- const request_list_t* running = getRunningList(rt);
- if (running)
- {
- LLSD sd = LLAssetStorage::getPendingRequestImpl(running, asset_type, asset_id);
- if (sd)
- {
- sd["is_running"] = true;
- return sd;
- }
- }
- LLSD sd = LLAssetStorage::getPendingRequest(rt, asset_type, asset_id);
- if (sd)
- {
- sd["is_running"] = false;
- }
- return sd;
-}
-
-// virtual
-bool LLHTTPAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id)
-{
- // Try removing this from the running list first.
- request_list_t* running = getRunningList(rt);
- if (running)
- {
- LLAssetRequest* req = findRequest(running, asset_type, asset_id);
- if (req)
- {
- // Remove this request from the running list to get it out of curl.
- running->remove(req);
-
- // Find this request in the pending list, so we can move it to the end of the line.
- request_list_t* pending = getRequestList(rt);
- if (pending)
- {
- request_list_t::iterator result = std::find_if(pending->begin(), pending->end(),
- std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req));
- if (pending->end() != result)
- {
- // This request was found in the pending list. Move it to the end!
- LLAssetRequest* pending_req = *result;
- pending->remove(pending_req);
-
- if (!pending_req->mIsUserWaiting) //A user is waiting on this request. Toss it.
- {
- pending->push_back(pending_req);
- }
- else
- {
- if (pending_req->mUpCallback) //Clean up here rather than _callUploadCallbacks because this request is already cleared the req.
- {
- pending_req->mUpCallback(pending_req->getUUID(), pending_req->mUserData, -1, LL_EXSTAT_REQUEST_DROPPED);
- }
-
- }
-
- LL_INFOS() << "Asset " << getRequestName(rt) << " request for "
- << asset_id << "." << LLAssetType::lookup(asset_type)
- << " removed from curl and placed at the end of the pending queue."
- << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Unable to find pending " << getRequestName(rt) << " request for "
- << asset_id << "." << LLAssetType::lookup(asset_type) << LL_ENDL;
- }
- }
- delete req;
-
- return true;
- }
- }
- return LLAssetStorage::deletePendingRequest(rt, asset_type, asset_id);
-}
-
-// internal requester, used by getAssetData in superclass
-void LLHTTPAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
- void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
- void *user_data, BOOL duplicate,
- BOOL is_priority)
-{
- // stash the callback info so we can find it after we get the response message
- LLAssetRequest *req = new LLAssetRequest(uuid, type);
- req->mDownCallback = callback;
- req->mUserData = user_data;
- req->mIsPriority = is_priority;
-
- // this will get picked up and downloaded in checkForTimeouts
-
- //
- // HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACK! Asset requests were taking too long and timing out.
- // Since texture requests are the LEAST sensitive (on the simulator) to being delayed, add
- // non-texture requests to the front, and add texture requests to the back. The theory is
- // that we always want them first, even if they're out of order.
- //
-
- if (req->getType() == LLAssetType::AT_TEXTURE)
- {
- mPendingDownloads.push_back(req);
- }
- else
- {
- mPendingDownloads.push_front(req);
- }
-}
-
-LLAssetRequest* LLHTTPAssetStorage::findNextRequest(LLAssetStorage::request_list_t& pending,
- LLAssetStorage::request_list_t& running)
-{
- // Early exit if the running list is full, or we don't have more pending than running.
- if (running.size() >= MAX_RUNNING_REQUESTS
- || pending.size() <= running.size()) return NULL;
-
- // Look for the first pending request that is not already running.
- request_list_t::iterator running_begin = running.begin();
- request_list_t::iterator running_end = running.end();
-
- request_list_t::iterator pending_iter = pending.begin();
-
- // Loop over all pending requests until we miss finding it in the running list.
- for (; pending_iter != pending.end(); ++pending_iter)
- {
- LLAssetRequest* req = *pending_iter;
- // Look for this pending request in the running list.
- if (running_end == std::find_if(running_begin, running_end,
- std::bind2nd(ll_asset_request_equal<LLAssetRequest*>(), req)))
- {
- // It isn't running! Return it.
- return req;
- }
- }
- return NULL;
-}
-
-// overloaded to additionally move data to/from the webserver
-void LLHTTPAssetStorage::checkForTimeouts()
-{
- CURLMcode mcode;
- LLAssetRequest *req;
- while ( (req = findNextRequest(mPendingDownloads, mRunningDownloads)) )
- {
- // Setup this curl download request
- // We need to generate a new request here
- // since the one in the list could go away
- std::string tmp_url;
- std::string uuid_str;
- req->getUUID().toString(uuid_str);
- std::string base_url = getBaseURL(req->getUUID(), req->getType());
- tmp_url = llformat("%s/%36s.%s", base_url.c_str() , uuid_str.c_str(), LLAssetType::lookup(req->getType()));
-
- LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
- req->getType(), RT_DOWNLOAD, tmp_url, mCurlMultiHandle);
- new_req->mTmpUUID.generate();
-
- // Sets pending download flag internally
- new_req->setupCurlHandle();
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle);
-
- mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
- if (mcode > CURLM_OK)
- {
- // Failure. Deleting the pending request will remove it from the running
- // queue, and push it to the end of the pending queue.
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_DOWNLOAD, new_req->getType(), new_req->getUUID());
- break;
- }
- else
- {
- LL_INFOS() << "Requesting " << new_req->mURLBuffer << LL_ENDL;
- }
- }
-
- while ( (req = findNextRequest(mPendingUploads, mRunningUploads)) )
- {
- // setup this curl upload request
-
- bool do_compress = req->getType() == LLAssetType::AT_OBJECT;
-
- std::string tmp_url;
- std::string uuid_str;
- req->getUUID().toString(uuid_str);
- tmp_url = mBaseURL + "/" + uuid_str + "." + LLAssetType::lookup(req->getType());
- if (do_compress) tmp_url += ".gz";
-
- LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
- req->getType(), RT_UPLOAD, tmp_url, mCurlMultiHandle);
-
- if (req->mIsUserWaiting) //If a user is waiting on a realtime response, we want to perserve information across upload attempts.
- {
- new_req->mTime = req->mTime;
- new_req->mTimeout = req->mTimeout;
- new_req->mIsUserWaiting = req->mIsUserWaiting;
- }
-
- if (do_compress)
- {
- new_req->prepareCompressedUpload();
- }
-
- // Sets pending upload flag internally
- new_req->setupCurlHandle();
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_UPLOAD, 1);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
-
- if (do_compress)
- {
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
- &LLHTTPAssetRequest::curlCompressedUploadCallback);
- }
- else
- {
- LLVFile file(mVFS, req->getUUID(), req->getType());
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
- &curlUpCallback);
- }
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
-
- mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
- if (mcode > CURLM_OK)
- {
- // Failure. Deleting the pending request will remove it from the running
- // queue, and push it to the end of the pending queue.
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
- break;
- }
- else
- {
- // Get the uncompressed file size.
- LLVFile file(mVFS,new_req->getUUID(),new_req->getType());
- S32 size = file.getSize();
- LL_INFOS() << "Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << LL_ENDL;
- if (size == 0)
- {
- LL_WARNS() << "Rejecting zero size PUT request!" << LL_ENDL;
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
- }
- }
- // Pending upload will have been flagged by the request
- }
-
- while ( (req = findNextRequest(mPendingLocalUploads, mRunningLocalUploads)) )
- {
- // setup this curl upload request
- LLVFile file(mVFS, req->getUUID(), req->getType());
-
- std::string tmp_url;
- std::string uuid_str;
- req->getUUID().toString(uuid_str);
-
- // KLW - All temporary uploads are saved locally "http://localhost:12041/asset"
- tmp_url = llformat("%s/%36s.%s", mLocalBaseURL.c_str(), uuid_str.c_str(), LLAssetType::lookup(req->getType()));
-
- LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(),
- req->getType(), RT_LOCALUPLOAD, tmp_url, mCurlMultiHandle);
- new_req->mRequestingAgentID = req->mRequestingAgentID;
-
- // Sets pending upload flag internally
- new_req->setupCurlHandle();
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_PUT, 1);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback);
- curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
-
- mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
- if (mcode > CURLM_OK)
- {
- // Failure. Deleting the pending request will remove it from the running
- // queue, and push it to the end of the pending queue.
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_LOCALUPLOAD, new_req->getType(), new_req->getUUID());
- break;
- }
- else
- {
- // Get the uncompressed file size.
- S32 size = file.getSize();
-
- LL_INFOS() << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!"
- << " Requesting PUT " << new_req->mURLBuffer << ", asset size: " << size << " bytes" << LL_ENDL;
- if (size == 0)
- {
-
- LL_WARNS() << "Rejecting zero size PUT request!" << LL_ENDL;
- new_req->cleanupCurlHandle();
- deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
- }
-
- }
- // Pending upload will have been flagged by the request
- }
- S32 count = 0;
- int queue_length;
- do
- {
- mcode = curl_multi_perform(mCurlMultiHandle, &queue_length);
- count++;
- } while (mcode == CURLM_CALL_MULTI_PERFORM && (count < 5));
-
- CURLMsg *curl_msg;
- do
- {
- curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
- if (curl_msg && curl_msg->msg == CURLMSG_DONE)
- {
- long curl_result = 0;
- S32 xfer_result = LL_ERR_NOERR;
-
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req);
-
- // TODO: Throw curl_result at all callbacks.
- curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
- if (RT_UPLOAD == req->mRequestType || RT_LOCALUPLOAD == req->mRequestType)
- {
- if (curl_msg->data.result == CURLE_OK &&
- ( curl_result == HTTP_OK
- || curl_result == HTTP_CREATED
- || curl_result == HTTP_NO_CONTENT))
- {
- LL_INFOS() << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << LL_ENDL;
- if (RT_LOCALUPLOAD == req->mRequestType)
- {
- addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName);
- }
- }
- else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||
- curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
- curl_result == HTTP_BAD_GATEWAY ||
- curl_result == HTTP_SERVICE_UNAVAILABLE)
- {
- LL_WARNS() << "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 << LL_ENDL;
-
- ////HACK (probably) I am sick of this getting requeued and driving me mad.
- //if (req->mIsUserWaiting)
- //{
- // deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
- //}
- }
- else
- {
- LL_WARNS() << "Failure uploading " << req->getUUID() << " to " << req->mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
-
- xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
- }
-
- if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||
- curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
- curl_result == HTTP_BAD_GATEWAY ||
- curl_result == HTTP_SERVICE_UNAVAILABLE))
- {
- // shared upload finished callback
- // in the base class, this is called from processUploadComplete
- _callUploadCallbacks(req->getUUID(), req->getType(), (xfer_result == 0), LL_EXSTAT_CURL_RESULT | curl_result);
- // Pending upload flag will get cleared when the request is deleted
- }
- }
- else if (RT_DOWNLOAD == req->mRequestType)
- {
- if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
- {
- if (req->mVFile && req->mVFile->getSize() > 0)
- {
- LL_INFOS() << "Success downloading " << req->mURLBuffer << ", size " << req->mVFile->getSize() << LL_ENDL;
-
- req->mVFile->rename(req->getUUID(), req->getType());
- }
- else
- {
- // *TODO: if this actually indicates a bad asset on the server
- // (not certain at this point), then delete it
- LL_WARNS() << "Found " << req->mURLBuffer << " to be zero size" << LL_ENDL;
- xfer_result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
- }
- }
- else
- {
- // KLW - TAT See if an avatar owns this texture, and if so request re-upload.
- LL_WARNS() << "Failure downloading " << req->mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
-
- xfer_result = (curl_result == HTTP_NOT_FOUND) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
-
- if (req->mVFile)
- {
- req->mVFile->remove();
- }
- }
-
- // call the static callback for transfer completion
- // this will cleanup all requests for this asset, including ours
- downloadCompleteCallback(
- xfer_result,
- req->getUUID(),
- req->getType(),
- (void *)req,
- LL_EXSTAT_CURL_RESULT | curl_result);
- // Pending download flag will get cleared when the request is deleted
- }
- else
- {
- // nothing, just axe this request
- // currently this can only mean an asset delete
- }
-
- // Deleting clears the pending upload/download flag if it's set and the request is transferring
- delete req;
- req = NULL;
- }
-
- } while (curl_msg && queue_length > 0);
-
-
- // Cleanup
- // We want to bump to the back of the line any running uploads that have timed out.
- bumpTimedOutUploads();
-
- LLAssetStorage::checkForTimeouts();
-}
-
-void LLHTTPAssetStorage::bumpTimedOutUploads()
-{
- bool user_waiting=FALSE;
-
- F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds();
-
- if (mPendingUploads.size())
- {
- request_list_t::iterator it = mPendingUploads.begin();
- LLAssetRequest* req = *it;
- user_waiting=req->mIsUserWaiting;
- }
-
- // No point bumping currently running uploads if there are no others in line.
- if (!(mPendingUploads.size() > mRunningUploads.size()) && !user_waiting)
- {
- return;
- }
-
- // deletePendingRequest will modify the mRunningUploads list so we don't want to iterate over it.
- request_list_t temp_running = mRunningUploads;
-
- request_list_t::iterator it = temp_running.begin();
- request_list_t::iterator end = temp_running.end();
- for ( ; it != end; ++it)
- {
- //request_list_t::iterator curiter = iter++;
- LLAssetRequest* req = *it;
-
- if ( req->mTimeout < (mt_secs - req->mTime) )
- {
- LL_WARNS() << "Asset upload request timed out for "
- << req->getUUID() << "."
- << LLAssetType::lookup(req->getType())
- << ", bumping to the back of the line!" << LL_ENDL;
-
- deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
- }
- }
-}
-
-// static
-size_t LLHTTPAssetStorage::curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- if (!gAssetStorage)
- {
- LL_WARNS() << "Missing gAssetStorage, aborting curl download callback!" << LL_ENDL;
- return 0;
- }
- S32 bytes = (S32)(size * nmemb);
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
-
- if (! req->mVFile)
- {
- req->mVFile = new LLVFile(gAssetStorage->mVFS, req->mTmpUUID, LLAssetType::AT_NONE, LLVFile::APPEND);
- }
-
- double content_length = 0.0;
- curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &content_length);
-
- // sanitize content_length, reconcile w/ actual data
- S32 file_length = llmax(0, (S32)llmin(content_length, 20000000.0), bytes + req->mVFile->getSize());
-
- req->mVFile->setMaxSize(file_length);
- req->mVFile->write((U8*)data, bytes);
-
- return nmemb;
-}
-
-// static
-size_t LLHTTPAssetStorage::curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- if (!gAssetStorage)
- {
- LL_WARNS() << "Missing gAssetStorage, aborting curl download callback!" << LL_ENDL;
- return 0;
- }
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
-
- if (! req->mVFile)
- {
- req->mVFile = new LLVFile(gAssetStorage->mVFS, req->getUUID(), req->getType(), LLVFile::READ);
- }
-
- S32 bytes = llmin((S32)(size * nmemb), (S32)(req->mVFile->getSize() - req->mVFile->tell()));
-
- req->mVFile->read((U8*)data, bytes);/*Flawfinder: ignore*/
-
- return req->mVFile->getLastBytesRead();
-}
-
-// static
-size_t LLHTTPAssetStorage::nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- // do nothing, this is here to soak up script output so it doesn't end up on stdout
-
- return nmemb;
-}
-
-
-
-// blocking asset fetch which bypasses the VFS
-// this is a very limited function for use by the simstate loader and other one-offs
-S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const std::string &url, const std::string& filename, progress_callback callback, void *userdata)
-{
- // *NOTE: There is no guarantee that the uuid and the asset_type match
- // - not that it matters. - Doug
- LL_DEBUGS() << "LLHTTPAssetStorage::getURLToFile() - " << url << LL_ENDL;
-
- FILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/
- if (! fp)
- {
- LL_WARNS() << "Failed to open " << filename << " for writing" << LL_ENDL;
- return LL_ERR_ASSET_REQUEST_FAILED;
- }
-
- // make sure we use the normal curl setup, even though we don't really need a request object
- LLHTTPAssetRequest req(this, uuid, asset_type, RT_DOWNLOAD, url, mCurlMultiHandle);
- req.mFP = fp;
-
- req.setupCurlHandle();
- curl_easy_setopt(req.mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
- curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEFUNCTION, &curlFileDownCallback);
- curl_easy_setopt(req.mCurlHandle, CURLOPT_WRITEDATA, req.mCurlHandle);
-
- curl_multi_add_handle(mCurlMultiHandle, req.mCurlHandle);
- LL_INFOS() << "Requesting as file " << req.mURLBuffer << LL_ENDL;
-
- // braindead curl loop
- int queue_length;
- CURLMsg *curl_msg;
- LLTimer timeout;
- timeout.setTimerExpirySec(GET_URL_TO_FILE_TIMEOUT);
- bool success = false;
- S32 xfer_result = 0;
- do
- {
- curl_multi_perform(mCurlMultiHandle, &queue_length);
- curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
-
- if (callback)
- {
- callback(userdata);
- }
-
- if ( curl_msg && (CURLMSG_DONE == curl_msg->msg) )
- {
- success = true;
- }
- else if (timeout.hasExpired())
- {
- LL_WARNS() << "Request for " << url << " has timed out." << LL_ENDL;
- success = false;
- xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
- break;
- }
- } while (!success);
-
- if (success)
- {
- long curl_result = 0;
- curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
-
- if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
- {
- S32 size = ftell(req.mFP);
- if (size > 0)
- {
- // everything seems to be in order
- LL_INFOS() << "Success downloading " << req.mURLBuffer << " to file, size " << size << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Found " << req.mURLBuffer << " to be zero size" << LL_ENDL;
- xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
- }
- }
- else
- {
- xfer_result = curl_result == HTTP_NOT_FOUND ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;
- LL_INFOS() << "Failure downloading " << req.mURLBuffer <<
- " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;
- }
- }
-
- fclose(fp);
- if (xfer_result)
- {
- LLFile::remove(filename);
- }
- return xfer_result;
-}
-
-
-// static
-size_t LLHTTPAssetStorage::curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data)
-{
- CURL *curl_handle = (CURL *)user_data;
- LLHTTPAssetRequest *req = NULL;
- curl_easy_getinfo(curl_handle, CURLINFO_PRIVATE, &req);
-
- if (! req->mFP)
- {
- LL_WARNS() << "Missing mFP, aborting curl file download callback!" << LL_ENDL;
- return 0;
- }
-
- return fwrite(data, size, nmemb, req->mFP);
-}
-
-LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt)
-{
- switch (rt)
- {
- case RT_DOWNLOAD:
- return &mRunningDownloads;
- case RT_UPLOAD:
- return &mRunningUploads;
- case RT_LOCALUPLOAD:
- return &mRunningLocalUploads;
- default:
- return NULL;
- }
-}
-
-const LLAssetStorage::request_list_t* LLHTTPAssetStorage::getRunningList(LLAssetStorage::ERequestType rt) const
-{
- switch (rt)
- {
- case RT_DOWNLOAD:
- return &mRunningDownloads;
- case RT_UPLOAD:
- return &mRunningUploads;
- case RT_LOCALUPLOAD:
- return &mRunningLocalUploads;
- default:
- return NULL;
- }
-}
-
-
-void LLHTTPAssetStorage::addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
-{
- request_list_t* requests = getRunningList(rt);
- if (requests)
- {
- requests->push_back(request);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetStorage::addRunningRequest - Request is not an upload OR download, this is bad!" << LL_ENDL;
- }
-}
-
-void LLHTTPAssetStorage::removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request)
-{
- request_list_t* requests = getRunningList(rt);
- if (requests)
- {
- requests->remove(request);
- }
- else
- {
- LL_ERRS() << "LLHTTPAssetStorage::removeRunningRequest - Destroyed request is not an upload OR download, this is bad!" << LL_ENDL;
- }
-}
-
-// virtual
-void LLHTTPAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name)
-{
- if (agent_id.isNull() || asset_id.isNull())
- {
- LL_WARNS() << "TAT: addTempAssetData bad id's asset_id: " << asset_id << " agent_id: " << agent_id << LL_ENDL;
- return;
- }
-
- LLTempAssetData temp_asset_data;
- temp_asset_data.mAssetID = asset_id;
- temp_asset_data.mAgentID = agent_id;
- temp_asset_data.mHostName = host_name;
-
- mTempAssets[asset_id] = temp_asset_data;
-}
-
-// virtual
-BOOL LLHTTPAssetStorage::hasTempAssetData(const LLUUID& texture_id) const
-{
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
- BOOL found = (citer != mTempAssets.end());
- return found;
-}
-
-// virtual
-std::string LLHTTPAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const
-{
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
- if (citer != mTempAssets.end())
- {
- return citer->second.mHostName;
- }
- else
- {
- return std::string();
- }
-}
-
-// virtual
-LLUUID LLHTTPAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const
-{
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(texture_id);
- if (citer != mTempAssets.end())
- {
- return citer->second.mAgentID;
- }
- else
- {
- return LLUUID::null;
- }
-}
-
-// virtual
-void LLHTTPAssetStorage::removeTempAssetData(const LLUUID& asset_id)
-{
- mTempAssets.erase(asset_id);
-}
-
-// virtual
-void LLHTTPAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id)
-{
- uuid_tempdata_map::iterator it = mTempAssets.begin();
- uuid_tempdata_map::iterator end = mTempAssets.end();
-
- while (it != end)
- {
- const LLTempAssetData& asset_data = it->second;
- if (asset_data.mAgentID == agent_id)
- {
- mTempAssets.erase(it++);
- }
- else
- {
- ++it;
- }
- }
-}
-
-std::string LLHTTPAssetStorage::getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type)
-{
- if (LLAssetType::AT_TEXTURE == asset_type)
- {
- uuid_tempdata_map::const_iterator citer = mTempAssets.find(asset_id);
- if (citer != mTempAssets.end())
- {
- const std::string& host_name = citer->second.mHostName;
- std::string url = llformat(LOCAL_ASSET_URL_FORMAT, host_name.c_str());
- return url;
- }
- }
-
- return mBaseURL;
-}
-
-void LLHTTPAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const
-{
- uuid_tempdata_map::const_iterator it = mTempAssets.begin();
- uuid_tempdata_map::const_iterator end = mTempAssets.end();
- S32 count = 0;
- for ( ; it != end; ++it)
- {
- const LLTempAssetData& temp_asset_data = it->second;
- if (avatar_id.isNull()
- || avatar_id == temp_asset_data.mAgentID)
- {
- LL_INFOS() << "TAT: dump agent " << temp_asset_data.mAgentID
- << " texture " << temp_asset_data.mAssetID
- << " host " << temp_asset_data.mHostName
- << LL_ENDL;
- count++;
- }
- }
-
- if (avatar_id.isNull())
- {
- LL_INFOS() << "TAT: dumped " << count << " entries for all avatars" << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "TAT: dumped " << count << " entries for avatar " << avatar_id << LL_ENDL;
- }
-}
-
-void LLHTTPAssetStorage::clearTempAssetData()
-{
- LL_INFOS() << "TAT: Clearing temp asset data map" << LL_ENDL;
- mTempAssets.clear();
-}
diff --git a/indra/llmessage/llhttpassetstorage.h b/indra/llmessage/llhttpassetstorage.h
deleted file mode 100755
index 783e95cac6..0000000000
--- a/indra/llmessage/llhttpassetstorage.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * @file llhttpassetstorage.h
- * @brief Class for loading asset data to/from an external source over http.
- *
- * $LicenseInfo:firstyear=2003&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 LLHTTPASSETSTORAGE_H
-#define LLHTTPASSETSTORAGE_H
-
-#include "llassetstorage.h"
-#include "curl/curl.h"
-
-class LLVFile;
-class LLHTTPAssetRequest;
-typedef void (*progress_callback)(void* userdata);
-
-struct LLTempAssetData;
-
-typedef std::map<LLUUID,LLTempAssetData> uuid_tempdata_map;
-
-class LLHTTPAssetStorage : public LLAssetStorage
-{
-public:
- LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, LLVFS *static_vfs,
- const LLHost &upstream_host,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name);
-
- LLHTTPAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
- LLVFS *vfs, LLVFS *static_vfs,
- const std::string& web_host,
- const std::string& local_web_host,
- const std::string& host_name);
-
-
- virtual ~LLHTTPAssetStorage();
-
- using LLAssetStorage::storeAssetData; // Unhiding virtuals...
-
- virtual void storeAssetData(
- const LLUUID& uuid,
- LLAssetType::EType atype,
- LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file = false,
- bool is_priority = false,
- bool store_local = false,
- const LLUUID& requesting_agent_id = LLUUID::null,
- bool user_waiting=FALSE,
- F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
-
- virtual void storeAssetData(
- const std::string& filename,
- const LLUUID& asset_id,
- LLAssetType::EType atype,
- LLStoreAssetCallback callback,
- void* user_data,
- bool temp_file,
- bool is_priority,
- bool user_waiting=FALSE,
- F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT);
-
- virtual LLSD getPendingDetails(ERequestType rt,
- LLAssetType::EType asset_type,
- const std::string& detail_prefix) const;
-
- virtual LLSD getPendingRequest(ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id) const;
-
- virtual bool deletePendingRequest(ERequestType rt,
- LLAssetType::EType asset_type,
- const LLUUID& asset_id);
-
- // Hack. One off curl download an URL to a file. Probably should be elsewhere.
- // Only used by lldynamicstate. The API is broken, and should be replaced with
- // a generic HTTP file fetch - Doug 9/25/06
- S32 getURLToFile(const LLUUID& uuid, LLAssetType::EType asset_type, const std::string &url, const std::string& filename, progress_callback callback, void *userdata);
-
- LLAssetRequest* findNextRequest(request_list_t& pending, request_list_t& running);
-
- void checkForTimeouts();
-
- static size_t curlDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
- static size_t curlFileDownCallback(void *data, size_t size, size_t nmemb, void *user_data);
- static size_t curlUpCallback(void *data, size_t size, size_t nmemb, void *user_data);
- static size_t nullOutputCallback(void *data, size_t size, size_t nmemb, void *user_data);
-
- // Should only be used by the LLHTTPAssetRequest
- void addRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
- void removeRunningRequest(ERequestType rt, LLHTTPAssetRequest* request);
-
- request_list_t* getRunningList(ERequestType rt);
- const request_list_t* getRunningList(ERequestType rt) const;
-
- // Temp assets are stored on sim nodes, they have agent ID and location data associated with them.
- virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name);
- virtual BOOL hasTempAssetData(const LLUUID& texture_id) const;
- virtual std::string getTempAssetHostName(const LLUUID& texture_id) const;
- virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const;
- virtual void removeTempAssetData(const LLUUID& asset_id);
- virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id);
-
- // Pass LLUUID::null for all
- virtual void dumpTempAssetData(const LLUUID& avatar_id) const;
- virtual void clearTempAssetData();
-
-protected:
- void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type,
- void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
- void *user_data, BOOL duplicate, BOOL is_priority);
-
-private:
- void _init(const std::string& web_host, const std::string& local_web_host, const std::string& host_name);
-
- // This will return the correct base URI for any http asset request
- std::string getBaseURL(const LLUUID& asset_id, LLAssetType::EType asset_type);
-
- // Check for running uploads that have timed out
- // Bump these to the back of the line to let other uploads complete.
- void bumpTimedOutUploads();
-
-protected:
- std::string mBaseURL;
- std::string mLocalBaseURL;
- std::string mHostName;
-
- CURLM *mCurlMultiHandle;
-
- request_list_t mRunningDownloads;
- request_list_t mRunningUploads;
- request_list_t mRunningLocalUploads;
-
- uuid_tempdata_map mTempAssets;
-};
-
-#endif
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
deleted file mode 100755
index 60f17e6870..0000000000
--- a/indra/llmessage/llhttpclient.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-/**
- * @file llhttpclient.cpp
- * @brief Implementation of classes for making HTTP requests.
- *
- * $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 <openssl/x509_vfy.h>
-#include "llhttpclient.h"
-
-#include "llassetstorage.h"
-#include "lliopipe.h"
-#include "llurlrequest.h"
-#include "llbufferstream.h"
-#include "llsdserialize.h"
-#include "llvfile.h"
-#include "llvfs.h"
-#include "lluri.h"
-
-#include "message.h"
-#include <curl/curl.h>
-
-
-const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
-LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
-
-////////////////////////////////////////////////////////////////////////////
-
-// Responder class moved to LLCurl
-
-namespace
-{
- class LLHTTPClientURLAdaptor : public LLURLRequestComplete
- {
- public:
- LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder)
- : LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR),
- mReason("LLURLRequest complete w/no status")
- {
- }
-
- ~LLHTTPClientURLAdaptor()
- {
- }
-
- virtual void httpStatus(S32 status, const std::string& reason)
- {
- LLURLRequestComplete::httpStatus(status,reason);
-
- mStatus = status;
- mReason = reason;
- }
-
- 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())
- {
- mResponder->setResult(mStatus, mReason);
- mResponder->completedRaw(channels, buffer);
- }
- }
- virtual void header(const std::string& header, const std::string& value)
- {
- if (mResponder.get())
- {
- mResponder->setResponseHeader(header, value);
- }
- }
-
- private:
- LLCurl::ResponderPtr mResponder;
- S32 mStatus;
- std::string mReason;
- };
-
- class Injector : public LLIOPipe
- {
- public:
- virtual const std::string& contentType() = 0;
- };
-
- class LLSDInjector : public Injector
- {
- public:
- LLSDInjector(const LLSD& sd) : mSD(sd) {}
- virtual ~LLSDInjector() {}
-
- 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)
- {
- LLBufferStream ostream(channels, buffer.get());
- LLSDSerialize::toXML(mSD, ostream);
- eos = true;
- return STATUS_DONE;
- }
-
- const LLSD mSD;
- };
-
- class RawInjector : public Injector
- {
- public:
- RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {}
- virtual ~RawInjector() {delete [] mData;}
-
- 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)
- {
- LLBufferStream ostream(channels, buffer.get());
- ostream.write((const char *)mData, mSize); // hopefully chars are always U8s
- eos = true;
- return STATUS_DONE;
- }
-
- const U8* mData;
- S32 mSize;
- };
-
- class FileInjector : public Injector
- {
- public:
- FileInjector(const std::string& filename) : mFilename(filename) {}
- virtual ~FileInjector() {}
-
- 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)
- {
- LLBufferStream ostream(channels, buffer.get());
-
- llifstream fstream(mFilename.c_str(), std::iostream::binary | std::iostream::out);
- if(fstream.is_open())
- {
- fstream.seekg(0, std::ios::end);
- U32 fileSize = (U32)fstream.tellg();
- fstream.seekg(0, std::ios::beg);
- std::vector<char> fileBuffer(fileSize);
- fstream.read(&fileBuffer[0], fileSize);
- ostream.write(&fileBuffer[0], fileSize);
- fstream.close();
- eos = true;
- return STATUS_DONE;
- }
-
- return STATUS_ERROR;
- }
-
- const std::string mFilename;
- };
-
- class VFileInjector : public Injector
- {
- public:
- VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {}
- virtual ~VFileInjector() {}
-
- 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)
- {
- LLBufferStream ostream(channels, buffer.get());
-
- LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ);
- S32 fileSize = vfile.getSize();
- U8* fileBuffer;
- fileBuffer = new U8 [fileSize];
- vfile.read(fileBuffer, fileSize);
- ostream.write((char*)fileBuffer, fileSize);
- delete [] fileBuffer;
- eos = true;
- return STATUS_DONE;
- }
-
- const LLUUID mUUID;
- LLAssetType::EType mAssetType;
- };
-
-
- LLPumpIO* theClientPump = NULL;
-}
-
-void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback)
-{
- LLHTTPClient::mCertVerifyCallback = callback;
-}
-
-static void request(
- const std::string& url,
- EHTTPMethod method,
- Injector* body_injector,
- LLCurl::ResponderPtr responder,
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
- const LLSD& headers = LLSD(),
- bool follow_redirects = true
- )
-{
- if (!LLHTTPClient::hasPump())
- {
- if (responder)
- {
- responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");
- }
- delete body_injector;
- return;
- }
- LLPumpIO::chain_t chain;
-
- LLURLRequest* req = new LLURLRequest(method, url, follow_redirects);
- if(!req->isValid())//failed
- {
- if (responder)
- {
- responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure");
- }
- delete req;
- delete body_injector;
- return;
- }
-
- req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
-
- LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL;
-
- // Insert custom headers if the caller sent any
- if (headers.isMap())
- {
- 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)
- {
- //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 != HTTP_PUT && method != HTTP_POST )
- {
- if(!headers.has(HTTP_OUT_HEADER_ACCEPT))
- {
- 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 == HTTP_POST && gMessageSystem)
- {
- req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d",
- gMessageSystem->mPort));
- }
-
- if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)
- {
- 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(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType());
- }
- chain.push_back(LLIOPipe::ptr_t(body_injector));
- }
-
- chain.push_back(LLIOPipe::ptr_t(req));
-
- theClientPump->addChain(chain, timeout);
-}
-
-
-void LLHTTPClient::getByteRange(
- const std::string& url,
- S32 offset,
- S32 bytes,
- ResponderPtr responder,
- const LLSD& hdrs,
- const F32 timeout,
- bool follow_redirects /* = true */)
-{
- LLSD headers = hdrs;
- if(offset > 0 || bytes > 0)
- {
- std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
- headers[HTTP_OUT_HEADER_RANGE] = range;
- }
- request(url,HTTP_GET, NULL, responder, timeout, headers, follow_redirects);
-}
-
-void LLHTTPClient::head(
- const std::string& url,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout,
- bool follow_redirects /* = true */)
-{
- 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, 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, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);
-}
-void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout,
- bool follow_redirects /* = true */)
-{
- getHeaderOnly(url, responder, LLSD(), timeout, follow_redirects);
-}
-
-void LLHTTPClient::get(const std::string& url, const LLSD& query, ResponderPtr responder, const LLSD& headers,
- const F32 timeout, bool follow_redirects /* = true */)
-{
- LLURI uri;
-
- uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
- get(uri.asString(), responder, headers, timeout, follow_redirects);
-}
-
-// A simple class for managing data returned from a curl http request.
-class LLHTTPBuffer
-{
-public:
- LLHTTPBuffer() { }
-
- static size_t curl_write( void *ptr, size_t size, size_t nmemb, void *user_data)
- {
- LLHTTPBuffer* self = (LLHTTPBuffer*)user_data;
-
- size_t bytes = (size * nmemb);
- self->mBuffer.append((char*)ptr,bytes);
- return nmemb;
- }
-
- LLSD asLLSD()
- {
- LLSD content;
-
- if (mBuffer.empty()) return content;
-
- std::istringstream istr(mBuffer);
- LLSDSerialize::fromXML(content, istr);
- return content;
- }
-
- const std::string& asString()
- {
- return mBuffer;
- }
-
-private:
- std::string mBuffer;
-};
-
-// These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome.
-
-/**
- @brief does a blocking request on the url, returning the data or bad status.
-
- @param url URI to verb on.
- @param method the verb to hit the URI with.
- @param body the body of the call (if needed - for instance not used for GET and DELETE, but is for POST and PUT)
- @param headers HTTP headers to use for the request.
- @param timeout Curl timeout to use. Defaults to 5. Rationale:
- Without this timeout, blockingGet() calls have been observed to take
- up to 90 seconds to complete. Users of blockingGet() already must
- check the HTTP return code for validity, so this will not introduce
- new errors. A 5 second timeout will succeed > 95% of the time (and
- probably > 99% of the time) based on my statistics. JC
-
- @returns an LLSD map: {status: integer, body: map}
- */
-static LLSD blocking_request(
- const std::string& url,
- EHTTPMethod method,
- const LLSD& body,
- const LLSD& headers = LLSD(),
- const F32 timeout = 5
-)
-{
- LL_DEBUGS() << "blockingRequest of " << url << LL_ENDL;
- char curl_error_buffer[CURL_ERROR_SIZE] = "\0";
- CURL* curlp = LLCurl::newEasyHandle();
- llassert_always(curlp != NULL) ;
-
- LLHTTPBuffer http_buffer;
- std::string body_str;
-
- // other request method checks root cert first, we skip?
-
- // Apply configured proxy settings
- LLProxy::getInstance()->applyProxySettings(curlp);
-
- // * Set curl handle options
- curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
- curl_easy_setopt(curlp, CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function.
- curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, LLHTTPBuffer::curl_write);
- curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer);
- curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());
- curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer);
-
- // * Setup headers (don't forget to free them after the call!)
- curl_slist* headers_list = NULL;
- if (headers.isMap())
- {
- LLSD::map_const_iterator iter = headers.beginMap();
- LLSD::map_const_iterator end = headers.endMap();
- for (; iter != end; ++iter)
- {
- std::ostringstream header;
- header << iter->first << ": " << iter->second.asString() ;
- LL_DEBUGS() << "header = " << header.str() << LL_ENDL;
- headers_list = curl_slist_append(headers_list, header.str().c_str());
- }
- }
-
- // * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
- if (method == HTTP_GET)
- {
- curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
- }
- 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 :(
- std::ostringstream ostr;
- LLSDSerialize::toXML(body, ostr);
- 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,
- 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, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str());
- }
-
- // * Do the action using curl, handle results
- LL_DEBUGS() << "HTTP body: " << body_str << LL_ENDL;
- 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 )
- {
- LL_INFOS() << "Curl is hosed - can't add headers" << LL_ENDL;
- }
-
- LLSD response = LLSD::emptyMap();
- S32 curl_success = curl_easy_perform(curlp);
- 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 != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) )
- {
- // We expect 404s, don't spam for them.
- LL_WARNS() << "CURL REQ URL: " << url << LL_ENDL;
- LL_WARNS() << "CURL REQ METHOD TYPE: " << method << LL_ENDL;
- LL_WARNS() << "CURL REQ HEADERS: " << headers.asString() << LL_ENDL;
- LL_WARNS() << "CURL REQ BODY: " << body_str << LL_ENDL;
- LL_WARNS() << "CURL HTTP_STATUS: " << http_status << LL_ENDL;
- LL_WARNS() << "CURL ERROR: " << curl_error_buffer << LL_ENDL;
- LL_WARNS() << "CURL ERROR BODY: " << http_buffer.asString() << LL_ENDL;
- response["body"] = http_buffer.asString();
- }
- else
- {
- response["body"] = http_buffer.asLLSD();
- LL_DEBUGS() << "CURL response: " << http_buffer.asString() << LL_ENDL;
- }
-
- if(headers_list)
- { // free the header list
- curl_slist_free_all(headers_list);
- }
-
- // * Cleanup
- LLCurl::deleteEasyHandle(curlp);
- return response;
-}
-
-LLSD LLHTTPClient::blockingGet(const std::string& url)
-{
- return blocking_request(url, HTTP_GET, LLSD());
-}
-
-LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
-{
- return blocking_request(url, HTTP_POST, body);
-}
-
-void LLHTTPClient::put(
- const std::string& url,
- const LLSD& body,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- 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::putRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_PUT, new RawInjector(data, size), responder, timeout, headers);
-}
-
-void LLHTTPClient::post(
- const std::string& url,
- const LLSD& body,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers);
-}
-
-void LLHTTPClient::postRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers);
-}
-
-void LLHTTPClient::postFile(
- const std::string& url,
- const std::string& filename,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers);
-}
-
-void LLHTTPClient::postFile(
- const std::string& url,
- const LLUUID& uuid,
- LLAssetType::EType asset_type,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);
-}
-
-// static
-void LLHTTPClient::del(
- const std::string& url,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
-{
- request(url, HTTP_DELETE, NULL, responder, timeout, headers);
-}
-
-// static
-void LLHTTPClient::move(
- 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_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);
-}
-
-
-void LLHTTPClient::setPump(LLPumpIO& pump)
-{
- theClientPump = &pump;
-}
-
-bool LLHTTPClient::hasPump()
-{
- return theClientPump != NULL;
-}
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
deleted file mode 100755
index fd48b4a743..0000000000
--- a/indra/llmessage/llhttpclient.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * @file llhttpclient.h
- * @brief Declaration of classes for making HTTP client requests.
- *
- * $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_LLHTTPCLIENT_H
-#define LL_LLHTTPCLIENT_H
-
-/**
- * These classes represent the HTTP client framework.
- */
-
-#include <string>
-
-#include <boost/intrusive_ptr.hpp>
-#include <openssl/x509_vfy.h>
-#include "llurlrequest.h"
-#include "llassettype.h"
-#include "llcurl.h"
-#include "lliopipe.h"
-
-extern const F32 HTTP_REQUEST_EXPIRY_SECS;
-
-class LLUUID;
-class LLPumpIO;
-class LLSD;
-
-
-class LLHTTPClient
-{
-public:
- // class Responder moved to LLCurl
-
- // For convenience
- typedef LLCurl::Responder Responder;
- typedef LLCurl::ResponderPtr ResponderPtr;
-
-
- /** @name non-blocking API */
- //@{
- static void head(
- const std::string& url,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
- bool follow_redirects = true);
- static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr,
- const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,
- bool follow_redirects = true);
- static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
- static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
-
- static void put(
- const std::string& url,
- const LLSD& body,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- static void putRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- 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,
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS, bool follow_redirects = true);
-
- static void post(
- const std::string& url,
- const LLSD& body,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- /** Takes ownership of data and deletes it when sent */
- static void postRaw(
- const std::string& url,
- const U8* data,
- S32 size,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- static void postFile(
- const std::string& url,
- const std::string& filename,
- ResponderPtr,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
- static void postFile(
- const std::string& url,
- const LLUUID& uuid,
- LLAssetType::EType asset_type,
- ResponderPtr responder,
- const LLSD& headers = LLSD(),
- const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
-
- static void del(
- const std::string& url,
- ResponderPtr responder,
- 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
- *
- * @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 move(
- const std::string& url,
- const std::string& destination,
- ResponderPtr responder,
- 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);
-
- //@}
-
- /**
- * @brief Blocking HTTP get that returns an LLSD map of status and body.
- *
- * @param url the complete serialized (and escaped) url to get
- * @return An LLSD of { 'status':status, 'body':payload }
- */
- static LLSD blockingGet(const std::string& url);
-
- /**
- * @brief Blocking HTTP POST that returns an LLSD map of status and body.
- *
- * @param url the complete serialized (and escaped) url to get
- * @param body the LLSD post body
- * @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) }
- */
- static LLSD blockingPost(const std::string& url, const LLSD& body);
-
-
- static void setPump(LLPumpIO& pump);
- ///< must be called before any of the above calls are made
- static bool hasPump();
-
- static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
- static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
-
-protected:
- static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
-};
-
-#endif // LL_LLHTTPCLIENT_H
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
deleted file mode 100755
index b56a804f94..0000000000
--- a/indra/llmessage/llhttpclientadapter.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file llhttpclientadapter.cpp
- * @brief
- *
- * $LicenseInfo:firstyear=2009&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 "llhttpclientadapter.h"
-#include "llhttpclient.h"
-
-LLHTTPClientAdapter::~LLHTTPClientAdapter()
-{
-}
-
-void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder)
-{
- LLSD empty_pragma_header;
- // Pragma is required to stop curl adding "no-cache"
- // 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(HTTP_OUT_HEADER_PRAGMA))
- {
- // as above
- empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
- }
- LLHTTPClient::get(url, responder, empty_pragma_header);
-}
-
-void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)
-{
- 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
deleted file mode 100755
index 270282c66f..0000000000
--- a/indra/llmessage/llhttpclientadapter.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * @file llhttpclientadepter.h
- * @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$
- */
-
-#ifndef LL_HTTPCLIENTADAPTER_H
-#define LL_HTTPCLIENTADAPTER_H
-
-#include "llhttpclientinterface.h"
-#include "llsingleton.h" // LLSingleton<>
-
-class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLHTTPClientAdapter>
-{
-public:
- virtual ~LLHTTPClientAdapter();
- 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/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h
deleted file mode 100755
index 12a3857a61..0000000000
--- a/indra/llmessage/llhttpclientinterface.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * @file llhttpclientinterface.h
- * @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$
- */
-
-#ifndef LL_LLHTTPCLIENTINTERFACE_H
-#define LL_LLHTTPCLIENTINTERFACE_H
-
-#include "linden_common.h"
-#include "llcurl.h"
-
-#include <string>
-
-class LLHTTPClientInterface
-{
-public:
- virtual ~LLHTTPClientInterface() {}
- virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0;
- virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0;
- virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0;
-};
-
-#endif // LL_LLHTTPCLIENTINTERFACE_H
-
diff --git a/indra/llmessage/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp
new file mode 100644
index 0000000000..d99bdd3f66
--- /dev/null
+++ b/indra/llmessage/llhttpsdhandler.cpp
@@ -0,0 +1,105 @@
+/**
+* @file llhttpsdhandler.h
+* @brief Public-facing declarations for the HttpHandler class
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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 "llhttpsdhandler.h"
+#include "httpresponse.h"
+#include "httpheaders.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "bufferstream.h"
+#include "llcorehttputil.h"
+
+//========================================================================
+LLHttpSDHandler::LLHttpSDHandler(bool selfDelete):
+ mSelfDelete(selfDelete)
+{
+}
+
+void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+ LLCore::HttpStatus status = response->getStatus();
+
+ if (!status)
+ {
+ this->onFailure(response, status);
+ }
+ else
+ {
+ LLSD resplsd;
+ const bool emit_parse_errors = false;
+
+ bool parsed = !((response->getBodySize() == 0) ||
+ !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd));
+
+ if (!parsed)
+ {
+ // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml'
+ LLCore::HttpHeaders::ptr_t headers(response->getHeaders());
+ const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL;
+
+ if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
+ {
+ std::string thebody = LLCoreHttpUtil::responseToString(response);
+
+ LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
+ << " body: " << thebody << LL_ENDL;
+ }
+ }
+
+ this->onSuccess(response, resplsd);
+ }
+
+ // The handler must destroy itself when it is done.
+ // *TODO: I'm not fond of this pattern. A class shooting itself in the head
+ // outside of a smart pointer always makes me nervous.
+ if (mSelfDelete)
+ delete this;
+}
+
+//========================================================================
+LLHttpSDGenericHandler::LLHttpSDGenericHandler(const std::string &name, bool selfDelete):
+ LLHttpSDHandler(selfDelete),
+ mName(name)
+{
+}
+
+void LLHttpSDGenericHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
+{
+ LL_DEBUGS() << mName << " Success." << LL_ENDL;
+}
+
+void LLHttpSDGenericHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
+{
+ LL_WARNS()
+ << "\n--------------------------------------------------------------------------\n"
+ << mName << " Error[" << status.toULong() << "] cannot access cap with url '"
+ << response->getRequestURL() << "' because " << status.toString()
+ << "\n--------------------------------------------------------------------------"
+ << LL_ENDL;
+}
diff --git a/indra/llmessage/llhttpsdhandler.h b/indra/llmessage/llhttpsdhandler.h
new file mode 100644
index 0000000000..3b81dc66b9
--- /dev/null
+++ b/indra/llmessage/llhttpsdhandler.h
@@ -0,0 +1,72 @@
+/**
+* @file llhttpsdhandler.h
+* @brief Public-facing declarations for the HttpHandler class
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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 _LLHTTPSDHANDLER_H_
+#define _LLHTTPSDHANDLER_H_
+#include "httpcommon.h"
+#include "httphandler.h"
+#include "lluri.h"
+
+/// Handler class LLCore's HTTP library. Splitting with separate success and
+/// failure routines and parsing the result body into LLSD on success. It
+/// is intended to be subclassed for specific capability handling.
+///
+// *TODO: This class self deletes at the end of onCompleted method. This is
+// less than ideal and should be revisited.
+class LLHttpSDHandler : public LLCore::HttpHandler //,
+// public std::enable_shared_from_this<LLHttpSDHandler>
+{
+public:
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+protected:
+ LLHttpSDHandler(bool selfDelete = true);
+
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0;
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0;
+
+private:
+ bool mSelfDelete;
+
+};
+
+/// A trivial implementation of LLHttpSDHandler. This success and failure
+/// methods log the action taken, the URI accessed and the status code returned
+/// in the response.
+class LLHttpSDGenericHandler : public LLHttpSDHandler
+{
+public:
+ LLHttpSDGenericHandler(const std::string &name, bool selfDelete = true);
+
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
+
+private:
+ std::string mName;
+};
+#endif
diff --git a/indra/llmessage/llhttpsender.cpp b/indra/llmessage/llhttpsender.cpp
deleted file mode 100755
index 5363088d79..0000000000
--- a/indra/llmessage/llhttpsender.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * @file llhttpsender.cpp
- * @brief Abstracts details of sending messages via HTTP.
- *
- * $LicenseInfo:firstyear=2007&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 "llhttpsender.h"
-
-#include <map>
-#include <sstream>
-
-#include "llhost.h"
-#include "llsd.h"
-
-namespace
-{
- typedef std::map<LLHost, LLHTTPSender*> SenderMap;
- static SenderMap senderMap;
- static LLPointer<LLHTTPSender> defaultSender(new LLHTTPSender());
-}
-
-//virtual
-LLHTTPSender::~LLHTTPSender()
-{
-}
-
-//virtual
-void LLHTTPSender::send(const LLHost& host, const std::string& name,
- const LLSD& body,
- LLHTTPClient::ResponderPtr response) const
-{
- // Default implementation inserts sender, message and sends HTTP POST
- std::ostringstream stream;
- stream << "http://" << host << "/trusted-message/" << name;
- LL_INFOS() << "LLHTTPSender::send: POST to " << stream.str() << LL_ENDL;
- LLHTTPClient::post(stream.str(), body, response);
-}
-
-//static
-void LLHTTPSender::setSender(const LLHost& host, LLHTTPSender* sender)
-{
- LL_INFOS() << "LLHTTPSender::setSender " << host << LL_ENDL;
- senderMap[host] = sender;
-}
-
-//static
-const LLHTTPSender& LLHTTPSender::getSender(const LLHost& host)
-{
- SenderMap::const_iterator iter = senderMap.find(host);
- if(iter == senderMap.end())
- {
- return *defaultSender;
- }
- return *(iter->second);
-}
-
-//static
-void LLHTTPSender::clearSender(const LLHost& host)
-{
- SenderMap::iterator iter = senderMap.find(host);
- if(iter != senderMap.end())
- {
- delete iter->second;
- senderMap.erase(iter);
- }
-}
-
-//static
-void LLHTTPSender::setDefaultSender(LLHTTPSender* sender)
-{
- defaultSender = sender;
-}
diff --git a/indra/llmessage/llhttpsender.h b/indra/llmessage/llhttpsender.h
deleted file mode 100755
index ff8fa2f95b..0000000000
--- a/indra/llmessage/llhttpsender.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file llhttpsender.h
- * @brief Abstracts details of sending messages via HTTP.
- *
- * $LicenseInfo:firstyear=2007&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_SENDER_H
-#define LL_HTTP_SENDER_H
-
-#include "llhttpclient.h"
-
-class LLHost;
-class LLSD;
-
-class LLHTTPSender : public LLThreadSafeRefCount
-{
- public:
-
- virtual ~LLHTTPSender();
-
- /** @brief Send message to host with body, call response when done */
- virtual void send(const LLHost& host,
- const std::string& message, const LLSD& body,
- LLHTTPClient::ResponderPtr response) const;
-
- /** @brief Set sender for host, takes ownership of sender. */
- static void setSender(const LLHost& host, LLHTTPSender* sender);
-
- /** @brief Get sender for host, retains ownership of returned sender. */
- static const LLHTTPSender& getSender(const LLHost& host);
-
- /** @brief Clear sender for host. */
- static void clearSender(const LLHost& host);
-
- /** @brief Set default sender, takes ownership of sender. */
- static void setDefaultSender(LLHTTPSender* sender);
-};
-
-#endif // LL_HTTP_SENDER_H
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index 9b8d19cc3e..537efa69d8 100755
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -30,9 +30,8 @@
#include <string>
#include <curl/curl.h>
-
+#include "httpcommon.h"
#include "llapr.h"
-#include "llcurl.h"
#include "llhost.h"
// Static class variable instances
@@ -408,16 +407,6 @@ void LLProxy::cleanupClass()
deleteSingleton();
}
-void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
-{
- applyProxySettings(handle->getEasy());
-}
-
-void LLProxy::applyProxySettings(LLCurl::Easy* handle)
-{
- applyProxySettings(handle->getCurlHandle());
-}
-
/**
* @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
*
@@ -439,21 +428,21 @@ void LLProxy::applyProxySettings(CURL* handle)
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
if (mHTTPProxyEnabled)
{
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY);
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()), CURLOPT_PROXYPORT);
if (mProxyType == LLPROXY_SOCKS)
{
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE);
if (mAuthMethodSelected == METHOD_PASSWORD)
{
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD);
}
}
else
{
- LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
+ LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE);
}
}
}
diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h
index a919370540..bd23dd39de 100755
--- a/indra/llmessage/llproxy.h
+++ b/indra/llmessage/llproxy.h
@@ -27,12 +27,12 @@
#ifndef LL_PROXY_H
#define LL_PROXY_H
-#include "llcurl.h"
#include "llhost.h"
#include "lliosocket.h"
#include "llmemory.h"
#include "llsingleton.h"
#include "llthread.h"
+#include <curl/curl.h>
#include <string>
// SOCKS error codes returned from the StartProxy method
@@ -208,16 +208,13 @@ enum LLSocks5AuthType
* thread-safe method to apply those options to a curl request
* (LLProxy::applyProxySettings()). This method is overloaded
* to accommodate the various abstraction libcurl layers that exist
- * throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
- *
- * If you are working with LLCurl or LLCurlEasyRequest objects,
- * the configured proxy settings will be applied in the constructors
- * of those request handles. If you are working with CURL objects
- * directly, you will need to pass the handle of the request to
- * applyProxySettings() before issuing the request.
+ * throughout the viewer (CURL).
*
* To ensure thread safety, all LLProxy members that relate to the HTTP
* proxy require the LLProxyMutex to be locked before accessing.
+ *
+ * *TODO$: This should be moved into the LLCore::Http space.
+ *
*/
class LLProxy: public LLSingleton<LLProxy>
{
@@ -252,9 +249,6 @@ public:
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
// Safe to call from any thread.
void applyProxySettings(CURL* handle);
- void applyProxySettings(LLCurl::Easy* handle);
- void applyProxySettings(LLCurlEasyRequest* handle);
-
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
S32 startSOCKSProxy(LLHost host);
diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp
deleted file mode 100755
index 61fcc5dd2f..0000000000
--- a/indra/llmessage/llsdmessage.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * @file llsdmessage.cpp
- * @author Nat Goodspeed
- * @date 2008-10-31
- * @brief Implementation for llsdmessage.
- *
- * $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$
- */
-
-#if LL_WINDOWS
-#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
-#endif
-
-// Precompiled header
-#include "linden_common.h"
-// associated header
-#include "llsdmessage.h"
-// STL headers
-// std headers
-// external library headers
-// other Linden headers
-#include "llevents.h"
-#include "llsdserialize.h"
-#include "llhttpclient.h"
-#include "llmessageconfig.h"
-#include "llhost.h"
-#include "message.h"
-#include "llsdutil.h"
-
-// Declare a static LLSDMessage instance to ensure that we have a listener as
-// soon as someone tries to post on our canonical LLEventPump name.
-static LLSDMessage httpListener;
-
-LLSDMessage::LLSDMessage():
- // Instantiating our own local LLEventPump with a string name the
- // constructor is NOT allowed to tweak is a way of ensuring Singleton
- // semantics: attempting to instantiate a second LLSDMessage object would
- // throw LLEventPump::DupPumpName.
- mEventPump("LLHTTPClient")
-{
- mEventPump.listen("self", boost::bind(&LLSDMessage::httpListener, this, _1));
-}
-
-bool LLSDMessage::httpListener(const LLSD& request)
-{
- // Extract what we want from the request object. We do it all up front
- // partly to document what we expect.
- LLSD::String url(request["url"]);
- LLSD payload(request["payload"]);
- LLSD::String reply(request["reply"]);
- LLSD::String error(request["error"]);
- LLSD::Real timeout(request["timeout"]);
- // If the LLSD doesn't even have a "url" key, we doubt it was intended for
- // this listener.
- if (url.empty())
- {
- std::ostringstream out;
- out << "request event without 'url' key to '" << mEventPump.getName() << "'";
- throw ArgError(out.str());
- }
- // Establish default timeout. This test relies on LLSD::asReal() returning
- // exactly 0.0 for an undef value.
- if (! timeout)
- {
- timeout = HTTP_REQUEST_EXPIRY_SECS;
- }
- LLHTTPClient::post(url, payload,
- new LLSDMessage::EventResponder(LLEventPumps::instance(),
- request,
- url, "POST", reply, error),
- LLSD(), // headers
- (F32)timeout);
- return false;
-}
-
-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(getContent());
- mReqID.stamp(response);
- mPumps.obtain(mReplyPump).post(response);
- }
- else // default success handling
- {
- LL_INFOS("LLSDMessage::EventResponder")
- << "'" << mMessage << "' to '" << mTarget << "' succeeded"
- << LL_ENDL;
- }
-}
-
-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
- // explicit pump name.
- if (! mErrorPump.empty())
- {
- LLSD info(mReqID.makeResponse());
- info["target"] = mTarget;
- info["message"] = mMessage;
- info["status"] = getStatus();
- info["reason"] = getReason();
- info["content"] = getContent();
- mPumps.obtain(mErrorPump).post(info);
- }
- else // default error handling
- {
- // convention seems to be to use LL_INFOS(), but that seems a bit casual?
- LL_WARNS("LLSDMessage::EventResponder")
- << "'" << mMessage << "' to '" << mTarget
- << "' failed " << dumpResponse() << LL_ENDL;
- }
-}
-
-LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderPtr responder,
- const std::string& name):
- mResponder(responder),
- mReplyPump(name + ".reply", true), // tweak name for uniqueness
- mErrorPump(name + ".error", true)
-{
- mReplyPump.listen("self", boost::bind(&ResponderAdapter::listener, this, _1, true));
- mErrorPump.listen("self", boost::bind(&ResponderAdapter::listener, this, _1, false));
-}
-
-bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)
-{
- if (success)
- {
- mResponder->successResult(payload);
- }
- else
- {
- mResponder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"]);
- }
-
- /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/
- delete this;
- // Destruction of mResponder will usually implicitly free its referent as well
- /*------------------------- NOTHING AFTER THIS -------------------------*/
- return false;
-}
-
-void LLSDMessage::link()
-{
-}
diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h
deleted file mode 100755
index e5d532d6a4..0000000000
--- a/indra/llmessage/llsdmessage.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * @file llsdmessage.h
- * @author Nat Goodspeed
- * @date 2008-10-30
- * @brief API intended to unify sending capability, UDP and TCP messages:
- * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes
- *
- * $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$
- */
-
-#if ! defined(LL_LLSDMESSAGE_H)
-#define LL_LLSDMESSAGE_H
-
-#include "llerror.h" // LOG_CLASS()
-#include "llevents.h" // LLEventPumps
-#include "llhttpclient.h"
-#include <string>
-#include <stdexcept>
-
-class LLSD;
-
-/**
- * Class managing the messaging API described in
- * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes
- */
-class LLSDMessage
-{
- LOG_CLASS(LLSDMessage);
-
-public:
- LLSDMessage();
-
- /// Exception if you specify arguments badly
- struct ArgError: public std::runtime_error
- {
- ArgError(const std::string& what):
- std::runtime_error(std::string("ArgError: ") + what) {}
- };
-
- /**
- * The response idiom used by LLSDMessage -- LLEventPump names on which to
- * post reply or error -- is designed for the case in which your
- * reply/error handlers are methods on the same class as the method
- * sending the message. Any state available to the sending method that
- * must be visible to the reply/error methods can conveniently be stored
- * on that class itself, if it's not already.
- *
- * The LLHTTPClient::Responder idiom requires a separate instance of a
- * separate class so that it can dispatch to the code of interest by
- * calling canonical virtual methods. Interesting state must be copied
- * into that new object.
- *
- * With some trepidation, because existing response code is packaged in
- * LLHTTPClient::Responder subclasses, we provide this adapter class
- * <i>for transitional purposes only.</i> Instantiate a new heap
- * ResponderAdapter with your new LLHTTPClient::ResponderPtr. Pass
- * ResponderAdapter::getReplyName() and/or getErrorName() in your
- * LLSDMessage (or LLViewerRegion::getCapAPI()) request event. The
- * ResponderAdapter will call the appropriate Responder method, then
- * @c delete itself.
- */
- class ResponderAdapter
- {
- public:
- /**
- * Bind the new LLHTTPClient::Responder subclass instance.
- *
- * Passing the constructor a name other than the default is only
- * interesting if you suspect some usage will lead to an exception or
- * log message.
- */
- ResponderAdapter(LLHTTPClient::ResponderPtr responder,
- const std::string& name="ResponderAdapter");
-
- /// EventPump name on which LLSDMessage should post reply event
- std::string getReplyName() const { return mReplyPump.getName(); }
- /// EventPump name on which LLSDMessage should post error event
- std::string getErrorName() const { return mErrorPump.getName(); }
-
- private:
- // We have two different LLEventStreams, though we route them both to
- // the same listener, so that we can bind an extra flag identifying
- // which case (reply or error) reached that listener.
- bool listener(const LLSD&, bool success);
-
- LLHTTPClient::ResponderPtr mResponder;
- LLEventStream mReplyPump, mErrorPump;
- };
-
- /**
- * Force our implementation file to be linked with caller. The .cpp file
- * contains a static instance of this class, which must be linked into the
- * executable to support the canonical listener. But since the primary
- * interface to that static instance is via a named LLEventPump rather
- * than by direct reference, the linker doesn't necessarily perceive the
- * necessity to bring in the translation unit. Referencing this dummy
- * method forces the issue.
- */
- static void link();
-
-private:
- friend class LLCapabilityListener;
- /// Responder used for internal purposes by LLSDMessage and
- /// LLCapabilityListener. Others should use higher-level APIs.
- class EventResponder: public LLHTTPClient::Responder
- {
- LOG_CLASS(EventResponder);
- public:
- /**
- * LLHTTPClient::Responder that dispatches via named LLEventPump instances.
- * We bind LLEventPumps, even though it's an LLSingleton, for testability.
- * We bind the string names of the desired LLEventPump instances rather
- * than actually obtain()ing them so we only obtain() the one we're going
- * to use. If the caller doesn't bother to listen() on it, the other pump
- * may never materialize at all.
- * @a target and @a message are only to clarify error processing.
- * For a capability message, @a target should be the region description,
- * @a message should be the capability name.
- * For a service with a visible URL, pass the URL as @a target and the HTTP verb
- * (e.g. "POST") as @a message.
- */
- EventResponder(LLEventPumps& pumps,
- const LLSD& request,
- const std::string& target, const std::string& message,
- const std::string& replyPump, const std::string& errorPump):
- mPumps(pumps),
- mReqID(request),
- mTarget(target),
- mMessage(message),
- mReplyPump(replyPump),
- mErrorPump(errorPump)
- {}
-
- protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
- private:
- LLEventPumps& mPumps;
- LLReqID mReqID;
- const std::string mTarget, mMessage, mReplyPump, mErrorPump;
- };
-
-private:
- bool httpListener(const LLSD&);
- LLEventStream mEventPump;
-};
-
-#endif /* ! defined(LL_LLSDMESSAGE_H) */
diff --git a/indra/llmessage/llsdrpcclient.cpp b/indra/llmessage/llsdrpcclient.cpp
deleted file mode 100755
index eb773ceb3a..0000000000
--- a/indra/llmessage/llsdrpcclient.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/**
- * @file llsdrpcclient.cpp
- * @author Phoenix
- * @date 2005-11-05
- * @brief Implementation of the llsd client classes.
- *
- * $LicenseInfo:firstyear=2005&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 "llsdrpcclient.h"
-
-#include "llbufferstream.h"
-#include "llfasttimer.h"
-#include "llfiltersd2xmlrpc.h"
-#include "llpumpio.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-#include "llurlrequest.h"
-
-/**
- * String constants
- */
-static std::string LLSDRPC_RESPONSE_NAME("response");
-static std::string LLSDRPC_FAULT_NAME("fault");
-
-/**
- * LLSDRPCResponse
- */
-LLSDRPCResponse::LLSDRPCResponse() :
- mIsError(false),
- mIsFault(false)
-{
-}
-
-// virtual
-LLSDRPCResponse::~LLSDRPCResponse()
-{
-}
-
-bool LLSDRPCResponse::extractResponse(const LLSD& sd)
-{
- bool rv = true;
- if(sd.has(LLSDRPC_RESPONSE_NAME))
- {
- mReturnValue = sd[LLSDRPC_RESPONSE_NAME];
- mIsFault = false;
- }
- else if(sd.has(LLSDRPC_FAULT_NAME))
- {
- mReturnValue = sd[LLSDRPC_FAULT_NAME];
- mIsFault = true;
- }
- else
- {
- mReturnValue.clear();
- mIsError = true;
- rv = false;
- }
- return rv;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_SDRPC_RESPONSE("SDRPC Response");
-
-// virtual
-LLIOPipe::EStatus LLSDRPCResponse::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_SDRPC_RESPONSE);
- PUMP_DEBUG;
- if(mIsError)
- {
- error(pump);
- }
- else if(mIsFault)
- {
- fault(pump);
- }
- else
- {
- response(pump);
- }
- PUMP_DEBUG;
- return STATUS_DONE;
-}
-
-/**
- * LLSDRPCClient
- */
-
-LLSDRPCClient::LLSDRPCClient() :
- mState(STATE_NONE),
- mQueue(EPBQ_PROCESS)
-{
-}
-
-// virtual
-LLSDRPCClient::~LLSDRPCClient()
-{
-}
-
-bool LLSDRPCClient::call(
- const std::string& uri,
- const std::string& method,
- const LLSD& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue)
-{
- //LL_INFOS() << "RPC: " << uri << "." << method << "(" << *parameter << ")"
- // << LL_ENDL;
- if(method.empty() || !response)
- {
- return false;
- }
- mState = STATE_READY;
- mURI.assign(uri);
- std::stringstream req;
- req << LLSDRPC_REQUEST_HEADER_1 << method
- << LLSDRPC_REQUEST_HEADER_2;
- LLSDSerialize::toNotation(parameter, req);
- req << LLSDRPC_REQUEST_FOOTER;
- mRequest = req.str();
- mQueue = queue;
- mResponse = response;
- return true;
-}
-
-bool LLSDRPCClient::call(
- const std::string& uri,
- const std::string& method,
- const std::string& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue)
-{
- //LL_INFOS() << "RPC: " << uri << "." << method << "(" << parameter << ")"
- // << LL_ENDL;
- if(method.empty() || parameter.empty() || !response)
- {
- return false;
- }
- mState = STATE_READY;
- mURI.assign(uri);
- std::stringstream req;
- req << LLSDRPC_REQUEST_HEADER_1 << method
- << LLSDRPC_REQUEST_HEADER_2 << parameter
- << LLSDRPC_REQUEST_FOOTER;
- mRequest = req.str();
- mQueue = queue;
- mResponse = response;
- return true;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SDRPC_CLIENT("SDRPC Client");
-
-// virtual
-LLIOPipe::EStatus LLSDRPCClient::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_SDRPC_CLIENT);
- PUMP_DEBUG;
- if((STATE_NONE == mState) || (!pump))
- {
- // You should have called the call() method already.
- return STATUS_PRECONDITION_NOT_MET;
- }
- EStatus rv = STATUS_DONE;
- switch(mState)
- {
- case STATE_READY:
- {
- PUMP_DEBUG;
-// LL_DEBUGS() << "LLSDRPCClient::process_impl STATE_READY" << LL_ENDL;
- buffer->append(
- channels.out(),
- (U8*)mRequest.c_str(),
- mRequest.length());
- context[CONTEXT_DEST_URI_SD_LABEL] = mURI;
- mState = STATE_WAITING_FOR_RESPONSE;
- break;
- }
- case STATE_WAITING_FOR_RESPONSE:
- {
- PUMP_DEBUG;
- // The input channel has the sd response in it.
- //LL_DEBUGS() << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE"
- // << LL_ENDL;
- LLBufferStream resp(channels, buffer.get());
- LLSD sd;
- LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in()));
- LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get();
- if (!response)
- {
- mState = STATE_DONE;
- break;
- }
- response->extractResponse(sd);
- if(EPBQ_PROCESS == mQueue)
- {
- LLPumpIO::chain_t chain;
- chain.push_back(mResponse);
- pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS);
- }
- else
- {
- pump->respond(mResponse.get());
- }
- mState = STATE_DONE;
- break;
- }
- case STATE_DONE:
- default:
- PUMP_DEBUG;
- LL_INFOS() << "invalid state to process" << LL_ENDL;
- rv = STATUS_ERROR;
- break;
- }
- return rv;
-}
diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h
deleted file mode 100755
index c4e0333ca3..0000000000
--- a/indra/llmessage/llsdrpcclient.h
+++ /dev/null
@@ -1,323 +0,0 @@
-/**
- * @file llsdrpcclient.h
- * @author Phoenix
- * @date 2005-11-05
- * @brief Implementation and helpers for structure data RPC clients.
- *
- * $LicenseInfo:firstyear=2005&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_LLSDRPCCLIENT_H
-#define LL_LLSDRPCCLIENT_H
-
-/**
- * This file declares classes to encapsulate a basic structured data
- * remote procedure client.
- */
-
-#include "llchainio.h"
-#include "llfiltersd2xmlrpc.h"
-#include "lliopipe.h"
-#include "llurlrequest.h"
-
-/**
- * @class LLSDRPCClientResponse
- * @brief Abstract base class to represent a response from an SD server.
- *
- * This is used as a base class for callbacks generated from an
- * structured data remote procedure call. The
- * <code>extractResponse</code> method will deal with the llsdrpc method
- * call overhead, and keep track of what to call during the next call
- * into <code>process</code>. If you use this as a base class, you
- * need to implement <code>response</code>, <code>fault</code>, and
- * <code>error</code> to do something useful. When in those methods,
- * you can parse and utilize the mReturnValue member data.
- */
-class LLSDRPCResponse : public LLIOPipe
-{
-public:
- LLSDRPCResponse();
- virtual ~LLSDRPCResponse();
-
- /**
- * @brief This method extracts the response out of the sd passed in
- *
- * Any appropriate data found in the sd passed in will be
- * extracted and managed by this object - not copied or cloned. It
- * will still be up to the caller to delete the pointer passed in.
- * @param sd The raw structured data response from the remote server.
- * @return Returns true if this was able to parse the structured data.
- */
- bool extractResponse(const LLSD& sd);
-
-protected:
- /**
- * @brief Method called when the response is ready.
- */
- virtual bool response(LLPumpIO* pump) = 0;
-
- /**
- * @brief Method called when a fault is generated by the remote server.
- */
- virtual bool fault(LLPumpIO* pump) = 0;
-
- /**
- * @brief Method called when there was an error
- */
- virtual bool error(LLPumpIO* pump) = 0;
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- LLSD mReturnValue;
- bool mIsError;
- bool mIsFault;
-};
-
-/**
- * @class LLSDRPCClient
- * @brief Client class for a structured data remote procedure call.
- *
- * This class helps deal with making structured data calls to a remote
- * server. You can visualize the calls as:
- * <code>
- * response = uri.method(parameter)
- * </code>
- * where you pass in everything to <code>call</code> and this class
- * takes care of the rest of the details.
- * In typical usage, you will derive a class from this class and
- * provide an API more useful for the specific application at
- * hand. For example, if you were writing a service to send an instant
- * message, you could create an API for it to send the messsage, and
- * that class would do the work of translating it into the method and
- * parameter, find the destination, and invoke <code>call</call> with
- * a useful implementation of LLSDRPCResponse passed in to handle the
- * response from the network.
- */
-class LLSDRPCClient : public LLIOPipe
-{
-public:
- LLSDRPCClient();
- virtual ~LLSDRPCClient();
-
- /**
- * @brief Enumeration for tracking which queue to process the
- * response.
- */
- enum EPassBackQueue
- {
- EPBQ_PROCESS,
- EPBQ_CALLBACK,
- };
-
- /**
- * @brief Call a method on a remote LLSDRPCServer
- *
- * @param uri The remote object to call, eg,
- * http://localhost/usher. If you are using a factory with a fixed
- * url, the uri passed in will probably be ignored.
- * @param method The method to call on the remote object
- * @param parameter The parameter to pass into the remote
- * object. It is up to the caller to delete the value passed in.
- * @param response The object which gets the response.
- * @param queue Specifies to call the response on the process or
- * callback queue.
- * @return Returns true if this object will be able to make the RPC call.
- */
- bool call(
- const std::string& uri,
- const std::string& method,
- const LLSD& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue);
-
- /**
- * @brief Call a method on a remote LLSDRPCServer
- *
- * @param uri The remote object to call, eg,
- * http://localhost/usher. If you are using a factory with a fixed
- * url, the uri passed in will probably be ignored.
- * @param method The method to call on the remote object
- * @param parameter The seriailized parameter to pass into the
- * remote object.
- * @param response The object which gets the response.
- * @param queue Specifies to call the response on the process or
- * callback queue.
- * @return Returns true if this object will be able to make the RPC call.
- */
- bool call(
- const std::string& uri,
- const std::string& method,
- const std::string& parameter,
- LLSDRPCResponse* response,
- EPassBackQueue queue);
-
-protected:
- /**
- * @brief Enumeration for tracking client state.
- */
- enum EState
- {
- STATE_NONE,
- STATE_READY,
- STATE_WAITING_FOR_RESPONSE,
- STATE_DONE
- };
-
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- EState mState;
- std::string mURI;
- std::string mRequest;
- EPassBackQueue mQueue;
- LLIOPipe::ptr_t mResponse;
-};
-
-/**
- * @class LLSDRPCClientFactory
- * @brief Basic implementation for making an SD RPC client factory
- *
- * This class eases construction of a basic sd rpc client. Here is an
- * example of it's use:
- * <code>
- * class LLUsefulService : public LLService { ... }
- * LLService::registerCreator(
- * "useful",
- * LLService::creator_t(new LLSDRPCClientFactory<LLUsefulService>))
- * </code>
- */
-template<class Client>
-class LLSDRPCClientFactory : public LLChainIOFactory
-{
-public:
- LLSDRPCClientFactory() {}
- LLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLSDRPCClientFactory::build" << LL_ENDL;
- LLURLRequest* http(new LLURLRequest(HTTP_POST));
- if(!http->isValid())
- {
- LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ;
- delete http;
- return false;
- }
-
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
- LLIOPipe::ptr_t http_pipe(http);
- http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD);
- if(mURL.empty())
- {
- chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
- }
- else
- {
- http->setURL(mURL);
- }
- chain.push_back(http_pipe);
- chain.push_back(service);
- return true;
- }
-protected:
- std::string mURL;
-};
-
-/**
- * @class LLXMLSDRPCClientFactory
- * @brief Basic implementation for making an XMLRPC to SD RPC client factory
- *
- * This class eases construction of a basic sd rpc client which uses
- * xmlrpc as a serialization grammar. Here is an example of it's use:
- * <code>
- * class LLUsefulService : public LLService { ... }
- * LLService::registerCreator(
- * "useful",
- * LLService::creator_t(new LLXMLSDRPCClientFactory<LLUsefulService>))
- * </code>
- */
-template<class Client>
-class LLXMLSDRPCClientFactory : public LLChainIOFactory
-{
-public:
- LLXMLSDRPCClientFactory() {}
- LLXMLSDRPCClientFactory(const std::string& fixed_url) : mURL(fixed_url) {}
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLXMLSDRPCClientFactory::build" << LL_ENDL;
-
- LLURLRequest* http(new LLURLRequest(HTTP_POST));
- if(!http->isValid())
- {
- LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ;
- delete http;
- return false ;
- }
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
- LLIOPipe::ptr_t http_pipe(http);
- http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
- if(mURL.empty())
- {
- chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
- }
- else
- {
- http->setURL(mURL);
- }
- chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest(NULL)));
- chain.push_back(http_pipe);
- chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
- chain.push_back(service);
- return true;
- }
-protected:
- std::string mURL;
-};
-
-#endif // LL_LLSDRPCCLIENT_H
diff --git a/indra/llmessage/llsdrpcserver.cpp b/indra/llmessage/llsdrpcserver.cpp
deleted file mode 100755
index c3ed19889e..0000000000
--- a/indra/llmessage/llsdrpcserver.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * @file llsdrpcserver.cpp
- * @author Phoenix
- * @date 2005-10-11
- * @brief Implementation of the LLSDRPCServer and related classes.
- *
- * $LicenseInfo:firstyear=2005&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 "llsdrpcserver.h"
-
-#include "llbuffer.h"
-#include "llbufferstream.h"
-#include "llfasttimer.h"
-#include "llpumpio.h"
-#include "llsdserialize.h"
-#include "llstl.h"
-
-static const char FAULT_PART_1[] = "{'fault':{'code':i";
-static const char FAULT_PART_2[] = ", 'description':'";
-static const char FAULT_PART_3[] = "'}}";
-
-static const char RESPONSE_PART_1[] = "{'response':";
-static const char RESPONSE_PART_2[] = "}";
-
-static const S32 FAULT_GENERIC = 1000;
-static const S32 FAULT_METHOD_NOT_FOUND = 1001;
-
-static const std::string LLSDRPC_METHOD_SD_NAME("method");
-static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter");
-
-
-/**
- * LLSDRPCServer
- */
-LLSDRPCServer::LLSDRPCServer() :
- mState(LLSDRPCServer::STATE_NONE),
- mPump(NULL),
- mLock(0)
-{
-}
-
-LLSDRPCServer::~LLSDRPCServer()
-{
- std::for_each(
- mMethods.begin(),
- mMethods.end(),
- llcompose1(
- DeletePointerFunctor<LLSDRPCMethodCallBase>(),
- llselect2nd<method_map_t::value_type>()));
- std::for_each(
- mCallbackMethods.begin(),
- mCallbackMethods.end(),
- llcompose1(
- DeletePointerFunctor<LLSDRPCMethodCallBase>(),
- llselect2nd<method_map_t::value_type>()));
-}
-
-
-// virtual
-ESDRPCSStatus LLSDRPCServer::deferredResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data) {
- // subclass should provide a sane implementation
- return ESDRPCS_DONE;
-}
-
-void LLSDRPCServer::clearLock()
-{
- if(mLock && mPump)
- {
- mPump->clearLock(mLock);
- mPump = NULL;
- mLock = 0;
- }
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_SDRPC_SERVER("SDRPC Server");
-
-// virtual
-LLIOPipe::EStatus LLSDRPCServer::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_SDRPC_SERVER);
- PUMP_DEBUG;
-// LL_DEBUGS() << "LLSDRPCServer::process_impl" << LL_ENDL;
- // Once we have all the data, We need to read the sd on
- // the the in channel, and respond on the out channel
- if(!eos) return STATUS_BREAK;
- if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
-
- std::string method_name;
- LLIOPipe::EStatus status = STATUS_DONE;
-
- switch(mState)
- {
- case STATE_DEFERRED:
- PUMP_DEBUG;
- if(ESDRPCS_DONE != deferredResponse(channels, buffer.get()))
- {
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "deferred response failed.");
- }
- mState = STATE_DONE;
- return STATUS_DONE;
-
- case STATE_DONE:
-// LL_DEBUGS() << "STATE_DONE" << LL_ENDL;
- break;
- case STATE_CALLBACK:
-// LL_DEBUGS() << "STATE_CALLBACK" << LL_ENDL;
- PUMP_DEBUG;
- method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
- if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
- {
- if(ESDRPCS_DONE != callbackMethod(
- method_name,
- mRequest[LLSDRPC_PARAMETER_SD_NAME],
- channels,
- buffer.get()))
- {
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Callback method call failed.");
- }
- }
- else
- {
- // this should never happen, since we should not be in
- // this state unless we originally found a method and
- // params during the first call to process.
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Invalid LLSDRPC sever state - callback without method.");
- }
- pump->clearLock(mLock);
- mLock = 0;
- mState = STATE_DONE;
- break;
- case STATE_NONE:
-// LL_DEBUGS() << "STATE_NONE" << LL_ENDL;
- default:
- {
- // First time we got here - process the SD request, and call
- // the method.
- PUMP_DEBUG;
- LLBufferStream istr(channels, buffer.get());
- mRequest.clear();
- LLSDSerialize::fromNotation(
- mRequest,
- istr,
- buffer->count(channels.in()));
-
- // { 'method':'...', 'parameter': ... }
- method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
- if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
- {
- ESDRPCSStatus rv = callMethod(
- method_name,
- mRequest[LLSDRPC_PARAMETER_SD_NAME],
- channels,
- buffer.get());
- switch(rv)
- {
- case ESDRPCS_DEFERRED:
- mPump = pump;
- mLock = pump->setLock();
- mState = STATE_DEFERRED;
- status = STATUS_BREAK;
- break;
-
- case ESDRPCS_CALLBACK:
- {
- mState = STATE_CALLBACK;
- LLPumpIO::LLLinkInfo link;
- link.mPipe = LLIOPipe::ptr_t(this);
- link.mChannels = channels;
- LLPumpIO::links_t links;
- links.push_back(link);
- pump->respond(links, buffer, context);
- mLock = pump->setLock();
- status = STATUS_BREAK;
- break;
- }
- case ESDRPCS_DONE:
- mState = STATE_DONE;
- break;
- case ESDRPCS_ERROR:
- default:
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Method call failed.");
- break;
- }
- }
- else
- {
- // send a fault
- buildFault(
- channels,
- buffer.get(),
- FAULT_GENERIC,
- "Unable to find method and parameter in request.");
- }
- break;
- }
- }
-
- PUMP_DEBUG;
- return status;
-}
-
-// virtual
-ESDRPCSStatus LLSDRPCServer::callMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* response)
-{
- // Try to find the method in the method table.
- ESDRPCSStatus rv = ESDRPCS_DONE;
- method_map_t::iterator it = mMethods.find(method);
- if(it != mMethods.end())
- {
- rv = (*it).second->call(params, channels, response);
- }
- else
- {
- it = mCallbackMethods.find(method);
- if(it == mCallbackMethods.end())
- {
- // method not found.
- std::ostringstream message;
- message << "rpc server unable to find method: " << method;
- buildFault(
- channels,
- response,
- FAULT_METHOD_NOT_FOUND,
- message.str());
- }
- else
- {
- // we found it in the callback methods - tell the process
- // to coordinate calling on the pump callback.
- return ESDRPCS_CALLBACK;
- }
- }
- return rv;
-}
-
-// virtual
-ESDRPCSStatus LLSDRPCServer::callbackMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* response)
-{
- // Try to find the method in the callback method table.
- ESDRPCSStatus rv = ESDRPCS_DONE;
- method_map_t::iterator it = mCallbackMethods.find(method);
- if(it != mCallbackMethods.end())
- {
- rv = (*it).second->call(params, channels, response);
- }
- else
- {
- std::ostringstream message;
- message << "pcserver unable to find callback method: " << method;
- buildFault(
- channels,
- response,
- FAULT_METHOD_NOT_FOUND,
- message.str());
- }
- return rv;
-}
-
-// static
-void LLSDRPCServer::buildFault(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- S32 code,
- const std::string& msg)
-{
- LLBufferStream ostr(channels, data);
- ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3;
- LL_INFOS() << "LLSDRPCServer::buildFault: " << code << ", " << msg << LL_ENDL;
-}
-
-// static
-void LLSDRPCServer::buildResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- const LLSD& response)
-{
- LLBufferStream ostr(channels, data);
- ostr << RESPONSE_PART_1;
- LLSDSerialize::toNotation(response, ostr);
- ostr << RESPONSE_PART_2;
-#if LL_DEBUG
- std::ostringstream debug_ostr;
- debug_ostr << "LLSDRPCServer::buildResponse: ";
- LLSDSerialize::toNotation(response, debug_ostr);
- LL_INFOS() << debug_ostr.str() << LL_ENDL;
-#endif
-}
diff --git a/indra/llmessage/llsdrpcserver.h b/indra/llmessage/llsdrpcserver.h
deleted file mode 100755
index 415bd31c26..0000000000
--- a/indra/llmessage/llsdrpcserver.h
+++ /dev/null
@@ -1,360 +0,0 @@
-/**
- * @file llsdrpcserver.h
- * @author Phoenix
- * @date 2005-10-11
- * @brief Declaration of the structured data remote procedure call server.
- *
- * $LicenseInfo:firstyear=2005&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_LLSDRPCSERVER_H
-#define LL_LLSDRPCSERVER_H
-
-/**
- * I've set this up to be pretty easy to use when you want to make a
- * structured data rpc server which responds to methods by
- * name. Derive a class from the LLSDRPCServer, and during
- * construction (or initialization if you have the luxury) map method
- * names to pointers to member functions. This will look a lot like:
- *
- * <code>
- * class LLMessageAgents : public LLSDRPCServer {<br>
- * public:<br>
- * typedef LLSDRPCServer<LLUsher> mem_fn_t;<br>
- * LLMessageAgents() {<br>
- * mMethods["message"] = new mem_fn_t(this, &LLMessageAgents::rpc_IM);<br>
- * mMethods["alert"] = new mem_fn_t(this, &LLMessageAgents::rpc_Alrt);<br>
- * }<br>
- * protected:<br>
- * rpc_IM(const LLSD& params,
- * const LLChannelDescriptors& channels,
- * LLBufferArray* data)
- * {...}<br>
- * rpc_Alert(const LLSD& params,
- * const LLChannelDescriptors& channels,
- * LLBufferArray* data)
- * {...}<br>
- * };<br>
- * </code>
- *
- * The params are an array where each element in the array is a single
- * parameter in the call.
- *
- * It is up to you to pack a valid serialized llsd response into the
- * data object passed into the method, but you can use the helper
- * methods below to help.
- */
-
-#include <map>
-#include "lliopipe.h"
-#include "lliohttpserver.h"
-#include "llfiltersd2xmlrpc.h"
-
-class LLSD;
-
-/**
- * @brief Enumeration for specifying server method call status. This
- * enumeration controls how the server class will manage the pump
- * process/callback mechanism.
- */
-enum ESDRPCSStatus
-{
- // The call went ok, but the response is not yet ready. The
- // method will arrange for the clearLock() call to be made at
- // a later date, after which, once the chain is being pumped
- // again, deferredResponse() will be called to gather the result
- ESDRPCS_DEFERRED,
-
- // The LLSDRPCServer would like to handle the method on the
- // callback queue of the pump.
- ESDRPCS_CALLBACK,
-
- // The method call finished and generated output.
- ESDRPCS_DONE,
-
- // Method failed for some unspecified reason - you should avoid
- // this. A generic fault will be sent to the output.
- ESDRPCS_ERROR,
-
- ESDRPCS_COUNT,
-};
-
-/**
- * @class LLSDRPCMethodCallBase
- * @brief Base class for calling a member function in an sd rpcserver
- * implementation.
- */
-class LLSDRPCMethodCallBase
-{
-public:
- LLSDRPCMethodCallBase() {}
- virtual ~LLSDRPCMethodCallBase() {}
-
- virtual ESDRPCSStatus call(
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* response) = 0;
-protected:
-};
-
-/**
- * @class LLSDRPCMethodCall
- * @brief Class which implements member function calls.
- */
-template<class Server>
-class LLSDRPCMethodCall : public LLSDRPCMethodCallBase
-{
-public:
- typedef ESDRPCSStatus (Server::*mem_fn)(
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
- LLSDRPCMethodCall(Server* s, mem_fn fn) :
- mServer(s),
- mMemFn(fn)
- {
- }
- virtual ~LLSDRPCMethodCall() {}
- virtual ESDRPCSStatus call(
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data)
- {
- return (*mServer.*mMemFn)(params, channels, data);
- }
-
-protected:
- Server* mServer;
- mem_fn mMemFn;
- //bool (Server::*mMemFn)(const LLSD& params, LLBufferArray& data);
-};
-
-
-/**
- * @class LLSDRPCServer
- * @brief Basic implementation of a structure data rpc server
- *
- * The rpc server is also designed to appropriately straddle the pump
- * <code>process()</code> and <code>callback()</code> to specify which
- * thread you want to work on when handling a method call. The
- * <code>mMethods</code> methods are called from
- * <code>process()</code>, while the <code>mCallbackMethods</code> are
- * called when a pump is in a <code>callback()</code> cycle.
- */
-class LLSDRPCServer : public LLIOPipe
-{
-public:
- LLSDRPCServer();
- virtual ~LLSDRPCServer();
-
- /**
- * enumeration for generic fault codes
- */
- enum
- {
- FAULT_BAD_REQUEST = 2000,
- FAULT_NO_RESPONSE = 2001,
- };
-
- /**
- * @brief Call this method to return an rpc fault.
- *
- * @param channel The channel for output on the data buffer
- * @param data buffer which will recieve the final output
- * @param code The fault code
- * @param msg The fault message
- */
- static void buildFault(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- S32 code,
- const std::string& msg);
-
- /**
- * @brief Call this method to build an rpc response.
- *
- * @param channel The channel for output on the data buffer
- * @param data buffer which will recieve the final output
- * @param response The return value from the method call
- */
- static void buildResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data,
- const LLSD& response);
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
-
- /**
- * @brief Enumeration to track the state of the rpc server instance
- */
- enum EState
- {
- STATE_NONE,
- STATE_CALLBACK,
- STATE_DEFERRED,
- STATE_DONE
- };
-
- /**
- * @brief This method is called when an http post comes in.
- *
- * The default behavior is to look at the method name, look up the
- * method in the method table, and call it. If the method is not
- * found, this function will build a fault response. You can
- * implement your own version of this function if you want to hard
- * wire some behavior or optimize things a bit.
- * @param method The method name being called
- * @param params The parameters
- * @param channel The channel for output on the data buffer
- * @param data The http data
- * @return Returns the status of the method call, done/deferred/etc
- */
- virtual ESDRPCSStatus callMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
-
- /**
- * @brief This method is called when a pump callback is processed.
- *
- * The default behavior is to look at the method name, look up the
- * method in the callback method table, and call it. If the method
- * is not found, this function will build a fault response. You
- * can implement your own version of this function if you want to
- * hard wire some behavior or optimize things a bit.
- * @param method The method name being called
- * @param params The parameters
- * @param channel The channel for output on the data buffer
- * @param data The http data
- * @return Returns the status of the method call, done/deferred/etc
- */
- virtual ESDRPCSStatus callbackMethod(
- const std::string& method,
- const LLSD& params,
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
-
- /**
- * @brief Called after a deferred service is unlocked
- *
- * If a method returns ESDRPCS_DEFERRED, then the service chain
- * will be locked and not processed until some other system calls
- * clearLock() on the service instance again. At that point,
- * once the pump starts processing the chain again, this method
- * will be called so the service can output the final result
- * into the buffers.
- */
- virtual ESDRPCSStatus deferredResponse(
- const LLChannelDescriptors& channels,
- LLBufferArray* data);
-
- // donovan put this public here 7/27/06
-public:
- /**
- * @brief unlock a service that as ESDRPCS_DEFERRED
- */
- void clearLock();
-
-protected:
- EState mState;
- LLSD mRequest;
- LLPumpIO* mPump;
- S32 mLock;
- typedef std::map<std::string, LLSDRPCMethodCallBase*> method_map_t;
- method_map_t mMethods;
- method_map_t mCallbackMethods;
-};
-
-/**
- * @name Helper Templates for making LLHTTPNodes
- *
- * These templates help in creating nodes for handing a service from
- * either SDRPC or XMLRPC, given a single implementation of LLSDRPCServer.
- *
- * To use it:
- * \code
- * class LLUsefulServer : public LLSDRPCServer { ... }
- *
- * LLHTTPNode& root = LLCreateHTTPWireServer(...);
- * root.addNode("llsdrpc/useful", new LLSDRPCNode<LLUsefulServer>);
- * root.addNode("xmlrpc/useful", new LLXMLRPCNode<LLUsefulServer>);
- * \endcode
- */
-//@{
-
-template<class Server>
-class LLSDRPCServerFactory : public LLChainIOFactory
-{
-public:
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLXMLSDRPCServerFactory::build" << LL_ENDL;
- chain.push_back(LLIOPipe::ptr_t(new Server));
- return true;
- }
-};
-
-template<class Server>
-class LLSDRPCNode : public LLHTTPNodeForFactory<
- LLSDRPCServerFactory<Server> >
-{
-};
-
-template<class Server>
-class LLXMLRPCServerFactory : public LLChainIOFactory
-{
-public:
- virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
- {
- LL_DEBUGS() << "LLXMLSDRPCServerFactory::build" << LL_ENDL;
- chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
- chain.push_back(LLIOPipe::ptr_t(new Server));
- chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
- return true;
- }
-};
-
-template<class Server>
-class LLXMLRPCNode : public LLHTTPNodeForFactory<
- LLXMLRPCServerFactory<Server> >
-{
-};
-
-//@}
-
-#endif // LL_LLSDRPCSERVER_H
diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp
index 5bd1112cfe..33944f7883 100755
--- a/indra/llmessage/lltrustedmessageservice.cpp
+++ b/indra/llmessage/lltrustedmessageservice.cpp
@@ -30,6 +30,7 @@
#include "llhost.h"
#include "llmessageconfig.h"
#include "message.h"
+#include "llhttpconstants.h"
bool LLTrustedMessageService::validate(const std::string& name, LLSD& context)
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
deleted file mode 100755
index 1294379eca..0000000000
--- a/indra/llmessage/llurlrequest.cpp
+++ /dev/null
@@ -1,783 +0,0 @@
-/**
- * @file llurlrequest.cpp
- * @author Phoenix
- * @date 2005-04-28
- * @brief Implementation of the URLRequest class and related classes.
- *
- * $LicenseInfo:firstyear=2005&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 "llurlrequest.h"
-
-#include <algorithm>
-#include <openssl/x509_vfy.h>
-#include <openssl/ssl.h>
-#include "llcurl.h"
-#include "llfasttimer.h"
-#include "llioutil.h"
-#include "llproxy.h"
-#include "llpumpio.h"
-#include "llsd.h"
-#include "llstring.h"
-#include "apr_env.h"
-#include "llapr.h"
-
-/**
- * String constants
- */
-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
- */
-class LLURLRequestDetail
-{
-public:
- LLURLRequestDetail();
- ~LLURLRequestDetail();
- std::string mURL;
- LLCurlEasyRequest* mCurlRequest;
- LLIOPipe::buffer_ptr_t mResponseBuffer;
- LLChannelDescriptors mChannels;
- U8* mLastRead;
- U32 mBodyLimit;
- S32 mByteAccumulator;
- bool mIsBodyLimitSet;
- LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback;
-};
-
-LLURLRequestDetail::LLURLRequestDetail() :
- mCurlRequest(NULL),
- mLastRead(NULL),
- mBodyLimit(0),
- mByteAccumulator(0),
- mIsBodyLimitSet(false),
- mSSLVerifyCallback(NULL)
-{
- mCurlRequest = new LLCurlEasyRequest();
-
- if(!mCurlRequest->isValid()) //failed.
- {
- delete mCurlRequest ;
- mCurlRequest = NULL ;
- }
-}
-
-LLURLRequestDetail::~LLURLRequestDetail()
-{
- delete mCurlRequest;
- mLastRead = NULL;
-}
-
-void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
-{
- mDetail->mSSLVerifyCallback = callback;
- mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true);
- mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);
-}
-
-
-// _sslCtxFunction
-// Callback function called when an SSL Context is created via CURL
-// used to configure the context for custom cert validation
-
-CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
-{
- LLURLRequest *req = (LLURLRequest *)param;
- if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL)
- {
- SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL);
- return CURLE_OK;
- }
- SSL_CTX * ctx = (SSL_CTX *) sslctx;
- // disable any default verification for server certs
- SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
- // set the verification callback.
- SSL_CTX_set_cert_verify_callback(ctx, req->mDetail->mSSLVerifyCallback, (void *)req);
- // the calls are void
- return CURLE_OK;
-
-}
-
-/**
- * class LLURLRequest
- */
-
-
-LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) :
- mAction(action),
- mFollowRedirects(follow_redirects)
-{
- initialize();
-}
-
-LLURLRequest::LLURLRequest(
- EHTTPMethod action,
- const std::string& url,
- bool follow_redirects /* = true */) :
- mAction(action),
- mFollowRedirects(follow_redirects)
-{
- initialize();
- setURL(url);
-}
-
-LLURLRequest::~LLURLRequest()
-{
- delete mDetail;
- mDetail = NULL ;
-}
-
-void LLURLRequest::setURL(const std::string& url)
-{
- mDetail->mURL = url;
- if (url.empty())
- {
- LL_WARNS() << "empty URL specified" << LL_ENDL;
- }
-}
-
-const std::string& LLURLRequest::getURL() const
-{
- return mDetail->mURL;
-}
-
-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);
-}
-
-void LLURLRequest::setBodyLimit(U32 size)
-{
- mDetail->mBodyLimit = size;
- mDetail->mIsBodyLimitSet = true;
-}
-
-void LLURLRequest::setCallback(LLURLRequestComplete* callback)
-{
- mCompletionCallback = callback;
- mDetail->mCurlRequest->setHeaderCallback(&headerCallback, (void*)callback);
-}
-
-// Added to mitigate the effect of libcurl looking
-// for the ALL_PROXY and http_proxy env variables
-// and deciding to insert a Pragma: no-cache
-// header! The only usage of this method at the
-// time of this writing is in llhttpclient.cpp
-// in the request() method, where this method
-// is called with use_proxy = FALSE
-void LLURLRequest::useProxy(bool use_proxy)
-{
- static char *env_proxy;
-
- if (use_proxy && (env_proxy == NULL))
- {
- apr_status_t status;
- LLAPRPool pool;
- status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
- if (status != APR_SUCCESS)
- {
- status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
- }
- if (status != APR_SUCCESS)
- {
- use_proxy = FALSE;
- }
- }
-
-
- LL_DEBUGS() << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL;
-
- if (env_proxy && use_proxy)
- {
- mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
- }
- else
- {
- mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, "");
- }
-}
-
-void LLURLRequest::useProxy(const std::string &proxy)
-{
- mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy);
-}
-
-void LLURLRequest::allowCookies()
-{
- mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");
-}
-
-//virtual
-bool LLURLRequest::isValid()
-{
- return mDetail->mCurlRequest && mDetail->mCurlRequest->isValid();
-}
-
-// virtual
-LLIOPipe::EStatus LLURLRequest::handleError(
- LLIOPipe::EStatus status,
- LLPumpIO* pump)
-{
- if(!isValid())
- {
- return STATUS_EXPIRED ;
- }
-
- if(mCompletionCallback && pump)
- {
- LLURLRequestComplete* complete = NULL;
- complete = (LLURLRequestComplete*)mCompletionCallback.get();
- complete->httpStatus(
- HTTP_INTERNAL_ERROR,
- LLIOPipe::lookupStatusString(status));
- complete->responseStatus(status);
- pump->respond(complete);
- mCompletionCallback = NULL;
- }
- return status;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_REQUEST("URL Request");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result");
-static LLTrace::BlockTimerStatHandle FTM_URL_PERFORM("Perform");
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_PUMP_RESPOND("Pump Respond");
-static LLTrace::BlockTimerStatHandle FTM_URL_ADJUST_TIMEOUT("Adjust Timeout");
-
-// virtual
-LLIOPipe::EStatus LLURLRequest::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_REQUEST);
- PUMP_DEBUG;
- //LL_INFOS() << "LLURLRequest::process_impl()" << LL_ENDL;
- if (!buffer) return STATUS_ERROR;
-
- // we're still waiting or prcessing, check how many
- // bytes we have accumulated.
- const S32 MIN_ACCUMULATION = 100000;
- if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
- {
- LL_RECORD_BLOCK_TIME(FTM_URL_ADJUST_TIMEOUT);
- // This is a pretty sloppy calculation, but this
- // tries to make the gross assumption that if data
- // is coming in at 56kb/s, then this transfer will
- // probably succeed. So, if we're accumlated
- // 100,000 bytes (MIN_ACCUMULATION) then let's
- // give this client another 2s to complete.
- const F32 TIMEOUT_ADJUSTMENT = 2.0f;
- mDetail->mByteAccumulator = 0;
- pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
- LL_DEBUGS() << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << LL_ENDL;
- if (mState == STATE_INITIALIZED)
- {
- LL_INFOS() << "LLURLRequest adjustTimeoutSeconds called during upload" << LL_ENDL;
- }
- }
-
- switch(mState)
- {
- case STATE_INITIALIZED:
- {
- PUMP_DEBUG;
- // We only need to wait for input if we are uploading
- // something.
- if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos)
- {
- // we're waiting to get all of the information
- return STATUS_BREAK;
- }
-
- // *FIX: bit of a hack, but it should work. The configure and
- // callback method expect this information to be ready.
- mDetail->mResponseBuffer = buffer;
- mDetail->mChannels = channels;
- if(!configure())
- {
- return STATUS_ERROR;
- }
- mState = STATE_WAITING_FOR_RESPONSE;
-
- // *FIX: Maybe we should just go to the next state now...
- return STATUS_BREAK;
- }
- case STATE_WAITING_FOR_RESPONSE:
- case STATE_PROCESSING_RESPONSE:
- {
- PUMP_DEBUG;
- LLIOPipe::EStatus status = STATUS_BREAK;
- {
- LL_RECORD_BLOCK_TIME(FTM_URL_PERFORM);
- if(!mDetail->mCurlRequest->wait())
- {
- return status ;
- }
- }
-
- bool keep_looping = true;
- while(keep_looping)
- {
- CURLcode result;
-
- bool newmsg = false;
- {
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_REQUEST_GET_RESULT);
- newmsg = mDetail->mCurlRequest->getResult(&result);
- }
-
- if(!newmsg)
- {
- // keep processing
- break;
- }
-
-
- mState = STATE_HAVE_RESPONSE;
- context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
- context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
- LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL;
- switch(result)
- {
- case CURLE_OK:
- case CURLE_WRITE_ERROR:
- // NB: The error indication means that we stopped the
- // writing due the body limit being reached
- if(mCompletionCallback && pump)
- {
- LLURLRequestComplete* complete = NULL;
- complete = (LLURLRequestComplete*)
- mCompletionCallback.get();
- complete->responseStatus(
- result == CURLE_OK
- ? STATUS_OK : STATUS_STOP);
- LLPumpIO::links_t chain;
- LLPumpIO::LLLinkInfo link;
- link.mPipe = mCompletionCallback;
- link.mChannels = LLBufferArray::makeChannelConsumer(
- channels);
- chain.push_back(link);
- {
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_PUMP_RESPOND);
- pump->respond(chain, buffer, context);
- }
- mCompletionCallback = NULL;
- }
- break;
- case CURLE_FAILED_INIT:
- case CURLE_COULDNT_CONNECT:
- status = STATUS_NO_CONNECTION;
- keep_looping = false;
- break;
- default: // CURLE_URL_MALFORMAT
- LL_WARNS() << "URLRequest Error: " << result
- << ", "
- << LLCurl::strerror(result)
- << ", "
- << (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL)
- << LL_ENDL;
- status = STATUS_ERROR;
- keep_looping = false;
- break;
- }
- }
- return status;
- }
- case STATE_HAVE_RESPONSE:
- PUMP_DEBUG;
- // we already stuffed everything into channel in in the curl
- // callback, so we are done.
- eos = true;
- context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
- context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
- LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL;
- return STATUS_DONE;
-
- default:
- PUMP_DEBUG;
- context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
- context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
- LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL;
- return STATUS_ERROR;
- }
-}
-
-void LLURLRequest::initialize()
-{
- mState = STATE_INITIALIZED;
- mDetail = new LLURLRequestDetail;
-
- if(!isValid())
- {
- return ;
- }
-
- mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
- mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
- mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
- mRequestTransferedBytes = 0;
- mResponseTransferedBytes = 0;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_URL_REQUEST_CONFIGURE("URL Configure");
-bool LLURLRequest::configure()
-{
- LL_RECORD_BLOCK_TIME(FTM_URL_REQUEST_CONFIGURE);
-
- bool rv = false;
- S32 bytes = mDetail->mResponseBuffer->countAfter(
- mDetail->mChannels.in(),
- NULL);
- switch(mAction)
- {
- case HTTP_HEAD:
- mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1);
- mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1);
- if (mFollowRedirects)
- {
- mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
- }
- rv = true;
- break;
- case HTTP_GET:
- mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
- if (mFollowRedirects)
- {
- mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
- }
-
- // Set Accept-Encoding to allow response compression
- mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
- rv = true;
- break;
-
- 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(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(HTTP_OUT_HEADER_EXPECT);
-
- // Disable the content type http header.
- // *FIX: what should it be?
- addHeader(HTTP_OUT_HEADER_CONTENT_TYPE);
-
- // Set the handle for an http post
- mDetail->mCurlRequest->setPost(NULL, bytes);
-
- // Set Accept-Encoding to allow response compression
- mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
- rv = true;
- break;
-
- case HTTP_DELETE:
- // 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 move
- mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
- // *NOTE: should we check for the Destination header?
- rv = true;
- break;
-
- default:
- LL_WARNS() << "Unhandled URLRequest action: " << mAction << LL_ENDL;
- break;
- }
- if(rv)
- {
- mDetail->mCurlRequest->sendRequest(mDetail->mURL);
- }
- return rv;
-}
-
-// static
-size_t LLURLRequest::downCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user)
-{
- LLURLRequest* req = (LLURLRequest*)user;
- if(STATE_WAITING_FOR_RESPONSE == req->mState)
- {
- req->mState = STATE_PROCESSING_RESPONSE;
- }
- U32 bytes = size * nmemb;
- if (req->mDetail->mIsBodyLimitSet)
- {
- if (bytes > req->mDetail->mBodyLimit)
- {
- bytes = req->mDetail->mBodyLimit;
- req->mDetail->mBodyLimit = 0;
- }
- else
- {
- req->mDetail->mBodyLimit -= bytes;
- }
- }
-
- req->mDetail->mResponseBuffer->append(
- req->mDetail->mChannels.out(),
- (U8*)data,
- bytes);
- req->mResponseTransferedBytes += bytes;
- req->mDetail->mByteAccumulator += bytes;
- return bytes;
-}
-
-// static
-size_t LLURLRequest::upCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user)
-{
- LLURLRequest* req = (LLURLRequest*)user;
- S32 bytes = llmin(
- (S32)(size * nmemb),
- req->mDetail->mResponseBuffer->countAfter(
- req->mDetail->mChannels.in(),
- req->mDetail->mLastRead));
- req->mDetail->mLastRead = req->mDetail->mResponseBuffer->readAfter(
- req->mDetail->mChannels.in(),
- req->mDetail->mLastRead,
- (U8*)data,
- bytes);
- req->mRequestTransferedBytes += bytes;
- return bytes;
-}
-
-static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)
-{
- const char* header_line = (const char*)data;
- size_t header_len = size * nmemb;
- LLURLRequestComplete* complete = (LLURLRequestComplete*)user;
-
- if (!complete || !header_line)
- {
- return header_len;
- }
-
- // *TODO: This should be a utility in llstring.h: isascii()
- for (size_t i = 0; i < header_len; ++i)
- {
- if (header_line[i] < 0)
- {
- return header_len;
- }
- }
-
- std::string header(header_line, header_len);
-
- // Per HTTP spec the first header line must be the status line.
- if (header.substr(0,5) == "HTTP/")
- {
- std::string::iterator end = header.end();
- std::string::iterator pos1 = std::find(header.begin(), end, ' ');
- if (pos1 != end) ++pos1;
- std::string::iterator pos2 = std::find(pos1, end, ' ');
- if (pos2 != end) ++pos2;
- std::string::iterator pos3 = std::find(pos2, end, '\r');
-
- std::string version(header.begin(), pos1);
- std::string status(pos1, pos2);
- std::string reason(pos2, pos3);
-
- S32 status_code = atoi(status.c_str());
- if (status_code > 0)
- {
- complete->httpStatus(status_code, reason);
- return header_len;
- }
- }
-
- std::string::iterator sep = std::find(header.begin(),header.end(),':');
-
- if (sep != header.end())
- {
- std::string key(header.begin(), sep);
- std::string value(sep + 1, header.end());
-
- key = utf8str_tolower(utf8str_trim(key));
- value = utf8str_trim(value);
-
- complete->header(key, value);
- }
- else
- {
- LLStringUtil::trim(header);
- if (!header.empty())
- {
- LL_WARNS() << "Unable to parse header: " << header << LL_ENDL;
- }
- }
-
- return header_len;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_EXTRACTOR("URL Extractor");
-/**
- * LLContextURLExtractor
- */
-// virtual
-LLIOPipe::EStatus LLContextURLExtractor::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_EXTRACTOR);
- PUMP_DEBUG;
- // The destination host is in the context.
- if(context.isUndefined() || !mRequest)
- {
- return STATUS_PRECONDITION_NOT_MET;
- }
-
- // copy in to out, since this just extract the URL and does not
- // actually change the data.
- LLChangeChannel change(channels.in(), channels.out());
- std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
-
- // find the context url
- if(context.has(CONTEXT_DEST_URI_SD_LABEL))
- {
- mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString());
- return STATUS_DONE;
- }
- return STATUS_ERROR;
-}
-
-
-/**
- * LLURLRequestComplete
- */
-LLURLRequestComplete::LLURLRequestComplete() :
- mRequestStatus(LLIOPipe::STATUS_ERROR)
-{
-}
-
-// virtual
-LLURLRequestComplete::~LLURLRequestComplete()
-{
-}
-
-//virtual
-void LLURLRequestComplete::header(const std::string& header, const std::string& value)
-{
-}
-
-//virtual
-void LLURLRequestComplete::complete(const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer)
-{
- if(STATUS_OK == mRequestStatus)
- {
- response(channels, buffer);
- }
- else
- {
- noResponse();
- }
-}
-
-//virtual
-void LLURLRequestComplete::response(const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer)
-{
- LL_WARNS() << "LLURLRequestComplete::response default implementation called"
- << LL_ENDL;
-}
-
-//virtual
-void LLURLRequestComplete::noResponse()
-{
- LL_WARNS() << "LLURLRequestComplete::noResponse default implementation called"
- << LL_ENDL;
-}
-
-void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status)
-{
- mRequestStatus = status;
-}
-
-static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_COMPLETE("URL Complete");
-// virtual
-LLIOPipe::EStatus LLURLRequestComplete::process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump)
-{
- LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_COMPLETE);
- PUMP_DEBUG;
- complete(channels, buffer);
- return STATUS_OK;
-}
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
deleted file mode 100755
index 88fccd4bf6..0000000000
--- a/indra/llmessage/llurlrequest.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/**
- * @file llurlrequest.h
- * @author Phoenix
- * @date 2005-04-21
- * @brief Declaration of url based requests on pipes.
- *
- * $LicenseInfo:firstyear=2005&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_LLURLREQUEST_H
-#define LL_LLURLREQUEST_H
-
-/**
- * This file holds the declaration of useful classes for dealing with
- * url based client requests.
- */
-
-#include <string>
-#include "lliopipe.h"
-#include "llchainio.h"
-#include "llerror.h"
-#include <openssl/x509_vfy.h>
-#include "llcurl.h"
-
-
-/**
- * External constants
- */
-extern const std::string CONTEXT_DEST_URI_SD_LABEL;
-extern const std::string CONTEXT_TRANSFERED_BYTES;
-
-class LLURLRequestDetail;
-
-class LLURLRequestComplete;
-
-/**
- * @class LLURLRequest
- * @brief Class to handle url based requests.
- * @see LLIOPipe
- *
- * Currently, this class is implemented on top of curl. From the
- * vantage of a programmer using this class, you do not care so much,
- * but it's useful to know since in order to accomplish 'non-blocking'
- * behavior, we have to use a more expensive curl interface which can
- * still block if the server enters a half-accepted state. It would be
- * worth the time and effort to eventually port this to a raw client
- * socket.
- */
-class LLURLRequest : public LLIOPipe
-{
- LOG_CLASS(LLURLRequest);
-public:
- typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param);
-
- /**
- * @brief Constructor.
- *
- * @param action One of the EHTTPMethod enumerations.
- */
- LLURLRequest(EHTTPMethod action, bool follow_redirects = true);
-
- /**
- * @brief Constructor.
- *
- * @param action One of the EHTTPMethod enumerations.
- * @param url The url of the request. It should already be encoded.
- */
- LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true);
-
- /**
- * @brief Destructor.
- */
- virtual ~LLURLRequest();
-
- /* @name Instance methods
- */
- //@{
- /**
- * @brief Set the url for the request
- *
- * This method assumes the url is encoded appropriately for the
- * request.
- * The url must be set somehow before the first call to process(),
- * or the url will not be set correctly.
- *
- */
- void setURL(const std::string& url);
- const std::string& getURL() const;
- /**
- * @brief Add a header to the http post.
- *
- * 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 std::string& header, const std::string& value = "");
- void addHeaderRaw(const char* header);
-
- /**
- * @brief Check remote server certificate signed by a known root CA.
- *
- * Set whether request will check that remote server
- * certificates are signed by a known root CA when using HTTPS.
- */
- void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param);
-
-
- /**
- * @brief Return at most size bytes of body.
- *
- * If the body had more bytes than this limit, they will not be
- * returned and the connection closed. In this case, STATUS_STOP
- * will be passed to responseStatus();
- */
- void setBodyLimit(U32 size);
-
- /**
- * @brief Set a completion callback for this URLRequest.
- *
- * The callback is added to this URLRequet's pump when either the
- * entire buffer is known or an error like timeout or connection
- * refused has happened. In the case of a complete transfer, this
- * object builds a response chain such that the callback and the
- * next process consumer get to read the output.
- *
- * This setup is a little fragile since the url request consumer
- * might not just read the data - it may do a channel change,
- * which invalidates the input to the callback, but it works well
- * in practice.
- */
- void setCallback(LLURLRequestComplete* callback);
- //@}
-
- /* @name LLIOPipe virtual implementations
- */
-
- /**
- * @ brief Turn off (or on) the CURLOPT_PROXY header.
- */
- void useProxy(bool use_proxy);
-
- /**
- * @ brief Set the CURLOPT_PROXY header to the given value.
- */
- void useProxy(const std::string& proxy);
-
- /**
- * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE.
- */
- void allowCookies();
-
- /*virtual*/ bool isValid() ;
-
-public:
- /**
- * @brief Give this pipe a chance to handle a generated error
- */
- virtual EStatus handleError(EStatus status, LLPumpIO* pump);
-
-
-protected:
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- enum EState
- {
- STATE_INITIALIZED,
- STATE_WAITING_FOR_RESPONSE,
- STATE_PROCESSING_RESPONSE,
- STATE_HAVE_RESPONSE,
- };
- EState mState;
- EHTTPMethod mAction;
- bool mFollowRedirects;
- LLURLRequestDetail* mDetail;
- LLIOPipe::ptr_t mCompletionCallback;
- S32 mRequestTransferedBytes;
- S32 mResponseTransferedBytes;
-
- static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
-
-private:
- /**
- * @brief Initialize the object. Called during construction.
- */
- void initialize();
-
- /**
- * @brief Handle action specific url request configuration.
- *
- * @return Returns true if this is configured.
- */
- bool configure();
-
- /**
- * @brief Download callback method.
- */
- static size_t downCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user);
-
- /**
- * @brief Upload callback method.
- */
- static size_t upCallback(
- char* data,
- size_t size,
- size_t nmemb,
- void* user);
-
- /**
- * @brief Declaration of unimplemented method to prevent copy
- * construction.
- */
- LLURLRequest(const LLURLRequest&);
-};
-
-
-/**
- * @class LLContextURLExtractor
- * @brief This class unpacks the url out of a agent usher service so
- * it can be packed into a LLURLRequest object.
- * @see LLIOPipe
- *
- * This class assumes that the context is a map that contains an entry
- * named CONTEXT_DEST_URI_SD_LABEL.
- */
-class LLContextURLExtractor : public LLIOPipe
-{
-public:
- LLContextURLExtractor(LLURLRequest* req) : mRequest(req) {}
- ~LLContextURLExtractor() {}
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
-protected:
- LLURLRequest* mRequest;
-};
-
-
-/**
- * @class LLURLRequestComplete
- * @brief Class which can optionally be used with an LLURLRequest to
- * get notification when the url request is complete.
- */
-class LLURLRequestComplete : public LLIOPipe
-{
-public:
-
- // Called once for each header received, except status lines
- virtual void header(const std::string& header, const std::string& value);
-
- // 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(S32 status, const std::string& reason) { }
-
- virtual void complete(
- const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer);
-
- /**
- * @brief This method is called when we got a valid response.
- *
- * It is up to class implementers to do something useful here.
- */
- virtual void response(
- const LLChannelDescriptors& channels,
- const buffer_ptr_t& buffer);
-
- /**
- * @brief This method is called if there was no response.
- *
- * It is up to class implementers to do something useful here.
- */
- virtual void noResponse();
-
- /**
- * @brief This method will be called by the LLURLRequest object.
- *
- * If this is set to STATUS_OK or STATUS_STOP, then the transfer
- * is asssumed to have worked. This will lead to calling response()
- * on the next call to process(). Otherwise, this object will call
- * noResponse() on the next call to process.
- * @param status The status of the URLRequest.
- */
- void responseStatus(EStatus status);
-
- // constructor & destructor.
- LLURLRequestComplete();
- virtual ~LLURLRequestComplete();
-
-protected:
- /* @name LLIOPipe virtual implementations
- */
- //@{
- /**
- * @brief Process the data in buffer
- */
- virtual EStatus process_impl(
- const LLChannelDescriptors& channels,
- buffer_ptr_t& buffer,
- bool& eos,
- LLSD& context,
- LLPumpIO* pump);
- //@}
-
- // value to note if we actually got the response. This value
- // depends on correct usage from the LLURLRequest instance.
- EStatus mRequestStatus;
-};
-
-#endif // LL_LLURLREQUEST_H
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index e9ce94ab3b..2f4b47286d 100755
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -50,9 +50,7 @@
#include "lldir.h"
#include "llerror.h"
#include "llfasttimer.h"
-#include "llhttpclient.h"
#include "llhttpnodeadapter.h"
-#include "llhttpsender.h"
#include "llmd5.h"
#include "llmessagebuilder.h"
#include "llmessageconfig.h"
@@ -77,6 +75,7 @@
#include "v3math.h"
#include "v4math.h"
#include "lltransfertargetvfile.h"
+#include "llcorehttputil.h"
// Constants
//const char* MESSAGE_LOG_FILENAME = "message.log";
@@ -97,45 +96,6 @@ public:
apr_pollfd_t mPollFD;
};
-namespace
-{
- class LLFnPtrResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLFnPtrResponder);
- public:
- LLFnPtrResponder(void (*callback)(void **,S32), void **callbackData, const std::string& name) :
- mCallback(callback),
- mCallbackData(callbackData),
- mMessageName(name)
- {
- }
-
- protected:
- virtual void httpFailure()
- {
- // don't spam when agent communication disconnected already
- if (HTTP_GONE != getStatus())
- {
- 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 httpSuccess()
- {
- if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR);
- }
-
- private:
-
- void (*mCallback)(void **,S32);
- void **mCallbackData;
- std::string mMessageName;
- };
-}
-
class LLMessageHandlerBridge : public LLHTTPNode
{
virtual bool validate(const std::string& name, LLSD& context) const
@@ -1129,29 +1089,6 @@ S32 LLMessageSystem::flushReliable(const LLHost &host)
return send_bytes;
}
-LLHTTPClient::ResponderPtr LLMessageSystem::createResponder(const std::string& name)
-{
- if(mSendReliable)
- {
- return new LLFnPtrResponder(
- mReliablePacketParams.mCallback,
- mReliablePacketParams.mCallbackData,
- name);
- }
- else
- {
- // These messages aren't really unreliable, they just weren't
- // explicitly sent as reliable, so they don't have a callback
-// LL_WARNS("Messaging") << "LLMessageSystem::sendMessage: Sending unreliable "
-// << mMessageBuilder->getMessageName() << " message via HTTP"
-// << LL_ENDL;
- return new LLFnPtrResponder(
- NULL,
- NULL,
- name);
- }
-}
-
// This can be called from signal handlers,
// so should should not use LL_INFOS().
S32 LLMessageSystem::sendMessage(const LLHost &host)
@@ -1216,13 +1153,17 @@ S32 LLMessageSystem::sendMessage(const LLHost &host)
if(mMessageBuilder == mLLSDMessageBuilder)
{
LLSD message = mLLSDMessageBuilder->getMessage();
-
- const LLHTTPSender& sender = LLHTTPSender::getSender(host);
- sender.send(
- host,
- mLLSDMessageBuilder->getMessageName(),
- message,
- createResponder(mLLSDMessageBuilder->getMessageName()));
+
+ UntrustedCallback_t cb = NULL;
+ if ((mSendReliable) && (mReliablePacketParams.mCallback))
+ {
+ cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1);
+ }
+
+ LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro",
+ boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this,
+ host.getUntrustedSimulatorCap(),
+ mLLSDMessageBuilder->getMessageName(), message, cb));
mSendReliable = FALSE;
mReliablePacketParams.clear();
@@ -1410,9 +1351,16 @@ S32 LLMessageSystem::sendMessage(
return 0;
}
- const LLHTTPSender& sender = LLHTTPSender::getSender(host);
- sender.send(host, name, message, createResponder(name));
- return 1;
+ UntrustedCallback_t cb = NULL;
+ if ((mSendReliable) && (mReliablePacketParams.mCallback))
+ {
+ cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1);
+ }
+
+ LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro",
+ boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this,
+ host.getUntrustedSimulatorCap(), name, message, cb));
+ return 1;
}
void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host )
@@ -1725,7 +1673,7 @@ LLHost LLMessageSystem::findHost(const U32 circuit_code)
}
else
{
- return LLHost::invalid;
+ return LLHost();
}
}
@@ -4055,6 +4003,36 @@ const LLHost& LLMessageSystem::getSender() const
return mLastSender;
}
+void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+
+ if (url.empty())
+ {
+ LL_WARNS() << "sendUntrustedSimulatorMessageCoro called with empty capability!" << LL_ENDL;
+ return;
+ }
+
+ LL_INFOS() << "sendUntrustedSimulatorMessageCoro: message " << message << " to cap " << url << LL_ENDL;
+ LLSD postData;
+ postData["message"] = message;
+ postData["body"] = body;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if ((callback) && (!callback.empty()))
+ callback((status) ? LL_ERR_NOERR : LL_ERR_TCP_TIMEOUT);
+}
+
+
LLHTTPRegistration<LLHTTPNodeAdapter<LLTrustedMessageService> >
gHTTPRegistrationTrustedMessageWildcard("/trusted-message/<message-name>");
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index 348b09b992..133db620e6 100755
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -50,7 +50,6 @@
#include "lltimer.h"
#include "llpacketring.h"
#include "llhost.h"
-#include "llcurl.h"
#include "llhttpnode.h"
//#include "llpacketack.h"
#include "llsingleton.h"
@@ -60,6 +59,7 @@
#include "llmessagesenderinterface.h"
#include "llstoredmessage.h"
+#include "boost/function.hpp"
const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
@@ -489,7 +489,6 @@ public:
void (*callback)(void **,S32),
void ** callback_data);
- LLCurl::ResponderPtr createResponder(const std::string& name);
S32 sendMessage(const LLHost &host);
S32 sendMessage(const U32 circuit);
private:
@@ -740,6 +739,9 @@ public:
void receivedMessageFromTrustedSender();
private:
+ typedef boost::function<void(S32)> UntrustedCallback_t;
+ void sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback);
+
bool mLastMessageFromTrustedMessageService;
diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp
deleted file mode 100755
index e9ce116bb3..0000000000
--- a/indra/llmessage/tests/llhttpclientadapter_test.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
-/**
- * @file llhttpclientadapter_test.cpp
- * @brief Tests for LLHTTPClientAdapter
- *
- * $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 "llhttpclientadapter.h"
-
-#include "../test/lltut.h"
-#include "llhttpclient.h"
-#include "llcurl_stub.cpp"
-
-float const HTTP_REQUEST_EXPIRY_SECS = 1.0F;
-
-std::vector<std::string> get_urls;
-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);
-}
-
-std::vector<std::string> put_urls;
-std::vector<LLSD> put_body;
-std::vector<LLSD> put_headers;
-std::vector<LLCurl::ResponderPtr> put_responders;
-
-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
-{
- struct LLHTTPClientAdapterData
- {
- LLHTTPClientAdapterData()
- {
- get_urls.clear();
- get_responders.clear();
- put_urls.clear();
- put_responders.clear();
- put_body.clear();
- put_headers.clear();
- delete_urls.clear();
- delete_responders.clear();
- }
- };
-
- typedef test_group<LLHTTPClientAdapterData> factory;
- typedef factory::object object;
-}
-
-namespace
-{
- tut::factory tf("LLHTTPClientAdapterData");
-}
-
-namespace tut
-{
- // Ensure we can create the object
- template<> template<>
- void object::test<1>()
- {
- LLHTTPClientAdapter adapter;
- }
-
- // Does the get pass the appropriate arguments to the LLHTTPClient
- template<> template<>
- void object::test<2>()
- {
- LLHTTPClientAdapter adapter;
-
- LLCurl::ResponderPtr responder = new LLCurl::Responder();
-
- adapter.get("Made up URL", responder);
- ensure_equals(get_urls.size(), 1);
- ensure_equals(get_urls[0], "Made up URL");
- }
-
- // Ensure the responder matches the one passed to get
- template<> template<>
- void object::test<3>()
- {
- LLHTTPClientAdapter adapter;
- LLCurl::ResponderPtr responder = new LLCurl::Responder();
-
- adapter.get("Made up URL", responder);
-
- ensure_equals(get_responders.size(), 1);
- ensure_equals(get_responders[0].get(), responder.get());
- }
-
- // Ensure the correct url is used in the put
- template<> template<>
- void object::test<4>()
- {
- LLHTTPClientAdapter adapter;
-
- LLCurl::ResponderPtr responder = new LLCurl::Responder();
-
- LLSD body;
- body["TestBody"] = "Foobar";
-
- adapter.put("Made up URL", body, responder);
- ensure_equals(put_urls.size(), 1);
- ensure_equals(put_urls[0], "Made up URL");
- }
-
- // Ensure the correct responder is used by put
- template<> template<>
- void object::test<5>()
- {
- LLHTTPClientAdapter adapter;
-
- LLCurl::ResponderPtr responder = new LLCurl::Responder();
-
- LLSD body;
- body["TestBody"] = "Foobar";
-
- adapter.put("Made up URL", body, responder);
-
- ensure_equals(put_responders.size(), 1);
- ensure_equals(put_responders[0].get(), responder.get());
- }
-
- // Ensure the message body is passed through the put properly
- template<> template<>
- void object::test<6>()
- {
- LLHTTPClientAdapter adapter;
-
- LLCurl::ResponderPtr responder = new LLCurl::Responder();
-
- LLSD body;
- body["TestBody"] = "Foobar";
-
- adapter.put("Made up URL", body, responder);
-
- 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/llsdmessage_test.cpp b/indra/llmessage/tests/llsdmessage_test.cpp
deleted file mode 100755
index 44b024a83f..0000000000
--- a/indra/llmessage/tests/llsdmessage_test.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * @file llsdmessage_test.cpp
- * @author Nat Goodspeed
- * @date 2008-12-22
- * @brief Test of llsdmessage.h
- *
- * $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$
- */
-
-#if LL_WINDOWS
-#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
-#endif
-
-// Precompiled header
-#include "linden_common.h"
-// associated header
-#include "llsdmessage.h"
-// STL headers
-#include <iostream>
-// std headers
-#include <stdexcept>
-#include <typeinfo>
-// external library headers
-// other Linden headers
-#include "../test/lltut.h"
-#include "../test/catch_and_store_what_in.h"
-#include "llsdserialize.h"
-#include "llevents.h"
-#include "stringize.h"
-#include "llhost.h"
-#include "tests/networkio.h"
-#include "tests/commtest.h"
-
-/*****************************************************************************
-* TUT
-*****************************************************************************/
-namespace tut
-{
- struct llsdmessage_data: public commtest_data
- {
- LLEventPump& httpPump;
-
- llsdmessage_data():
- httpPump(pumps.obtain("LLHTTPClient"))
- {
- LLCurl::initClass();
- LLSDMessage::link();
- }
- };
- typedef test_group<llsdmessage_data> llsdmessage_group;
- typedef llsdmessage_group::object llsdmessage_object;
- llsdmessage_group llsdmgr("llsdmessage");
-
- template<> template<>
- void llsdmessage_object::test<1>()
- {
- std::string threw;
- // This should fail...
- try
- {
- LLSDMessage localListener;
- }
- CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupPumpName)
- ensure("second LLSDMessage should throw", ! threw.empty());
- }
-
- template<> template<>
- void llsdmessage_object::test<2>()
- {
- LLSD request, body;
- body["data"] = "yes";
- request["payload"] = body;
- request["reply"] = replyPump.getName();
- request["error"] = errorPump.getName();
- bool threw = false;
- try
- {
- httpPump.post(request);
- }
- catch (const LLSDMessage::ArgError&)
- {
- threw = true;
- }
- ensure("missing URL", threw);
- }
-
- template<> template<>
- void llsdmessage_object::test<3>()
- {
- LLSD request, body;
- body["data"] = "yes";
- request["url"] = server + "got-message";
- request["payload"] = body;
- request["reply"] = replyPump.getName();
- request["error"] = errorPump.getName();
- httpPump.post(request);
- ensure("got response", netio.pump());
- ensure("success response", success);
- ensure_equals(result["reply"].asString(), "success");
-
- body["status"] = 499;
- body["reason"] = "custom error message";
- request["url"] = server + "fail";
- request["payload"] = body;
- httpPump.post(request);
- ensure("got response", netio.pump());
- ensure("failure response", ! success);
- ensure_equals(result["status"].asInteger(), body["status"].asInteger());
- ensure_equals(result["reason"].asString(), body["reason"].asString());
- }
-} // namespace tut
diff --git a/indra/llmessage/tests/lltesthttpclientadapter.cpp b/indra/llmessage/tests/lltesthttpclientadapter.cpp
deleted file mode 100755
index 4539e4a540..0000000000
--- a/indra/llmessage/tests/lltesthttpclientadapter.cpp
+++ /dev/null
@@ -1,61 +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 "lltesthttpclientadapter.h"
-
-LLTestHTTPClientAdapter::LLTestHTTPClientAdapter()
-{
-}
-
-LLTestHTTPClientAdapter::~LLTestHTTPClientAdapter()
-{
-}
-
-void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder)
-{
- mGetUrl.push_back(url);
- mGetResponder.push_back(responder);
-}
-
-void LLTestHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)
-{
- mPutUrl.push_back(url);
- mPutBody.push_back(body);
- mPutResponder.push_back(responder);
-}
-
-U32 LLTestHTTPClientAdapter::putCalls() const
-{
- return mPutUrl.size();
-}
-
-void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)
-{
- mGetUrl.push_back(url);
- mGetHeaders.push_back(headers);
- mGetResponder.push_back(responder);
-}
-
-
diff --git a/indra/llmessage/tests/lltesthttpclientadapter.h b/indra/llmessage/tests/lltesthttpclientadapter.h
deleted file mode 100755
index c29cbb3a2a..0000000000
--- a/indra/llmessage/tests/lltesthttpclientadapter.h
+++ /dev/null
@@ -1,57 +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$
- */
-
-/* Macro Definitions */
-#ifndef LL_LLTESTHTTPCLIENTADAPTER_H
-#define LL_LLTESTHTTPCLIENTADAPTER_H
-
-
-#include "linden_common.h"
-#include "llhttpclientinterface.h"
-
-class LLTestHTTPClientAdapter : public LLHTTPClientInterface
-{
-public:
- LLTestHTTPClientAdapter();
- virtual ~LLTestHTTPClientAdapter();
- 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);
- U32 putCalls() const;
-
- std::vector<LLSD> mPutBody;
- std::vector<LLSD> mGetHeaders;
- std::vector<std::string> mPutUrl;
- std::vector<std::string> mGetUrl;
- std::vector<LLCurl::ResponderPtr> mPutResponder;
- std::vector<LLCurl::ResponderPtr> mGetResponder;
-};
-
-
-
-#endif //LL_LLSIMULATORPRESENCESENDER_H
-
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 75ce624a58..dd2e806dda 100755
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -6,6 +6,7 @@ include(00-Common)
include(LLCommon)
include(LLMath)
include(LLMessage)
+include(LLCoreHttp)
include(LLXML)
include(LLPhysicsExtensions)
include(LLCharacter)
@@ -75,9 +76,12 @@ target_link_libraries(llprimitive
${LLCOMMON_LIBRARIES}
${LLMATH_LIBRARIES}
${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLXML_LIBRARIES}
${LLPHYSICSEXTENSIONS_LIBRARIES}
${LLCHARACTER_LIBRARIES}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
)
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 52738aeb6f..7fb1db15fb 100755
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -8,13 +8,16 @@ include(LLImage)
include(LLInventory)
include(LLMath)
include(LLMessage)
+include(LLCoreHttp)
include(LLRender)
include(LLWindow)
+include(LLCoreHttp)
include(LLVFS)
include(LLXML)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLIMAGE_INCLUDE_DIRS}
${LLINVENTORY_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
@@ -268,16 +271,18 @@ add_library (llui ${llui_SOURCE_FILES})
# Libraries on which this library depends, needed for Linux builds
# Sort by high-level to low-level
target_link_libraries(llui
- ${LLMESSAGE_LIBRARIES}
${LLRENDER_LIBRARIES}
${LLWINDOW_LIBRARIES}
${LLIMAGE_LIBRARIES}
${LLINVENTORY_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLVFS_LIBRARIES} # ugh, just for LLDir
${LLXUIXML_LIBRARIES}
${LLXML_LIBRARIES}
${LLMATH_LIBRARIES}
${HUNSPELL_LIBRARY}
+ ${LLMESSAGE_LIBRARIES}
${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender
)
@@ -289,6 +294,8 @@ if(LL_TESTS)
)
LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}")
# INTEGRATION TESTS
- set(test_libs llui llmessage llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES})
- LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+ set(test_libs llui llmessage llcorehttp llcommon ${LLCOMMON_LIBRARIES} ${BOOST_COROUTINE_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${WINDOWS_LIBRARIES})
+ if(NOT LINUX)
+ LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}")
+ endif(NOT LINUX)
endif(LL_TESTS)
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 6db0d88998..72ff89f33c 100755
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -957,7 +957,7 @@ std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const
// LLUrlEntryParcel statics.
LLUUID LLUrlEntryParcel::sAgentID(LLUUID::null);
LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null);
-LLHost LLUrlEntryParcel::sRegionHost(LLHost::invalid);
+LLHost LLUrlEntryParcel::sRegionHost;
bool LLUrlEntryParcel::sDisconnected(false);
std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
@@ -1006,7 +1006,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC
void LLUrlEntryParcel::sendParcelInfoRequest(const LLUUID& parcel_id)
{
- if (sRegionHost == LLHost::invalid || sDisconnected) return;
+ if (sRegionHost.isInvalid() || sDisconnected) return;
LLMessageSystem *msg = gMessageSystem;
msg->newMessage("ParcelInfoRequest");
@@ -1430,7 +1430,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const
return LLTrans::getString("ExperienceNameNull");
}
- const LLSD& experience_details = LLExperienceCache::get(experience_id);
+ const LLSD& experience_details = LLExperienceCache::instance().get(experience_id);
if(!experience_details.isUndefined())
{
std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
@@ -1438,7 +1438,7 @@ std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const
}
addObserver(experience_id_string, url, cb);
- LLExperienceCache::get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
+ LLExperienceCache::instance().get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
return LLTrans::getString("LoadingData");
}
diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp
index 5d3f9ac327..f01178c374 100755
--- a/indra/llui/tests/llurlentry_stub.cpp
+++ b/indra/llui/tests/llurlentry_stub.cpp
@@ -165,8 +165,6 @@ LLFontGL* LLFontGL::getFontDefault()
char const* const _PREHASH_AgentData = (char *)"AgentData";
char const* const _PREHASH_AgentID = (char *)"AgentID";
-LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS);
-
LLMessageSystem* gMessageSystem = NULL;
//
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 15f2354552..ba1cc436f9 100755
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -37,17 +37,17 @@
#include <boost/regex.hpp>
-namespace LLExperienceCache
-{
- const LLSD& get( const LLUUID& key)
- {
- static LLSD boo;
- return boo;
- }
-
- void get( const LLUUID& key, callback_slot_t slot ){}
-
-}
+// namespace LLExperienceCache
+// {
+// const LLSD& get( const LLUUID& key)
+// {
+// static LLSD boo;
+// return boo;
+// }
+//
+// void get( const LLUUID& key, callback_slot_t slot ){}
+//
+// }
typedef std::map<std::string, LLControlGroup*> settings_map_t;
settings_map_t LLUI::sSettingGroups;
diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt
index c59645bd70..ab20388261 100755
--- a/indra/mac_crash_logger/CMakeLists.txt
+++ b/indra/mac_crash_logger/CMakeLists.txt
@@ -4,6 +4,7 @@ project(mac_crash_logger)
include(00-Common)
include(LLCommon)
+include(LLCoreHttp)
include(LLCrashLogger)
include(LLMath)
include(LLMessage)
@@ -11,8 +12,10 @@ include(LLVFS)
include(LLXML)
include(Linking)
include(LLSharedLibs)
+include(Boost)
include_directories(
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLCRASHLOGGER_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
@@ -71,7 +74,10 @@ target_link_libraries(mac-crash-logger
${LLMESSAGE_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLCOMMON_LIBRARIES}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_COROUTINE_LIBRARY}
)
add_custom_command(
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 16877c345e..07c0cb795e 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -123,8 +123,6 @@ set(viewer_SOURCE_FILES
llappearancemgr.cpp
llappviewer.cpp
llappviewerlistener.cpp
- llassetuploadqueue.cpp
- llassetuploadresponders.cpp
llattachmentsmgr.cpp
llaudiosourcevo.cpp
llautoreplace.cpp
@@ -141,8 +139,6 @@ set(viewer_SOURCE_FILES
llbrowsernotification.cpp
llbuycurrencyhtml.cpp
llcallingcard.cpp
- llcapabilitylistener.cpp
- llcaphttpsender.cpp
llchannelmanager.cpp
llchatbar.cpp
llchathistory.cpp
@@ -151,7 +147,6 @@ set(viewer_SOURCE_FILES
llchiclet.cpp
llchicletbar.cpp
llclassifiedinfo.cpp
- llclassifiedstatsresponder.cpp
llcofwearables.cpp
llcolorswatch.cpp
llcommanddispatcherlistener.cpp
@@ -196,7 +191,6 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
- llexperienceassociationresponder.cpp
llexperiencelog.cpp
llexternaleditor.cpp
llface.cpp
@@ -233,7 +227,6 @@ set(viewer_SOURCE_FILES
llfloaterconversationpreview.cpp
llfloaterdeleteenvpreset.cpp
llfloaterdestinations.cpp
- llfloaterdisplayname.cpp
llfloatereditdaycycle.cpp
llfloatereditsky.cpp
llfloatereditwater.cpp
@@ -276,7 +269,6 @@ set(viewer_SOURCE_FILES
llfloaternotificationsconsole.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
- llfloateroutbox.cpp
llfloaterpathfindingcharacters.cpp
llfloaterpathfindingconsole.cpp
llfloaterpathfindinglinksets.cpp
@@ -333,7 +325,6 @@ set(viewer_SOURCE_FILES
llgroupmgr.cpp
llhasheduniqueid.cpp
llhints.cpp
- llhomelocationresponder.cpp
llhttpretrypolicy.cpp
llhudeffect.cpp
llhudeffectbeam.cpp
@@ -568,7 +559,6 @@ set(viewer_SOURCE_FILES
lltextureinfo.cpp
lltextureinfodetails.cpp
lltexturestats.cpp
- lltexturestatsuploader.cpp
lltextureview.cpp
lltoast.cpp
lltoastalertpanel.cpp
@@ -604,7 +594,6 @@ set(viewer_SOURCE_FILES
lltwitterconnect.cpp
lluilistener.cpp
lluploaddialog.cpp
- lluploadfloaterobservers.cpp
llurl.cpp
llurldispatcher.cpp
llurldispatcherlistener.cpp
@@ -617,6 +606,7 @@ set(viewer_SOURCE_FILES
llviewerassetstats.cpp
llviewerassetstorage.cpp
llviewerassettype.cpp
+ llviewerassetupload.cpp
llviewerattachmenu.cpp
llvieweraudio.cpp
llviewercamera.cpp
@@ -624,7 +614,6 @@ set(viewer_SOURCE_FILES
llviewercontrol.cpp
llviewercontrollistener.cpp
llviewerdisplay.cpp
- llviewerdisplayname.cpp
llviewerfloaterreg.cpp
llviewerfoldertype.cpp
llviewergenericmessage.cpp
@@ -739,8 +728,6 @@ set(viewer_HEADER_FILES
llappearancemgr.h
llappviewer.h
llappviewerlistener.h
- llassetuploadqueue.h
- llassetuploadresponders.h
llattachmentsmgr.h
llaudiosourcevo.h
llautoreplace.h
@@ -756,9 +743,7 @@ set(viewer_HEADER_FILES
llbreadcrumbview.h
llbuycurrencyhtml.h
llcallingcard.h
- llcapabilitylistener.h
llcapabilityprovider.h
- llcaphttpsender.h
llchannelmanager.h
llchatbar.h
llchathistory.h
@@ -767,7 +752,6 @@ set(viewer_HEADER_FILES
llchiclet.h
llchicletbar.h
llclassifiedinfo.h
- llclassifiedstatsresponder.h
llcofwearables.h
llcolorswatch.h
llcommanddispatcherlistener.h
@@ -812,7 +796,6 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
- llexperienceassociationresponder.h
llexperiencelog.h
llexternaleditor.h
llface.h
@@ -849,7 +832,6 @@ set(viewer_HEADER_FILES
llfloaterconversationpreview.h
llfloaterdeleteenvpreset.h
llfloaterdestinations.h
- llfloaterdisplayname.h
llfloatereditdaycycle.h
llfloatereditsky.h
llfloatereditwater.h
@@ -895,7 +877,6 @@ set(viewer_HEADER_FILES
llfloaternotificationsconsole.h
llfloaterobjectweights.h
llfloateropenobject.h
- llfloateroutbox.h
llfloaterpathfindingcharacters.h
llfloaterpathfindingconsole.h
llfloaterpathfindinglinksets.h
@@ -952,7 +933,6 @@ set(viewer_HEADER_FILES
llhasheduniqueid.h
llhints.h
llhttpretrypolicy.h
- llhomelocationresponder.h
llhudeffect.h
llhudeffectbeam.h
llhudeffectlookat.h
@@ -1175,7 +1155,6 @@ set(viewer_HEADER_FILES
lltextureinfo.h
lltextureinfodetails.h
lltexturestats.h
- lltexturestatsuploader.h
lltextureview.h
lltoast.h
lltoastalertpanel.h
@@ -1225,6 +1204,7 @@ set(viewer_HEADER_FILES
llviewerassetstats.h
llviewerassetstorage.h
llviewerassettype.h
+ llviewerassetupload.h
llviewerattachmenu.h
llvieweraudio.h
llviewercamera.h
@@ -1232,7 +1212,6 @@ set(viewer_HEADER_FILES
llviewercontrol.h
llviewercontrollistener.h
llviewerdisplay.h
- llviewerdisplayname.h
llviewerfloaterreg.h
llviewerfoldertype.h
llviewergenericmessage.h
@@ -1983,8 +1962,8 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${viewer_LIBRARIES}
${BOOST_PROGRAM_OPTIONS_LIBRARY}
${BOOST_REGEX_LIBRARY}
- ${BOOST_CONTEXT_LIBRARY}
${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
${DBUSGLIB_LIBRARIES}
${OPENGL_LIBRARIES}
${FMODWRAPPER_LIBRARY} # must come after LLAudio
@@ -2238,10 +2217,9 @@ if (LL_TESTS)
SET(viewer_TEST_SOURCE_FILES
llagentaccess.cpp
lldateutil.cpp
- llmediadataclient.cpp
+# llmediadataclient.cpp
lllogininstance.cpp
- llremoteparcelrequest.cpp
- lltranslate.cpp
+# llremoteparcelrequest.cpp
llviewerhelputil.cpp
llversioninfo.cpp
llworldmap.cpp
@@ -2263,15 +2241,9 @@ if (LL_TESTS)
)
set_source_files_properties(
- lltranslate.cpp
- PROPERTIES
- LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}"
- )
-
- set_source_files_properties(
llmediadataclient.cpp
PROPERTIES
- LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}"
+ LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}"
)
set_source_files_properties(
@@ -2327,7 +2299,6 @@ if (LL_TESTS)
LL_ADD_PROJECT_UNIT_TESTS(${VIEWER_BINARY_NAME} "${viewer_TEST_SOURCE_FILES}")
#set(TEST_DEBUG on)
- set(test_sources llcapabilitylistener.cpp)
##################################################
# DISABLING PRECOMPILED HEADERS USAGE FOR TESTS
##################################################
@@ -2343,26 +2314,29 @@ if (LL_TESTS)
${GOOGLEMOCK_LIBRARIES}
)
- LL_ADD_INTEGRATION_TEST(llcapabilitylistener
- "${test_sources}"
- "${test_libs}"
- ${PYTHON_EXECUTABLE}
- "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py"
- )
+ if (LINUX)
+ # llcommon uses `clock_gettime' which is provided by librt on linux.
+ set(LIBRT_LIBRARY
+ rt
+ )
+ endif (LINUX)
set(test_libs
- ${LLMESSAGE_LIBRARIES}
- ${LLCOREHTTP_LIBRARIES}
${WINDOWS_LIBRARIES}
${LLVFS_LIBRARIES}
${LLMATH_LIBRARIES}
${LLCOMMON_LIBRARIES}
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
+ ${LIBRT_LIBRARY}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
)
- LL_ADD_INTEGRATION_TEST(llsechandler_basic
+ LL_ADD_INTEGRATION_TEST(llsechandler_basic
llsechandler_basic.cpp
"${test_libs}"
)
@@ -2393,13 +2367,12 @@ if (LL_TESTS)
"${test_libs}"
)
- LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${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)
#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
- #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
include(LLAddBuildTest)
SET(viewer_TEST_SOURCE_FILES
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 98d0ba53f6..81da856d7e 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2403,6 +2403,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>DebugSlshareLogTag</key>
+ <map>
+ <key>Comment</key>
+ <string>Request slshare-service debug logging</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string/>
+ </map>
<key>DebugStatModeFPS</key>
<map>
<key>Comment</key>
@@ -14417,6 +14428,24 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>PoolSizeAIS</key>
+ <map>
+ <key>Comment</key>
+ <string>Coroutine Pool size for AIS</string>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>25</integer>
+ </map>
+ <key>PoolSizeUpload</key>
+ <map>
+ <key>Comment</key>
+ <string>Coroutine Pool size for Upload</string>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>1</real>
+ </map>
<!-- Settings below are for back compatibility only.
They are not used in current viewer anymore. But they can't be removed to avoid
diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp
index a42286a9e4..92a5413adb 100755
--- a/indra/newview/llaccountingcostmanager.cpp
+++ b/indra/newview/llaccountingcostmanager.cpp
@@ -27,90 +27,145 @@
#include "llviewerprecompiledheaders.h"
#include "llaccountingcostmanager.h"
#include "llagent.h"
-#include "llcurl.h"
-#include "llhttpclient.h"
+#include "httpcommon.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
+#include <algorithm>
+#include <iterator>
+
//===============================================================================
LLAccountingCostManager::LLAccountingCostManager()
{
+
}
-//===============================================================================
-class LLAccountingCostResponder : public LLCurl::Responder
+
+// Coroutine for sending and processing avatar name cache requests.
+// Do not call directly. See documentation in lleventcoro.h and llcoro.h for
+// further explanation.
+void LLAccountingCostManager::accountingCostCoro(std::string url,
+ eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle)
{
- LOG_CLASS(LLAccountingCostResponder);
-public:
- LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle )
- : mObjectIDs( objectIDs ),
- mObserverHandle( observer_handle )
- {
- LLAccountingCostObserver* observer = mObserverHandle.get();
- if (observer)
- {
- mTransactionID = observer->getTransactionID();
- }
- }
+ LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName()
+ << " with url '" << url << LL_ENDL;
- void clearPendingRequests ( void )
- {
- for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter )
- {
- LLAccountingCostManager::getInstance()->removePendingObject( iter->asUUID() );
- }
- }
-
-protected:
- void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- clearPendingRequests();
-
- LLAccountingCostObserver* observer = mObserverHandle.get();
- if (observer && observer->getTransactionID() == mTransactionID)
- {
- observer->setErrorStatus(getStatus(), getReason());
- }
- }
-
- void httpSuccess()
- {
- const LLSD& content = getContent();
- //Check for error
- if ( !content.isMap() || content.has("error") )
- {
- failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content);
- return;
- }
- else if (content.has("selected"))
- {
- F32 physicsCost = 0.0f;
- F32 networkCost = 0.0f;
- F32 simulationCost = 0.0f;
-
- physicsCost = content["selected"]["physics"].asReal();
- networkCost = content["selected"]["streaming"].asReal();
- simulationCost = content["selected"]["simulation"].asReal();
-
- SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost );
-
- LLAccountingCostObserver* observer = mObserverHandle.get();
- if (observer && observer->getTransactionID() == mTransactionID)
- {
- observer->onWeightsUpdate(selectionCost);
- }
- }
-
- clearPendingRequests();
- }
-
-private:
- //List of posted objects
- LLSD mObjectIDs;
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AccountingCost", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ try
+ {
+ uuid_set_t diffSet;
+
+ std::set_difference(mObjectList.begin(), mObjectList.end(),
+ mPendingObjectQuota.begin(), mPendingObjectQuota.end(),
+ std::inserter(diffSet, diffSet.begin()));
+
+ if (diffSet.empty())
+ return;
+
+ mObjectList.clear();
+
+ std::string keystr;
+ if (selectionType == Roots)
+ {
+ keystr = "selected_roots";
+ }
+ else if (selectionType == Prims)
+ {
+ keystr = "selected_prims";
+ }
+ else
+ {
+ LL_INFOS() << "Invalid selection type " << LL_ENDL;
+ return;
+ }
+
+ LLSD objectList(LLSD::emptyMap());
+
+ for (uuid_set_t::iterator it = diffSet.begin(); it != diffSet.end(); ++it)
+ {
+ objectList.append(*it);
+ }
+
+ mPendingObjectQuota.insert(diffSet.begin(), diffSet.end());
+
+ LLSD dataToPost = LLSD::emptyMap();
+ dataToPost[keystr.c_str()] = objectList;
- // Current request ID
- LLUUID mTransactionID;
+ LLAccountingCostObserver* observer = observerHandle.get();
+ LLUUID transactionId = observer->getTransactionID();
+ observer = NULL;
+
+
+
+ LLSD results = httpAdapter->postAndSuspend(httpRequest, url, dataToPost);
+
+ LLSD httpResults = results["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ // do/while(false) allows error conditions to break out of following
+ // block while normal flow goes forward once.
+ do
+ {
+ observer = observerHandle.get();
+
+ if (!status || results.has("error"))
+ {
+ LL_WARNS() << "Error on fetched data" << LL_ENDL;
+ if (!status)
+ observer->setErrorStatus(status.getType(), status.toString());
+ else
+ observer->setErrorStatus(499, "Error on fetched data");
+
+ break;
+ }
+
+ if (!httpResults["success"].asBoolean())
+ {
+ LL_WARNS() << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL;
+ if (observer)
+ {
+ observer->setErrorStatus(httpResults["status"].asInteger(), httpResults["message"].asStringRef());
+ }
+ break;
+ }
+
+
+ if (results.has("selected"))
+ {
+ LLSD selected = results["selected"];
+
+ F32 physicsCost = 0.0f;
+ F32 networkCost = 0.0f;
+ F32 simulationCost = 0.0f;
+
+ physicsCost = selected["physics"].asReal();
+ networkCost = selected["streaming"].asReal();
+ simulationCost = selected["simulation"].asReal();
+
+ SelectionCost selectionCost( physicsCost, networkCost, simulationCost);
+
+ observer->onWeightsUpdate(selectionCost);
+ }
+
+ } while (false);
+
+ }
+ catch (std::exception e)
+ {
+ LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+ }
+
+ mPendingObjectQuota.clear();
+}
- // Cost update observer handle
- LLHandle<LLAccountingCostObserver> mObserverHandle;
-};
//===============================================================================
void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
const std::string& url,
@@ -119,50 +174,11 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
// Invoking system must have already determined capability availability
if ( !url.empty() )
{
- LLSD objectList;
- U32 objectIndex = 0;
-
- IDIt IDIter = mObjectList.begin();
- IDIt IDIterEnd = mObjectList.end();
-
- for ( ; IDIter != IDIterEnd; ++IDIter )
- {
- // Check to see if a request for this object has already been made.
- if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() )
- {
- mPendingObjectQuota.insert( *IDIter );
- objectList[objectIndex++] = *IDIter;
- }
- }
-
- mObjectList.clear();
-
- //Post results
- if ( objectList.size() > 0 )
- {
- std::string keystr;
- if ( selectionType == Roots )
- {
- keystr="selected_roots";
- }
- else
- if ( selectionType == Prims )
- {
- keystr="selected_prims";
- }
- else
- {
- LL_INFOS()<<"Invalid selection type "<<LL_ENDL;
- mObjectList.clear();
- mPendingObjectQuota.clear();
- return;
- }
-
- LLSD dataToPost = LLSD::emptyMap();
- dataToPost[keystr.c_str()] = objectList;
-
- LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList, observer_handle ));
- }
+ std::string coroname =
+ LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro",
+ boost::bind(&LLAccountingCostManager::accountingCostCoro, this, url, selectionType, observer_handle));
+ LL_DEBUGS() << coroname << " with url '" << url << LL_ENDL;
+
}
else
{
diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h
index 3ade34c81d..f251ceffd4 100755
--- a/indra/newview/llaccountingcostmanager.h
+++ b/indra/newview/llaccountingcostmanager.h
@@ -30,6 +30,13 @@
#include "llhandle.h"
#include "llaccountingcost.h"
+#include "httpcommon.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
+
//===============================================================================
// An interface class for panels which display the parcel accounting information.
class LLAccountingCostObserver
@@ -64,11 +71,13 @@ public:
private:
//Set of objects that will be used to generate a cost
- std::set<LLUUID> mObjectList;
+ uuid_set_t mObjectList;
//During fetchCosts we move object into a the pending set to signify that
//a fetch has been instigated.
- std::set<LLUUID> mPendingObjectQuota;
- typedef std::set<LLUUID>::iterator IDIt;
+ uuid_set_t mPendingObjectQuota;
+
+ void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle);
+
};
//===============================================================================
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 092d868bb9..3316f1e654 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -38,7 +38,6 @@
#include "llappearancemgr.h"
#include "llanimationstates.h"
#include "llcallingcard.h"
-#include "llcapabilitylistener.h"
#include "llchannelmanager.h"
#include "llchicletbar.h"
#include "llconsole.h"
@@ -52,7 +51,6 @@
#include "llfloatertools.h"
#include "llgroupactions.h"
#include "llgroupmgr.h"
-#include "llhomelocationresponder.h"
#include "llhudmanager.h"
#include "lljoystickbutton.h"
#include "llmorphview.h"
@@ -63,7 +61,6 @@
#include "llpaneltopinfobar.h"
#include "llparcel.h"
#include "llrendersphere.h"
-#include "llsdmessage.h"
#include "llsdutil.h"
#include "llsky.h"
#include "llslurl.h"
@@ -95,6 +92,7 @@
#include "lscript_byteformat.h"
#include "stringize.h"
#include "boost/foreach.hpp"
+#include "llcorehttputil.h"
using namespace LLAvatarAppearanceDefines;
@@ -361,7 +359,8 @@ LLAgent::LLAgent() :
mMaturityPreferenceNumRetries(0U),
mLastKnownRequestMaturity(SIM_ACCESS_MIN),
mLastKnownResponseMaturity(SIM_ACCESS_MIN),
- mTeleportState( TELEPORT_NONE ),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mTeleportState(TELEPORT_NONE),
mRegionp(NULL),
mAgentOriginGlobal(),
@@ -461,6 +460,10 @@ void LLAgent::init()
mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this));
}
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT);
+
mInitialized = TRUE;
}
@@ -927,7 +930,7 @@ LLHost LLAgent::getRegionHost() const
}
else
{
- return LLHost::invalid;
+ return LLHost();
}
}
@@ -950,6 +953,15 @@ BOOL LLAgent::inPrelude()
}
+std::string LLAgent::getRegionCapability(const std::string &name)
+{
+ if (!mRegionp)
+ return std::string();
+
+ return mRegionp->getCapability(name);
+}
+
+
//-----------------------------------------------------------------------------
// canManageEstate()
//-----------------------------------------------------------------------------
@@ -2326,27 +2338,9 @@ void LLAgent::setStartPosition( U32 location_id )
body["HomeLocation"] = homeLocation;
- // This awkward idiom warrants explanation.
- // For starters, LLSDMessage::ResponderAdapter is ONLY for testing the new
- // LLSDMessage functionality with a pre-existing LLHTTPClient::Responder.
- // In new code, define your reply/error methods on the same class as the
- // sending method, bind them to local LLEventPump objects and pass those
- // LLEventPump names in the request LLSD object.
- // When testing old code, the new LLHomeLocationResponder object
- // is referenced by an LLHTTPClient::ResponderPtr, so when the
- // ResponderAdapter is deleted, the LLHomeLocationResponder will be too.
- // We must trust that the underlying LLHTTPClient code will eventually
- // fire either the reply callback or the error callback; either will cause
- // the ResponderAdapter to delete itself.
- LLSDMessage::ResponderAdapter*
- adapter(new LLSDMessage::ResponderAdapter(new LLHomeLocationResponder()));
-
- request["message"] = "HomeLocation";
- request["payload"] = body;
- request["reply"] = adapter->getReplyName();
- request["error"] = adapter->getErrorName();
-
- gAgent.getRegion()->getCapAPI().post(request);
+ if (!requestPostCapability("HomeLocation", body,
+ boost::bind(&LLAgent::setStartPositionSuccess, this, _1)))
+ LL_WARNS() << "Unable to post to HomeLocation capability." << LL_ENDL;
const U32 HOME_INDEX = 1;
if( HOME_INDEX == location_id )
@@ -2355,32 +2349,51 @@ void LLAgent::setStartPosition( U32 location_id )
}
}
-struct HomeLocationMapper: public LLCapabilityListener::CapabilityMapper
+void LLAgent::setStartPositionSuccess(const LLSD &result)
{
- // No reply message expected
- HomeLocationMapper(): LLCapabilityListener::CapabilityMapper("HomeLocation") {}
- virtual void buildMessage(LLMessageSystem* msg,
- const LLUUID& agentID,
- const LLUUID& sessionID,
- const std::string& capabilityName,
- const LLSD& payload) const
+ 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 (!result.has("success"))
+ break;
+
+ if (0 != strncmp("true", result["success"].asString().c_str(), 4))
+ break;
+
+ // did the simulator return a "justified" home location?
+ // If no, we keep error set to true
+ if (!result.has("HomeLocation"))
+ break;
+
+ if ((!result["HomeLocation"].has("LocationPos")) ||
+ (!result["HomeLocation"]["LocationPos"].has("X")) ||
+ (!result["HomeLocation"]["LocationPos"].has("Y")) ||
+ (!result["HomeLocation"]["LocationPos"].has("Z")))
+ break;
+
+ agent_pos.mV[VX] = result["HomeLocation"]["LocationPos"]["X"].asInteger();
+ agent_pos.mV[VY] = result["HomeLocation"]["LocationPos"]["Y"].asInteger();
+ agent_pos.mV[VZ] = result["HomeLocation"]["LocationPos"]["Z"].asInteger();
+
+ error = false;
+
+ } while (0);
+
+ if (error)
{
- msg->newMessageFast(_PREHASH_SetStartLocationRequest);
- msg->nextBlockFast( _PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, agentID);
- msg->addUUIDFast(_PREHASH_SessionID, sessionID);
- msg->nextBlockFast( _PREHASH_StartLocationData);
- // corrected by sim
- msg->addStringFast(_PREHASH_SimName, "");
- msg->addU32Fast(_PREHASH_LocationID, payload["HomeLocation"]["LocationId"].asInteger());
- msg->addVector3Fast(_PREHASH_LocationPos,
- ll_vector3_from_sdmap(payload["HomeLocation"]["LocationPos"]));
- msg->addVector3Fast(_PREHASH_LocationLookAt,
- ll_vector3_from_sdmap(payload["HomeLocation"]["LocationLookAt"]));
+ LL_WARNS() << "Error in response to home position set." << LL_ENDL;
}
-};
-// Need an instance of this class so it will self-register
-static HomeLocationMapper homeLocationMapper;
+ else
+ {
+ LL_INFOS() << "setting home position" << LL_ENDL;
+
+ LLViewerRegion *viewer_region = gAgent.getRegion();
+ setHomePosRegion(viewer_region->getHandle(), agent_pos);
+ }
+}
void LLAgent::requestStopMotion( LLMotion* motion )
{
@@ -2517,87 +2530,6 @@ int LLAgent::convertTextToMaturity(char text)
return LLAgentAccess::convertTextToMaturity(text);
}
-class LLMaturityPreferencesResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLMaturityPreferencesResponder);
-public:
- LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity);
- virtual ~LLMaturityPreferencesResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-protected:
-
-private:
- U8 parseMaturityFromServerResponse(const LLSD &pContent) const;
-
- LLAgent *mAgent;
- U8 mPreferredMaturity;
- U8 mPreviousMaturity;
-};
-
-LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity)
- : LLHTTPClient::Responder(),
- mAgent(pAgent),
- mPreferredMaturity(pPreferredMaturity),
- mPreviousMaturity(pPreviousMaturity)
-{
-}
-
-LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()
-{
-}
-
-void LLMaturityPreferencesResponder::httpSuccess()
-{
- U8 actualMaturity = parseMaturityFromServerResponse(getContent());
-
- if (actualMaturity != mPreferredMaturity)
- {
- LL_WARNS() << "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() << LL_ENDL;
- }
- mAgent->handlePreferredMaturityResult(actualMaturity);
-}
-
-void LLMaturityPreferencesResponder::httpFailure()
-{
- LL_WARNS() << "while attempting to change maturity preference from '"
- << LLViewerRegion::accessToString(mPreviousMaturity)
- << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)
- << "', " << dumpResponse() << LL_ENDL;
- mAgent->handlePreferredMaturityError();
-}
-
-U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const
-{
- U8 maturity = SIM_ACCESS_MIN;
-
- 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.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())
- {
- LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString();
- LLStringUtil::trim(actualPreference);
- maturity = LLViewerRegion::shortStringToAccess(actualPreference);
- }
-
- return maturity;
-}
-
void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity)
{
// Update the number of responses received
@@ -2726,42 +2658,96 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)
// Update the last know maturity request
mLastKnownRequestMaturity = pPreferredMaturity;
- // Create a response handler
- LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity));
-
// If we don't have a region, report it as an error
if (getRegion() == NULL)
{
- responderPtr->failureResult(0U, "region is not defined", LLSD());
+ LL_WARNS("Agent") << "Region is not defined, can not change Maturity setting." << LL_ENDL;
+ return;
}
- else
- {
- // Find the capability to send maturity preference
- std::string url = getRegion()->getCapability("UpdateAgentInformation");
- // If the capability is not defined, report it as an error
- if (url.empty())
- {
- responderPtr->failureResult(0U,
- "capability 'UpdateAgentInformation' is not defined for region", LLSD());
- }
- else
- {
- // Set new access preference
- LLSD access_prefs = LLSD::emptyMap();
- access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity);
-
- LLSD body = LLSD::emptyMap();
- body["access_prefs"] = access_prefs;
- LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity)
- << "' via capability to: " << url << LL_ENDL;
- LLSD headers;
- LLHTTPClient::post(url, body, responderPtr, headers, 30.0f);
- }
- }
+ LLSD access_prefs = LLSD::emptyMap();
+ access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity);
+
+ LLSD postData = LLSD::emptyMap();
+ postData["access_prefs"] = access_prefs;
+ LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) << LL_ENDL;
+
+ if (!requestPostCapability("UpdateAgentInformation", postData,
+ static_cast<httpCallback_t>(boost::bind(&LLAgent::processMaturityPreferenceFromServer, this, _1, pPreferredMaturity)),
+ static_cast<httpCallback_t>(boost::bind(&LLAgent::handlePreferredMaturityError, this))
+ ))
+ {
+ LL_WARNS("Agent") << "Maturity request post failed." << LL_ENDL;
+ }
}
}
+
+void LLAgent::processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity)
+{
+ U8 maturity = SIM_ACCESS_MIN;
+
+ llassert(result.isDefined());
+ llassert(result.isMap());
+ llassert(result.has("access_prefs"));
+ llassert(result.get("access_prefs").isMap());
+ llassert(result.get("access_prefs").has("max"));
+ llassert(result.get("access_prefs").get("max").isString());
+ if (result.isDefined() && result.isMap() && result.has("access_prefs")
+ && result.get("access_prefs").isMap() && result.get("access_prefs").has("max")
+ && result.get("access_prefs").get("max").isString())
+ {
+ LLSD::String actualPreference = result.get("access_prefs").get("max").asString();
+ LLStringUtil::trim(actualPreference);
+ maturity = LLViewerRegion::shortStringToAccess(actualPreference);
+ }
+
+ if (maturity != perferredMaturity)
+ {
+ LL_WARNS() << "while attempting to change maturity preference from '"
+ << LLViewerRegion::accessToString(mLastKnownResponseMaturity)
+ << "' to '" << LLViewerRegion::accessToString(perferredMaturity)
+ << "', the server responded with '"
+ << LLViewerRegion::accessToString(maturity)
+ << "' [value:" << static_cast<U32>(maturity)
+ << "], " << LL_ENDL;
+ }
+ handlePreferredMaturityResult(maturity);
+}
+
+
+bool LLAgent::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure)
+{
+ std::string url;
+
+ url = getRegion()->getCapability(capName);
+
+ if (url.empty())
+ {
+ LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL;
+ return false;
+ }
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, mHttpPolicy, postData, cbSuccess, cbFailure);
+ return true;
+}
+
+bool LLAgent::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure)
+{
+ std::string url;
+
+ url = getRegion()->getCapability(capName);
+
+ if (url.empty())
+ {
+ LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL;
+ return false;
+ }
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, mHttpPolicy, cbSuccess, cbFailure);
+ return true;
+}
+
BOOL LLAgent::getAdminOverride() const
{
return mAgentAccess->getAdminOverride();
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 4830cb754b..5731f4db89 100755
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -34,7 +34,9 @@
#include "llcoordframe.h" // for mFrameAgent
#include "llavatarappearancedefines.h"
#include "llpermissionsflags.h"
+#include "llevents.h"
#include "v3dmath.h"
+#include "llcorehttputil.h"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
@@ -61,6 +63,8 @@ class LLPauseRequestHandle;
class LLUIColor;
class LLTeleportRequest;
+
+
typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr;
//--------------------------------------------------------------------
@@ -112,6 +116,8 @@ public:
void init();
void cleanup();
+private:
+
//--------------------------------------------------------------------
// Login
//--------------------------------------------------------------------
@@ -227,6 +233,8 @@ public:
void setHomePosRegion(const U64& region_handle, const LLVector3& pos_region);
BOOL getHomePosGlobal(LLVector3d* pos_global);
private:
+ void setStartPositionSuccess(const LLSD &result);
+
BOOL mHaveHomePosition;
U64 mHomeRegionHandle;
LLVector3 mHomePosRegion;
@@ -254,6 +262,9 @@ public:
LLHost getRegionHost() const;
BOOL inPrelude();
+ // Capability
+ std::string getRegionCapability(const std::string &name); // short hand for if (getRegion()) { getRegion()->getCapability(name) }
+
/**
* Register a boost callback to be called when the agent changes regions
* Note that if you need to access a capability for the region, you may need to wait
@@ -631,6 +642,8 @@ public:
void setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange);
private:
+
+
friend class LLTeleportRequest;
friend class LLTeleportRequestViaLandmark;
friend class LLTeleportRequestViaLure;
@@ -758,11 +771,12 @@ private:
unsigned int mMaturityPreferenceNumRetries;
U8 mLastKnownRequestMaturity;
U8 mLastKnownResponseMaturity;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
bool isMaturityPreferenceSyncedWithServer() const;
void sendMaturityPreferenceToServer(U8 pPreferredMaturity);
+ void processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity);
- friend class LLMaturityPreferencesResponder;
void handlePreferredMaturityResult(U8 pServerMaturity);
void handlePreferredMaturityError();
void reportPreferredMaturitySuccess();
@@ -911,6 +925,22 @@ public:
/********************************************************************************
** **
+ ** UTILITY
+ **/
+public:
+ typedef LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t httpCallback_t;
+
+ /// Utilities for allowing the the agent sub managers to post and get via
+ /// HTTP using the agent's policy settings and headers.
+ bool requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL);
+ bool requestGetCapability(const std::string &capName, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL);
+
+/** Utility
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
** DEBUGGING
**/
diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp
index fe6236a32a..cdb0e3302d 100755
--- a/indra/newview/llagentlanguage.cpp
+++ b/indra/newview/llagentlanguage.cpp
@@ -32,6 +32,7 @@
#include "llviewerregion.h"
// library includes
#include "llui.h" // getLanguage()
+#include "httpcommon.h"
// static
void LLAgentLanguage::init()
@@ -54,22 +55,17 @@ void LLAgentLanguage::onChange()
// static
bool LLAgentLanguage::update()
{
- LLSD body;
- std::string url;
+ LLSD body;
- if (gAgent.getRegion())
- {
- url = gAgent.getRegion()->getCapability("UpdateAgentLanguage");
- }
-
- if (!url.empty())
- {
- std::string language = LLUI::getLanguage();
+ std::string language = LLUI::getLanguage();
- body["language"] = language;
- body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic");
+ body["language"] = language;
+ body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic");
- LLHTTPClient::post(url, body, new LLHTTPClient::Responder);
- }
+ if (!gAgent.requestPostCapability("UpdateAgentLanguage", body))
+ {
+ LL_WARNS("Language") << "Language capability unavailable." << LL_ENDL;
+ }
+
return true;
}
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 714b456ae7..afc6e208e6 100755
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -40,317 +40,381 @@
/// 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);
-}
+//=========================================================================
+const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3");
+const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3");
+
+//-------------------------------------------------------------------------
+/*static*/
+bool AISAPI::isAvailable()
+{
+ if (gAgent.getRegion())
+ {
+ return gAgent.getRegion()->isCapabilityAvailable(INVENTORY_CAP_NAME);
+ }
+ return false;
+}
+
+/*static*/
+void AISAPI::getCapNames(LLSD& capNames)
+{
+ capNames.append(INVENTORY_CAP_NAME);
+ capNames.append(LIBRARY_CAP_NAME);
+}
-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;
- }
-}
+/*static*/
+std::string AISAPI::getInvCap()
+{
+ if (gAgent.getRegion())
+ {
+ return gAgent.getRegion()->getCapability(INVENTORY_CAP_NAME);
+ }
+ return std::string();
+}
+
+/*static*/
+std::string AISAPI::getLibCap()
+{
+ if (gAgent.getRegion())
+ {
+ return gAgent.getRegion()->getCapability(LIBRARY_CAP_NAME);
+ }
+ return std::string();
+}
+
+/*static*/
+void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback)
+{
+ std::string cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID tid;
+ tid.generate();
-void AISCommand::setCommandFunc(command_func_type command_func)
+ std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+
+ // I may be suffering from golden hammer here, but the first part of this bind
+ // is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that
+ // the compiler can identify the correct signature to select.
+ //
+ // Reads as follows:
+ // LLSD - method returning LLSD
+ // (LLCoreHttpUtil::HttpCoroutineAdapter::*) - pointer to member function of HttpCoroutineAdapter
+ // (LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) - signature of method
+ //
+ invokationFn_t postFn = boost::bind(
+ // Humans ignore next line. It is just a cast.
+ static_cast<LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY));
+ EnqueueAISCommand("CreateInventory", proc);
+}
+
+/*static*/
+void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback)
{
- 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);
+ std::string cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+
+ LLUUID tid;
+ tid.generate();
+
+ std::string url = cap + std::string("/category/") + folderId.asString() + "/links?tid=" + tid.asString();
- if (mCallback)
- {
- LLUUID id; // will default to null if parse fails.
- getResponseUUID(content,id);
- mCallback->fire(id);
- }
-}
+ // see comment above in CreateInventoryCommand
+ invokationFn_t putFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndSuspend), _1, _2, _3, _4, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, putFn, url, folderId, newInventory, callback, SLAMFOLDER));
+
+ EnqueueAISCommand("SlamFolder", proc);
+}
+
+void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback)
+{
+ std::string cap;
+
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+
+ std::string url = cap + std::string("/category/") + categoryId.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+
+ invokationFn_t delFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, delFn, url, categoryId, LLSD(), callback, REMOVECATEGORY));
+
+ EnqueueAISCommand("RemoveCategory", proc);
+}
+
+/*static*/
+void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback)
+{
+ std::string cap;
+
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+
+ std::string url = cap + std::string("/item/") + itemId.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+
+ invokationFn_t delFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, delFn, url, itemId, LLSD(), callback, REMOVEITEM));
+
+ EnqueueAISCommand("RemoveItem", proc);
+}
+
+void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback)
+{
+ std::string cap;
+
+ cap = getLibCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Library cap not found!" << LL_ENDL;
+ return;
+ }
-/*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);
- }
-}
+ LL_DEBUGS("Inventory") << "Copying library category: " << sourceId << " => " << destId << LL_ENDL;
-//static
-bool AISCommand::isAPIAvailable()
-{
- if (gAgent.getRegion())
- {
- return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3");
- }
- return false;
-}
+ LLUUID tid;
+ tid.generate();
-//static
-bool AISCommand::getInvCap(std::string& cap)
-{
- if (gAgent.getRegion())
- {
- cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
- }
- if (!cap.empty())
- {
- return true;
- }
- return false;
-}
+ std::string url = cap + std::string("/category/") + sourceId.asString() + "?tid=" + tid.asString();
+ if (!copySubfolders)
+ {
+ url += ",depth=0";
+ }
+ LL_INFOS() << url << LL_ENDL;
-//static
-bool AISCommand::getLibCap(std::string& cap)
-{
- if (gAgent.getRegion())
- {
- cap = gAgent.getRegion()->getCapability("LibraryAPIv3");
- }
- if (!cap.empty())
- {
- return true;
- }
- return false;
-}
+ std::string destination = destId.asString();
-//static
-void AISCommand::getCapabilityNames(LLSD& capabilityNames)
+ invokationFn_t copyFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const std::string, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::copyAndSuspend), _1, _2, _3, destination, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, copyFn, url, destId, LLSD(), callback, COPYLIBRARYCATEGORY));
+
+ EnqueueAISCommand("CopyLibraryCategory", proc);
+}
+
+/*static*/
+void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback)
{
- capabilityNames.append("InventoryAPIv3");
- capabilityNames.append("LibraryAPIv3");
-}
+ std::string cap;
-RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> callback):
- AISCommand(callback)
-{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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);
-}
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
-RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> callback):
- AISCommand(callback)
-{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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);
-}
+ std::string url = cap + std::string("/category/") + categoryId.asString() + "/children";
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> callback):
- AISCommand(callback)
-{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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);
-}
+ invokationFn_t delFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6);
-UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id,
- const LLSD& updates,
- LLPointer<LLInventoryCallback> callback):
- mUpdates(updates),
- AISCommand(callback)
-{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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);
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, delFn, url, categoryId, LLSD(), callback, PURGEDESCENDENTS));
+
+ EnqueueAISCommand("PurgeDescendents", proc);
}
-UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& cat_id,
- const LLSD& updates,
- LLPointer<LLInventoryCallback> callback):
- mUpdates(updates),
- AISCommand(callback)
-{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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)
+/*static*/
+void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback)
{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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);
+ std::string cap;
+
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + categoryId.asString();
+
+ invokationFn_t patchFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndSuspend), _1, _2, _3, _4, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, patchFn, url, categoryId, updates, callback, UPDATECATEGORY));
+
+ EnqueueAISCommand("UpdateCategory", proc);
}
-SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback):
- mContents(contents),
- AISCommand(callback)
+/*static*/
+void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback)
{
- std::string cap;
- if (!getInvCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- return;
- }
- LLUUID tid;
- tid.generate();
- std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString();
- LL_INFOS() << 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::put, url, mContents, responder, headers, timeout);
- setCommandFunc(cmd);
+
+ std::string cap;
+
+ cap = getInvCap();
+ if (cap.empty())
+ {
+ LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+ return;
+ }
+ std::string url = cap + std::string("/item/") + itemId.asString();
+
+ invokationFn_t patchFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> body
+ // _5 -> httpOptions
+ // _6 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndSuspend), _1, _2, _3, _4, _5, _6);
+
+ LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+ _1, patchFn, url, itemId, updates, callback, UPDATEITEM));
+
+ EnqueueAISCommand("UpdateItem", proc);
}
-CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id,
- const LLUUID& dest_id,
- LLPointer<LLInventoryCallback> callback,
- bool copy_subfolders):
- AISCommand(callback)
+/*static*/
+void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc)
{
- std::string cap;
- if (!getLibCap(cap))
- {
- LL_WARNS() << "No cap found" << LL_ENDL;
- 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();
- if (!copy_subfolders)
- {
- url += ",depth=0";
- }
- LL_INFOS() << url << LL_ENDL;
- 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);
+ std::string procFullName = "AIS(" + procName + ")";
+ LLCoprocedureManager::instance().enqueueCoprocedure("AIS", procFullName, proc);
+
}
-bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id)
+/*static*/
+void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter,
+ invokationFn_t invoke, std::string url,
+ LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type)
{
- if (content.has("category_id"))
- {
- id = content["category_id"];
- return true;
- }
- return false;
+ LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
+ LLCore::HttpHeaders::ptr_t httpHeaders;
+
+ httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS);
+
+ LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+
+ LLSD result = invoke(httpAdapter, httpRequest, url, body, httpOptions, httpHeaders);
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status || !result.isMap())
+ {
+ if (!result.isMap())
+ {
+ status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents");
+ }
+ LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
+ LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
+ }
+
+ gInventory.onAISUpdateReceived("AISCommand", result);
+
+ if (callback && !callback.empty())
+ {
+ LLUUID id(LLUUID::null);
+
+ if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
+ {
+ id = result["category_id"];
+ }
+
+ callback(id);
+ }
+
}
+//-------------------------------------------------------------------------
AISUpdate::AISUpdate(const LLSD& update)
{
parseUpdate(update);
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index bb483fb133..e97059014b 100755
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -31,112 +31,55 @@
#include <map>
#include <set>
#include <string>
-#include "llcurl.h"
-#include "llhttpclient.h"
#include "llhttpretrypolicy.h"
#include "llviewerinventory.h"
+#include "llcorehttputil.h"
+#include "llcoproceduremanager.h"
-class AISCommand: public LLHTTPClient::Responder
+class AISAPI
{
public:
- typedef boost::function<void()> command_func_type;
+ typedef boost::function<void(const LLUUID &invItem)> completion_t;
- AISCommand(LLPointer<LLInventoryCallback> callback);
+ static bool isAvailable();
+ static void getCapNames(LLSD& capNames);
- virtual ~AISCommand() {}
+ static void CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback = completion_t());
+ static void SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback = completion_t());
+ static void RemoveCategory(const LLUUID &categoryId, completion_t callback = completion_t());
+ static void RemoveItem(const LLUUID &itemId, completion_t callback = completion_t());
+ static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t());
+ static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t());
+ static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t());
+ static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t());
- 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;
-};
+ typedef enum {
+ COPYINVENTORY,
+ SLAMFOLDER,
+ REMOVECATEGORY,
+ REMOVEITEM,
+ PURGEDESCENDENTS,
+ UPDATECATEGORY,
+ UPDATEITEM,
+ COPYLIBRARYCATEGORY
+ } COMMAND_TYPE;
-class UpdateCategoryCommand: public AISCommand
-{
-public:
- UpdateCategoryCommand(const LLUUID& cat_id,
- const LLSD& updates,
- LLPointer<LLInventoryCallback> callback);
-private:
- LLSD mUpdates;
-};
+ static const std::string INVENTORY_CAP_NAME;
+ static const std::string LIBRARY_CAP_NAME;
-class SlamFolderCommand: public AISCommand
-{
-public:
- SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback);
-
-private:
- LLSD mContents;
-};
+ typedef boost::function < LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t, LLCore::HttpRequest::ptr_t,
+ const std::string, LLSD, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) > invokationFn_t;
-class CopyLibraryCategoryCommand: public AISCommand
-{
-public:
- CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback, bool copy_subfolders = true);
+ static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
-protected:
- /* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id);
-};
+ static std::string getInvCap();
+ static std::string getLibCap();
-class CreateInventoryCommand: public AISCommand
-{
-public:
- CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback);
+ static void InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter,
+ invokationFn_t invoke, std::string url, LLUUID targetId, LLSD body,
+ completion_t callback, COMMAND_TYPE type);
-private:
- LLSD mNewInventory;
};
class AISUpdate
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index f5f224b83e..91a5148e4c 100755
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -31,6 +31,10 @@
#include "llappviewer.h"
#include "llviewercontrol.h"
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+#include "llsecapi.h"
+#include <curl/curl.h>
// Here is where we begin to get our connection usage under control.
// This establishes llcorehttp policy classes that, among other
@@ -93,6 +97,16 @@ static const struct
4, 1, 4, 0, false,
"",
"inventory"
+ },
+ { // AP_MATERIALS
+ 2, 1, 8, 0, false,
+ "RenderMaterials",
+ "material manager requests"
+ },
+ { // AP_AGENT
+ 2, 1, 32, 0, true,
+ "Agent",
+ "Agent requests"
}
};
@@ -124,6 +138,9 @@ LLAppCoreHttp::~LLAppCoreHttp()
void LLAppCoreHttp::init()
{
+
+ LLCore::LLHttp::initialize();
+
LLCore::HttpStatus status = LLCore::HttpRequest::createService();
if (! status)
{
@@ -151,6 +168,15 @@ void LLAppCoreHttp::init()
<< LL_ENDL;
}
+ // Set up SSL Verification call back.
+ status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_SSL_VERIFY_CALLBACK,
+ LLCore::HttpRequest::GLOBAL_POLICY_ID,
+ sslVerify, NULL);
+ if (!status)
+ {
+ LL_WARNS("Init") << "Failed to set SSL Verification. Reason: " << status.toString() << LL_ENDL;
+ }
+
// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):
// 0 - None
// 1 - Basic start, stop simple transitions
@@ -182,6 +208,8 @@ void LLAppCoreHttp::init()
}
mHttpClasses[app_policy].mPolicy = LLCore::HttpRequest::createPolicyClass();
+ // We have run out of available HTTP policies. Adjust HTTP_POLICY_CLASS_LIMIT in _httpinternal.h
+ llassert(mHttpClasses[app_policy].mPolicy != LLCore::HttpRequest::INVALID_POLICY_ID);
if (! mHttpClasses[app_policy].mPolicy)
{
// Use default policy (but don't accidentally modify default)
@@ -457,6 +485,62 @@ void LLAppCoreHttp::refreshSettings(bool initial)
}
}
+LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url,
+ LLCore::HttpHandler const * const handler, void *appdata)
+{
+ X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata);
+ LLCore::HttpStatus result;
+ LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
+ LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
+ LLSD validation_params = LLSD::emptyMap();
+ LLURI uri(url);
+
+ validation_params[CERT_HOSTNAME] = uri.hostName();
+
+ // *TODO: In the case of an exception while validating the cert, we need a way
+ // to pass the offending(?) cert back out. *Rider*
+
+ try
+ {
+ // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects
+ store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
+ }
+ catch (LLCertValidationTrustException &cert_exception)
+ {
+ // this exception is is handled differently than the general cert
+ // exceptions, as we allow the user to actually add the certificate
+ // for trust.
+ // therefore we pass back a different error code
+ // NOTE: We're currently 'wired' to pass around CURL error codes. This is
+ // somewhat clumsy, as we may run into errors that do not map directly to curl
+ // error codes. Should be refactored with login refactoring, perhaps.
+ result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CACERT);
+ result.setMessage(cert_exception.getMessage());
+ LLPointer<LLCertificate> cert = cert_exception.getCert();
+ cert->ref(); // adding an extra ref here
+ result.setErrorData(cert.get());
+ // We should probably have a more generic way of passing information
+ // back to the error handlers.
+ }
+ catch (LLCertException &cert_exception)
+ {
+ result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_PEER_CERTIFICATE);
+ result.setMessage(cert_exception.getMessage());
+ LLPointer<LLCertificate> cert = cert_exception.getCert();
+ cert->ref(); // adding an extra ref here
+ result.setErrorData(cert.get());
+ }
+ catch (...)
+ {
+ // any other odd error, we just handle as a connect error.
+ result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR);
+ }
+
+ return result;
+}
+
+
+
void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
{
diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h
index 37d7a737e7..410d7c6b07 100755
--- a/indra/newview/llappcorehttp.h
+++ b/indra/newview/llappcorehttp.h
@@ -164,7 +164,29 @@ public:
/// Pipelined: no
AP_INVENTORY,
AP_REPORTING = AP_INVENTORY, // Piggy-back on inventory
-
+
+ /// Material resource requests and puts.
+ ///
+ /// Destination: simhost:12043
+ /// Protocol: https:
+ /// Transfer size: KB
+ /// Long poll: no
+ /// Concurrency: low
+ /// Request rate: low
+ /// Pipelined: no
+ AP_MATERIALS,
+
+ /// Appearance resource requests and puts.
+ ///
+ /// Destination: simhost:12043
+ /// Protocol: https:
+ /// Transfer size: KB
+ /// Long poll: no
+ /// Concurrency: mid
+ /// Request rate: low
+ /// Pipelined: yes
+ AP_AGENT,
+
AP_COUNT // Must be last
};
@@ -233,7 +255,9 @@ private:
bool mStopped;
HttpClass mHttpClasses[AP_COUNT];
bool mPipelined; // Global setting
- boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting
+ boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting
+
+ static LLCore::HttpStatus sslVerify(const std::string &uri, LLCore::HttpHandler const * const handler, void *appdata);
};
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 35593dd4ff..eea585e998 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -23,7 +23,7 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
-
+
#include "llviewerprecompiledheaders.h"
#include <boost/lexical_cast.hpp>
@@ -54,12 +54,26 @@
#include "llsdserialize.h"
#include "llhttpretrypolicy.h"
#include "llaisapi.h"
+#include "llhttpsdhandler.h"
+#include "llcorehttputil.h"
+#include "llappviewer.h"
#if LL_MSVC
// disable boost::lexical_cast warning
#pragma warning (disable:4702)
#endif
+#if 1
+// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model.
+// temp code in transition
+void doAppearanceCb(LLPointer<LLInventoryCallback> cb, LLUUID id)
+{
+ if (cb.notNull())
+ cb->fire(id);
+}
+#endif
+
+
std::string self_av_string()
{
// On logout gAgentAvatarp can already be invalid
@@ -1257,6 +1271,8 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)
items = new_items;
}
+//=========================================================================
+
const LLUUID LLAppearanceMgr::getCOF() const
{
return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
@@ -2458,8 +2474,7 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
<< " )" << LL_ENDL;
// If we are copying from library, attempt to use AIS to copy the category.
- bool ais_ran=false;
- if (copy && AISCommand::isAPIAvailable())
+ if (copy && AISAPI::isAvailable())
{
LLUUID parent_id;
parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
@@ -2471,11 +2486,11 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
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, false);
- ais_ran=cmd_ptr->run_command();
- }
- if (!ais_ran)
+ AISAPI::completion_t cr = boost::bind(&doAppearanceCb, track_cb, _1);
+ AISAPI::CopyLibraryCategory(category->getUUID(), parent_id, false, cr);
+ }
+ else
{
selfStartPhase("wear_inventory_category_fetch");
callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
@@ -3267,276 +3282,6 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,
}
-class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(RequestAgentUpdateAppearanceResponder);
-
- friend class LLAppearanceMgr;
-
-public:
- RequestAgentUpdateAppearanceResponder();
-
- virtual ~RequestAgentUpdateAppearanceResponder();
-
-private:
- // 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;
-};
-
-RequestAgentUpdateAppearanceResponder::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 << LL_ENDL;
- if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired()))
- {
- LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL;
- mInFlightCounter = 0;
- }
- if (cof_version < last_rcv)
- {
- LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
- << " will not request for " << cof_version << LL_ENDL;
- return;
- }
- if (mInFlightCounter>0 && last_req >= cof_version)
- {
- LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
- << " will not request for " << cof_version << LL_ENDL;
- return;
- }
-
- // Actually send the request.
- LL_DEBUGS("Avatar") << "ATT sending bake request for cof_version " << cof_version << LL_ENDL;
- mRetryPolicy->reset();
- sendRequest();
-}
-
-void RequestAgentUpdateAppearanceResponder::sendRequest()
-{
- if (gAgentAvatarp->isEditingAppearance())
- {
- // don't send out appearance updates if in appearance editing mode
- return;
- }
-
- if (!gAgent.getRegion())
- {
- LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL;
- return;
- }
- if (gAgent.getRegion()->getCentralBakeVersion()==0)
- {
- LL_WARNS() << "Region does not support baking" << LL_ENDL;
- }
- std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
- if (url.empty())
- {
- LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL;
- 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"))
- {
- body["cof_version"] = cof_version+999;
- }
- }
- LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL;
-
- mInFlightCounter++;
- mInFlightTimer.setTimerExpirySec(60.0);
- LLHTTPClient::post(url, body, this);
- llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
- gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
-}
-
-void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content)
-{
- LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
- << " ================================= " << LL_ENDL;
- 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())
- {
- ais_items.insert(item["item_id"].asUUID());
- if (item["type"].asInteger() == 24) // link
- {
- LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID()
- << " linked_item_id: " << item["asset_id"].asUUID()
- << " name: " << item["name"].asString()
- << LL_ENDL;
- }
- 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()
- << LL_ENDL;
- }
- 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()
- << LL_ENDL;
- }
- }
- }
- LL_INFOS("Avatar") << LL_ENDL;
- LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()
- << " ================================= " << LL_ENDL;
- 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.size(); i++)
- {
- const LLViewerInventoryItem* inv_item = item_array.at(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()
- << LL_ENDL;
- }
- LL_INFOS("Avatar") << " ================================= " << LL_ENDL;
- S32 local_only = 0, ais_only = 0;
- for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
- {
- if (ais_items.find(*it) == ais_items.end())
- {
- LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL;
- local_only++;
- }
- }
- for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
- {
- if (local_items.find(*it) == local_items.end())
- {
- LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL;
- ais_only++;
- }
- }
- if (local_only==0 && ais_only==0)
- {
- LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req "
- << content["observed"].asInteger()
- << " rcv " << content["expected"].asInteger()
- << ")" << LL_ENDL;
- }
-}
-
-/* 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" << LL_ENDL;
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
- 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))
- {
- LL_INFOS() << "retrying" << LL_ENDL;
- doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this),
- seconds_to_wait);
- }
- else
- {
- LL_WARNS() << "giving up after too many retries" << LL_ENDL;
- }
-}
-
LLSD LLAppearanceMgr::dumpCOF() const
{
@@ -3603,102 +3348,201 @@ LLSD LLAppearanceMgr::dumpCOF() const
void LLAppearanceMgr::requestServerAppearanceUpdate()
{
- mAppearanceResponder->onRequestRequested();
-}
-class LLIncrementCofVersionResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLIncrementCofVersionResponder);
-public:
- LLIncrementCofVersionResponder() : LLHTTPClient::Responder()
+ if (!testCOFRequestVersion())
{
- mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5);
+ // *TODO: LL_LOG message here
+ return;
}
- virtual ~LLIncrementCofVersionResponder()
+ if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired()))
{
+ LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL;
+ mInFlightCounter = 0;
}
-protected:
- virtual void httpSuccess()
+ if (gAgentAvatarp->isEditingAppearance())
{
- LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL;
- 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;
+ LL_WARNS("Avatar") << "Avatar editing appearance, not sending request." << LL_ENDL;
+ // don't send out appearance updates if in appearance editing mode
+ return;
}
- virtual void httpFailure()
+ if (!gAgent.getRegion())
{
- LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error "
- << dumpResponse() << LL_ENDL;
- F32 seconds_to_wait;
- mRetryPolicy->onFailure(getStatus(), getResponseHeaders());
- if (mRetryPolicy->shouldRetry(seconds_to_wait))
- {
- LL_INFOS() << "retrying" << LL_ENDL;
- doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion,
- LLAppearanceMgr::getInstance(),
- LLHTTPClient::ResponderPtr(this)),
- seconds_to_wait);
- }
- else
- {
- LL_WARNS() << "giving up after too many retries" << LL_ENDL;
- }
+ LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL;
+ return;
}
-
-private:
- LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
-};
-
-void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr)
-{
- // If we don't have a region, report it as an error
- if (gAgent.getRegion() == NULL)
+ if (gAgent.getRegion()->getCentralBakeVersion() == 0)
{
- LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL;
- return;
+ LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;
}
- std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion");
- if (url.empty())
+ LLSD postData;
+ S32 cof_version = LLAppearanceMgr::instance().getCOFVersion();
+ if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
{
- LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL;
- return;
+ postData = LLAppearanceMgr::instance().dumpCOF();
}
-
- LL_INFOS() << "Requesting cof_version be incremented via capability to: "
- << url << LL_ENDL;
- LLSD headers;
- LLSD body = LLSD::emptyMap();
-
- if (!responder_ptr.get())
+ else
{
- responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder());
+ postData["cof_version"] = cof_version;
+ if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))
+ {
+ postData["cof_version"] = cof_version + 999;
+ }
}
- LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f);
+ mInFlightCounter++;
+ mInFlightTimer.setTimerExpirySec(60.0);
+
+ llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion);
+ gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version;
+
+ if (!gAgent.requestPostCapability("UpdateAvatarAppearance", postData,
+ static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::serverAppearanceUpdateSuccess, this, _1)),
+ static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::decrementInFlightCounter, this))))
+ {
+ LL_WARNS("Avatar") << "Unable to access UpdateAvatarAppearance in this region." << LL_ENDL;
+ }
}
-U32 LLAppearanceMgr::getNumAttachmentsInCOF()
+void LLAppearanceMgr::serverAppearanceUpdateSuccess(const LLSD &result)
{
- const LLUUID cof = getCOF();
- LLInventoryModel::item_array_t obj_items;
- getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT);
- return obj_items.size();
+ decrementInFlightCounter();
+ if (result["success"].asBoolean())
+ {
+ LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL;
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result);
+ }
+ }
+ else
+ {
+ LL_WARNS("Avatar") << "Non success response for change appearance" << LL_ENDL;
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ debugAppearanceUpdateCOF(result);
+ }
+ }
+}
+
+/*static*/
+void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content)
+{
+ dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content);
+
+ LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger()
+ << " ================================= " << LL_ENDL;
+ 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())
+ {
+ ais_items.insert(item["item_id"].asUUID());
+ if (item["type"].asInteger() == 24) // link
+ {
+ LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID()
+ << " linked_item_id: " << item["asset_id"].asUUID()
+ << " name: " << item["name"].asString()
+ << LL_ENDL;
+ }
+ 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()
+ << LL_ENDL;
+ }
+ 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()
+ << LL_ENDL;
+ }
+ }
+ }
+ LL_INFOS("Avatar") << LL_ENDL;
+ LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()
+ << " ================================= " << LL_ENDL;
+ 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.size(); i++)
+ {
+ const LLViewerInventoryItem* inv_item = item_array.at(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()
+ << LL_ENDL;
+ }
+ LL_INFOS("Avatar") << " ================================= " << LL_ENDL;
+ S32 local_only = 0, ais_only = 0;
+ for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it)
+ {
+ if (ais_items.find(*it) == ais_items.end())
+ {
+ LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL;
+ local_only++;
+ }
+ }
+ for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)
+ {
+ if (local_items.find(*it) == local_items.end())
+ {
+ LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL;
+ ais_only++;
+ }
+ }
+ if (local_only == 0 && ais_only == 0)
+ {
+ LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req "
+ << content["observed"].asInteger()
+ << " rcv " << content["expected"].asInteger()
+ << ")" << LL_ENDL;
+ }
}
+bool LLAppearanceMgr::testCOFRequestVersion() const
+{
+ // If we have already received an update for this or higher cof version, ignore.
+ S32 cof_version = 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
+ << LL_ENDL;
+ if (cof_version < last_rcv)
+ {
+ LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv
+ << " will not request for " << cof_version << LL_ENDL;
+ return false;
+ }
+ if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version)
+ {
+ LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req
+ << " will not request for " << cof_version << LL_ENDL;
+ return false;
+ }
+
+ // Actually send the request.
+ LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL;
+ return true;
+}
+
std::string LLAppearanceMgr::getAppearanceServiceURL() const
{
if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty())
@@ -3774,7 +3618,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo
// First, make a folder in the My Outfits directory.
const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
// cap-based category creation was buggy until recently. use
// existence of AIS as an indicator the fix is present. Does
@@ -3967,15 +3811,17 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,
}
}
+bool LLAppearanceMgr::mActive = true;
+
LLAppearanceMgr::LLAppearanceMgr():
mAttachmentInvLinkEnabled(false),
mOutfitIsDirty(false),
mOutfitLocked(false),
- mIsInUpdateAppearanceFromCOF(false),
- mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)
+ mInFlightCounter(0),
+ mInFlightTimer(),
+ mIsInUpdateAppearanceFromCOF(false)
{
LLOutfitObserver& outfit_observer = LLOutfitObserver::instance();
-
// unlock outfit on save operation completed
outfit_observer.addCOFSavedCallback(boost::bind(
&LLAppearanceMgr::setOutfitLocked, this, false));
@@ -3983,11 +3829,12 @@ LLAppearanceMgr::LLAppearanceMgr():
mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
"OutfitOperationsTimeout")));
- gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL);
+ gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL);
}
LLAppearanceMgr::~LLAppearanceMgr()
{
+ mActive = false;
}
void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val)
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 4ed8c1bfb9..9b6ceb7d3e 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -34,12 +34,10 @@
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
#include "llviewerinventory.h"
-#include "llhttpclient.h"
class LLWearableHoldingPattern;
class LLInventoryCallback;
class LLOutfitUnLockTimer;
-class RequestAgentUpdateAppearanceResponder;
class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
{
@@ -54,7 +52,6 @@ public:
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);
void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
@@ -224,20 +221,23 @@ public:
void requestServerAppearanceUpdate();
- void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL);
+ void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }
+ std::string getAppearanceServiceURL() const;
- U32 getNumAttachmentsInCOF();
- // *HACK Remove this after server side texture baking is deployed on all sims.
- void incrementCofVersionLegacy();
+ bool testCOFRequestVersion() const;
+ void decrementInFlightCounter()
+ {
+ mInFlightCounter = llmax(mInFlightCounter - 1, 0);
+ }
- void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; }
- std::string getAppearanceServiceURL() const;
private:
+ void serverAppearanceUpdateSuccess(const LLSD &result);
+ static void debugAppearanceUpdateCOF(const LLSD& content);
+
std::string mAppearanceServiceURL;
-
protected:
LLAppearanceMgr();
~LLAppearanceMgr();
@@ -261,13 +261,14 @@ private:
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.
*/
bool mOutfitLocked;
+ S32 mInFlightCounter;
+ LLTimer mInFlightTimer;
+ static bool mActive;
std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9b9b591cd1..44c9f893b8 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -57,8 +57,6 @@
#include "llfocusmgr.h"
#include "llviewerjoystick.h"
#include "llallocator.h"
-#include "llares.h"
-#include "llcurl.h"
#include "llcalc.h"
#include "llconversationlog.h"
#include "lldxhardware.h"
@@ -228,7 +226,7 @@
#include "llmachineid.h"
#include "llmainlooprepeater.h"
-
+#include "llcoproceduremanager.h"
#include "llviewereventrecorder.h"
@@ -755,8 +753,11 @@ void fast_exit(int rc)
{
_exit(rc);
}
+
+
}
+
bool LLAppViewer::init()
{
setupErrorHandling(mSecondInstance);
@@ -825,12 +826,7 @@ bool LLAppViewer::init()
// before consumers (LLTextureFetch).
mAppCoreHttp.init();
- // *NOTE:Mani - LLCurl::initClass is not thread safe.
- // Called before threads are created.
- LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"),
- gSavedSettings.getS32("CurlMaximumNumberOfHandles"),
- gSavedSettings.getBOOL("CurlUseMultipleThreads"));
- LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;
+ LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ;
LLMachineID::init();
@@ -900,7 +896,7 @@ bool LLAppViewer::init()
// the libs involved in getting to a full login screen.
//
LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
- LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
+ LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL;
/////////////////////////////////////////////////
// OS-specific login dialogs
@@ -1157,8 +1153,6 @@ bool LLAppViewer::init()
{
LLNotificationsUtil::add("CorruptedProtectedDataStore");
}
- LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback);
-
gGLActive = FALSE;
@@ -1216,6 +1210,12 @@ bool LLAppViewer::init()
LLAgentLanguage::init();
+ /// Tell the Coprocedure manager how to discover and store the pool sizes
+ // what I wanted
+ LLCoprocedureManager::getInstance()->setPropertyMethods(
+ boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1),
+ boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS));
+
return true;
}
@@ -1282,7 +1282,6 @@ static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread");
static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads");
static LLTrace::BlockTimerStatHandle FTM_IDLE("Idle");
static LLTrace::BlockTimerStatHandle FTM_PUMP("Pump");
-static LLTrace::BlockTimerStatHandle FTM_PUMP_ARES("Ares");
static LLTrace::BlockTimerStatHandle FTM_PUMP_SERVICE("Service");
static LLTrace::BlockTimerStatHandle FTM_SERVICE_CALLBACK("Callback");
static LLTrace::BlockTimerStatHandle FTM_AGENT_AUTOPILOT("Autopilot");
@@ -1306,8 +1305,6 @@ bool LLAppViewer::mainLoop()
// Create IO Pump to use for HTTP Requests.
gServicePump = new LLPumpIO(gAPRPoolp);
- LLHTTPClient::setPump(*gServicePump);
- LLCurl::setCAFile(gDirUtilp->getCAFile());
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
@@ -1426,26 +1423,6 @@ bool LLAppViewer::mainLoop()
LL_RECORD_BLOCK_TIME(FTM_IDLE);
idle();
- if (gAres != NULL && gAres->isInitialized())
- {
- pingMainloopTimeout("Main:ServicePump");
- LL_RECORD_BLOCK_TIME(FTM_PUMP);
- {
- LL_RECORD_BLOCK_TIME(FTM_PUMP_ARES);
- gAres->process();
- }
- {
- LL_RECORD_BLOCK_TIME(FTM_PUMP_SERVICE);
- // this pump is necessary to make the login screen show up
- gServicePump->pump();
-
- {
- LL_RECORD_BLOCK_TIME(FTM_SERVICE_CALLBACK);
- gServicePump->callback();
- }
- }
- }
-
resumeMainloopTimeout();
}
@@ -1550,11 +1527,6 @@ bool LLAppViewer::mainLoop()
}
gMeshRepo.update() ;
- if(!LLCurl::getCurlThread()->update(1))
- {
- LLCurl::getCurlThread()->pause() ; //nothing in the curl thread.
- }
-
if(!total_work_pending) //pause texture fetching threads if nothing to process.
{
LLAppViewer::getTextureCache()->pause();
@@ -1992,7 +1964,6 @@ bool LLAppViewer::cleanup()
pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
pending += LLVFSThread::updateClass(0);
pending += LLLFSThread::updateClass(0);
- pending += LLCurl::getCurlThread()->update(1) ;
F64 idle_time = idleTimer.getElapsedTimeF64();
if(!pending)
{
@@ -2004,7 +1975,6 @@ bool LLAppViewer::cleanup()
break;
}
}
- LLCurl::getCurlThread()->pause() ;
// Delete workers first
// shotdown all worker threads before deleting them in case of co-dependencies
@@ -2019,17 +1989,9 @@ bool LLAppViewer::cleanup()
LL_INFOS() << "Shutting down message system" << LL_ENDL;
end_messaging_system();
- // *NOTE:Mani - The following call is not thread safe.
- LL_CHECK_MEMORY
- LLCurl::cleanupClass();
- LL_CHECK_MEMORY
-
// Non-LLCurl libcurl library
mAppCoreHttp.cleanup();
- // NOTE The following call is not thread safe.
- ll_cleanup_ares();
-
LLFilePickerThread::cleanupClass();
//MUST happen AFTER LLCurl::cleanupClass
@@ -2115,6 +2077,7 @@ bool LLAppViewer::cleanup()
}
LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL;
LLProxy::cleanupClass();
+ LLCore::LLHttp::cleanup();
LLWearableType::cleanupClass();
@@ -3354,7 +3317,7 @@ LLSD LLAppViewer::getViewerInfo() const
#endif
info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
- info["LIBCURL_VERSION"] = LLCurl::getVersionString();
+ info["LIBCURL_VERSION"] = LLCore::LLHttp::getCURLVersion();
info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
bool want_fullname = true;
info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD();
@@ -4700,31 +4663,6 @@ void LLAppViewer::saveNameCache()
}
-void LLAppViewer::saveExperienceCache()
-{
- std::string filename =
- gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
- LL_INFOS("ExperienceCache") << "Saving " << filename << LL_ENDL;
- llofstream cache_stream(filename.c_str());
- if(cache_stream.is_open())
- {
- LLExperienceCache::exportFile(cache_stream);
- }
-}
-
-void LLAppViewer::loadExperienceCache()
-{
- std::string filename =
- gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
- LL_INFOS("ExperienceCache") << "Loading " << filename << LL_ENDL;
- llifstream cache_stream(filename.c_str());
- if(cache_stream.is_open())
- {
- LLExperienceCache::importFile(cache_stream);
- }
-}
-
-
/*! @brief This class is an LLFrameTimer that can be created with
an elapsed time that starts counting up from the given value
rather than 0.0.
@@ -4920,7 +4858,6 @@ void LLAppViewer::idle()
// floating throughout the various object lists.
//
idleNameCache();
- idleExperienceCache();
idleNetwork();
@@ -5350,22 +5287,6 @@ void LLAppViewer::idleNameCache()
LLAvatarNameCache::idle();
}
-void LLAppViewer::idleExperienceCache()
-{
- LLViewerRegion* region = gAgent.getRegion();
- if (!region) return;
-
- std::string lookup_url=region->getCapability("GetExperienceInfo");
- if(!lookup_url.empty() && *lookup_url.rbegin() != '/')
- {
- lookup_url += '/';
- }
-
- LLExperienceCache::setLookupURL(lookup_url);
-
- LLExperienceCache::idle();
-}
-
//
// Handle messages, and all message related stuff
//
@@ -5528,7 +5449,9 @@ void LLAppViewer::disconnectViewer()
}
saveNameCache();
- saveExperienceCache();
+ LLExperienceCache *expCache = LLExperienceCache::getIfExists();
+ if (expCache)
+ expCache->cleanup();
// close inventory interface, close all windows
LLFloaterInventory::cleanup();
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 718871138e..e8a1ca036b 100755
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -122,9 +122,6 @@ public:
void loadNameCache();
void saveNameCache();
- void loadExperienceCache();
- void saveExperienceCache();
-
void removeMarkerFiles();
void removeDumpDir();
@@ -233,7 +230,6 @@ private:
void idle();
void idleShutdown();
// update avatar SLID and display name caches
- void idleExperienceCache();
void idleNameCache();
void idleNetwork();
diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp
deleted file mode 100755
index 359ee1e221..0000000000
--- a/indra/newview/llassetuploadqueue.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/**
- * @file llassetupload.cpp
- * @brief Serializes asset upload request
- *
- * $LicenseInfo:firstyear=2007&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 "llassetuploadqueue.h"
-#include "llviewerregion.h"
-#include "llviewerobjectlist.h"
-
-#include "llassetuploadresponders.h"
-#include "llsd.h"
-#include <iostream>
-
-class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder
-{
- LOG_CLASS(LLAssetUploadChainResponder);
-public:
-
- LLAssetUploadChainResponder(const LLSD& post_data,
- const std::string& file_name,
- const LLUUID& queue_id,
- U8* data,
- U32 data_size,
- std::string script_name,
- LLAssetUploadQueueSupplier *supplier) :
- LLUpdateTaskInventoryResponder(post_data, file_name, queue_id, LLAssetType::AT_LSL_TEXT),
- mSupplier(supplier),
- mData(data),
- 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;
- delete mData;
- }
-
-protected:
- virtual void httpFailure()
- {
- // Parent class will spam the failure.
- //LL_WARNS() << dumpResponse() << LL_ENDL;
- LLUpdateTaskInventoryResponder::httpFailure();
- LLAssetUploadQueue *queue = mSupplier->get();
- if (queue)
- {
- queue->request(&mSupplier);
- }
- }
-
- virtual void httpSuccess()
- {
- LLUpdateTaskInventoryResponder::httpSuccess();
- LLAssetUploadQueue *queue = mSupplier->get();
- if (queue)
- {
- // 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"];
-
- mSupplier->log(std::string("Compiling " + mScriptName).c_str());
- LL_INFOS() << "Compiling " << LL_ENDL;
-
- // postRaw takes ownership of mData and will delete it.
- LLHTTPClient::postRaw(uploader, mData, mDataSize, this);
- mData = NULL;
- mDataSize = 0;
- }
-
- virtual void uploadComplete(const LLSD& content)
- {
- // Bytecode save completed
- if (content["compiled"])
- {
- mSupplier->log("Compilation succeeded");
- LL_INFOS() << "Compiled!" << LL_ENDL;
- }
- else
- {
- LLSD compile_errors = content["errors"];
- for(LLSD::array_const_iterator line = compile_errors.beginArray();
- line < compile_errors.endArray(); line++)
- {
- std::string str = line->asString();
- str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
- mSupplier->log(str);
- LL_INFOS() << content["errors"] << LL_ENDL;
- }
- }
- LLUpdateTaskInventoryResponder::uploadComplete(content);
- }
-
- LLAssetUploadQueueSupplier *mSupplier;
- U8* mData;
- U32 mDataSize;
- std::string mScriptName;
-};
-
-
-LLAssetUploadQueue::LLAssetUploadQueue(LLAssetUploadQueueSupplier *supplier) :
- mSupplier(supplier)
-{
-}
-
-//virtual
-LLAssetUploadQueue::~LLAssetUploadQueue()
-{
- delete mSupplier;
-}
-
-// Takes ownership of supplier.
-void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier)
-{
- if (mQueue.empty())
- return;
-
- UploadData data = mQueue.front();
- mQueue.pop_front();
-
- LLSD body;
- body["task_id"] = data.mTaskId;
- body["item_id"] = data.mItemId;
- body["is_script_running"] = data.mIsRunning;
- body["target"] = data.mIsTargetMono? "mono" : "lsl2";
- body["experience"] = data.mExperienceId;
-
- std::string url = "";
- LLViewerObject* object = gObjectList.findObject(data.mTaskId);
- if (object)
- {
- url = object->getRegion()->getCapability("UpdateScriptTask");
- LLHTTPClient::post(url, body,
- new LLAssetUploadChainResponder(
- body, data.mFilename, data.mQueueId,
- data.mData, data.mDataSize, data.mScriptName, *supplier));
- }
-
- *supplier = NULL;
-}
-
-void LLAssetUploadQueue::queue(const std::string& filename,
- const LLUUID& task_id,
- const LLUUID& item_id,
- BOOL is_running,
- BOOL is_target_mono,
- const LLUUID& queue_id,
- U8* script_data,
- U32 data_size,
- std::string script_name,
- const LLUUID& experience_id)
-{
- UploadData data;
- data.mTaskId = task_id;
- data.mItemId = item_id;
- data.mIsRunning = is_running;
- data.mIsTargetMono = is_target_mono;
- data.mQueueId = queue_id;
- data.mFilename = filename;
- data.mData = script_data;
- data.mDataSize = data_size;
- data.mScriptName = script_name;
- data.mExperienceId = experience_id;
-
- mQueue.push_back(data);
-
- if(mSupplier)
- {
- request(&mSupplier);
- }
-}
-
-LLAssetUploadQueueSupplier::~LLAssetUploadQueueSupplier()
-{
-}
diff --git a/indra/newview/llassetuploadqueue.h b/indra/newview/llassetuploadqueue.h
deleted file mode 100755
index 2ceee8f700..0000000000
--- a/indra/newview/llassetuploadqueue.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * @file llassetuploadqueue.h
- * @brief Serializes asset upload request
- *
- * $LicenseInfo:firstyear=2007&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_LLASSETUPLOADQUEUE_H
-#define LL_LLASSETUPLOADQUEUE_H
-
-#include "lluuid.h"
-
-#include <string>
-#include <deque>
-
-class LLAssetUploadQueueSupplier;
-
-class LLAssetUploadQueue
-{
-public:
-
- // Takes ownership of supplier.
- LLAssetUploadQueue(LLAssetUploadQueueSupplier* supplier);
- virtual ~LLAssetUploadQueue();
-
- void queue(const std::string& filename,
- const LLUUID& task_id,
- const LLUUID& item_id,
- BOOL is_running,
- BOOL is_target_mono,
- const LLUUID& queue_id,
- U8* data,
- U32 data_size,
- std::string script_name,
- const LLUUID& experience_id);
-
- bool isEmpty() const {return mQueue.empty();}
-
-private:
-
- friend class LLAssetUploadChainResponder;
-
- struct UploadData
- {
- std::string mFilename;
- LLUUID mTaskId;
- LLUUID mItemId;
- BOOL mIsRunning;
- BOOL mIsTargetMono;
- LLUUID mQueueId;
- U8* mData;
- U32 mDataSize;
- std::string mScriptName;
- LLUUID mExperienceId;
- };
-
- // Ownership of mSupplier passed to currently waiting responder
- // and returned to queue when no requests in progress.
- LLAssetUploadQueueSupplier* mSupplier;
- std::deque<UploadData> mQueue;
-
- // Passes on ownership of mSupplier if request is made.
- void request(LLAssetUploadQueueSupplier** supplier);
-};
-
-class LLAssetUploadQueueSupplier
-{
-public:
- virtual ~LLAssetUploadQueueSupplier();
- virtual LLAssetUploadQueue* get() const = 0;
- virtual void log(std::string message) const = 0;
-};
-
-#endif // LL_LLASSETUPLOADQUEUE_H
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
deleted file mode 100755
index d2b1dcbf35..0000000000
--- a/indra/newview/llassetuploadresponders.cpp
+++ /dev/null
@@ -1,1148 +0,0 @@
-/**
- * @file llassetuploadresponders.cpp
- * @brief Processes responses received for asset upload requests.
- *
- * $LicenseInfo:firstyear=2007&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 "llassetuploadresponders.h"
-
-// viewer includes
-#include "llagent.h"
-#include "llcompilequeue.h"
-#include "llbuycurrencyhtml.h"
-#include "llfilepicker.h"
-#include "llinventorydefines.h"
-#include "llinventoryobserver.h"
-#include "llinventorypanel.h"
-#include "llpermissionsflags.h"
-#include "llpreviewnotecard.h"
-#include "llpreviewscript.h"
-#include "llpreviewgesture.h"
-#include "llgesturemgr.h"
-#include "llstatusbar.h" // sendMoneyBalanceRequest()
-#include "llsdserialize.h"
-#include "lluploaddialog.h"
-#include "llviewerobject.h"
-#include "llviewercontrol.h"
-#include "llviewerobjectlist.h"
-#include "llviewermenufile.h"
-#include "llviewertexlayer.h"
-#include "llviewerwindow.h"
-#include "lltrans.h"
-
-// library includes
-#include "lldir.h"
-#include "lleconomy.h"
-#include "llfloaterreg.h"
-#include "llfocusmgr.h"
-#include "llnotificationsutil.h"
-#include "llscrolllistctrl.h"
-#include "llsdserialize.h"
-#include "llsdutil.h"
-#include "llvfs.h"
-
-void dialog_refresh_all();
-
-void on_new_single_inventory_upload_complete(
- LLAssetType::EType asset_type,
- LLInventoryType::EType inventory_type,
- const std::string inventory_type_string,
- const LLUUID& item_folder_id,
- const std::string& item_name,
- const std::string& item_description,
- const LLSD& server_response,
- S32 upload_price)
-{
- bool success = false;
-
- if ( upload_price > 0 )
- {
- // this upload costed us L$, update our balance
- // and display something saying that it cost L$
- LLStatusBar::sendMoneyBalanceRequest();
-
- LLSD args;
- args["AMOUNT"] = llformat("%d", upload_price);
- LLNotificationsUtil::add("UploadPayment", args);
- }
-
- if( item_folder_id.notNull() )
- {
- U32 everyone_perms = PERM_NONE;
- U32 group_perms = PERM_NONE;
- U32 next_owner_perms = PERM_ALL;
- if( server_response.has("new_next_owner_mask") )
- {
- // The server provided creation perms so use them.
- // Do not assume we got the perms we asked for in
- // since the server may not have granted them all.
- everyone_perms = server_response["new_everyone_mask"].asInteger();
- group_perms = server_response["new_group_mask"].asInteger();
- next_owner_perms = server_response["new_next_owner_mask"].asInteger();
- }
- else
- {
- // The server doesn't provide creation perms
- // so use old assumption-based perms.
- if( inventory_type_string != "snapshot")
- {
- next_owner_perms = PERM_MOVE | PERM_TRANSFER;
- }
- }
-
- LLPermissions new_perms;
- new_perms.init(
- gAgent.getID(),
- gAgent.getID(),
- LLUUID::null,
- LLUUID::null);
-
- new_perms.initMasks(
- PERM_ALL,
- PERM_ALL,
- everyone_perms,
- group_perms,
- next_owner_perms);
-
- U32 inventory_item_flags = 0;
- if (server_response.has("inventory_flags"))
- {
- inventory_item_flags = (U32) server_response["inventory_flags"].asInteger();
- if (inventory_item_flags != 0)
- {
- LL_INFOS() << "inventory_item_flags " << inventory_item_flags << LL_ENDL;
- }
- }
- S32 creation_date_now = time_corrected();
- LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
- server_response["new_inventory_item"].asUUID(),
- item_folder_id,
- new_perms,
- server_response["new_asset"].asUUID(),
- asset_type,
- inventory_type,
- item_name,
- item_description,
- LLSaleInfo::DEFAULT,
- inventory_item_flags,
- creation_date_now);
-
- gInventory.updateItem(item);
- gInventory.notifyObservers();
- success = true;
-
- // Show the preview panel for textures and sounds to let
- // user know that the image (or snapshot) arrived intact.
- LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel();
- if ( panel )
- {
- LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
-
- panel->setSelection(
- server_response["new_inventory_item"].asUUID(),
- TAKE_FOCUS_NO);
-
- // restore keyboard focus
- gFocusMgr.setKeyboardFocus(focus);
- }
- }
- else
- {
- LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL;
- }
-
- // remove the "Uploading..." message
- LLUploadDialog::modalUploadFinished();
-
- // Let the Snapshot floater know we have finished uploading a snapshot to inventory.
- LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
- if (asset_type == LLAssetType::AT_TEXTURE && floater_snapshot)
- {
- floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory")));
- }
-}
-
-LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type)
- : LLHTTPClient::Responder(),
- mPostData(post_data),
- mVFileID(vfile_id),
- mAssetType(asset_type)
-{
- if (!gVFS->getExists(vfile_id, asset_type))
- {
- LL_WARNS() << "LLAssetUploadResponder called with nonexistant vfile_id" << LL_ENDL;
- mVFileID.setNull();
- mAssetType = LLAssetType::AT_NONE;
- return;
- }
-}
-
-LLAssetUploadResponder::LLAssetUploadResponder(
- const LLSD &post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type)
- : LLHTTPClient::Responder(),
- mPostData(post_data),
- mFileName(file_name),
- mAssetType(asset_type)
-{
-}
-
-LLAssetUploadResponder::~LLAssetUploadResponder()
-{
- if (!mFileName.empty())
- {
- // Delete temp file
- LLFile::remove(mFileName);
- }
-}
-
-// virtual
-void LLAssetUploadResponder::httpFailure()
-{
- // *TODO: Add adaptive retry policy?
- LL_WARNS() << dumpResponse() << LL_ENDL;
- std::string reason;
- if (isHttpClientErrorStatus(getStatus()))
- {
- reason = "Error in upload request. Please visit "
- "http://secondlife.com/support for help fixing this problem.";
- }
- else
- {
- reason = "The server is experiencing unexpected "
- "difficulties.";
- }
- LLSD args;
- args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
- args["REASON"] = reason;
- LLNotificationsUtil::add("CannotUploadReason", args);
-
- // unfreeze script preview
- if(mAssetType == LLAssetType::AT_LSL_TEXT)
- {
- LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", mPostData["item_id"]);
- if (preview)
- {
- LLSD errors;
- errors.append(LLTrans::getString("UploadFailed") + reason);
- preview->callbackLSLCompileFailed(errors);
- }
- }
-
- LLUploadDialog::modalUploadFinished();
- LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails
-}
-
-//virtual
-void LLAssetUploadResponder::httpSuccess()
-{
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- LL_DEBUGS() << "LLAssetUploadResponder::result from capabilities" << LL_ENDL;
-
- const std::string& state = content["state"].asStringRef();
-
- if (state == "upload")
- {
- uploadUpload(content);
- }
- else if (state == "complete")
- {
- // rename file in VFS with new asset id
- if (mFileName.empty())
- {
- // rename the file in the VFS to the actual asset id
- // LL_INFOS() << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << LL_ENDL;
- gVFS->renameFile(mVFileID, mAssetType, content["new_asset"].asUUID(), mAssetType);
- }
- uploadComplete(content);
- }
- else
- {
- uploadFailure(content);
- }
-}
-
-void LLAssetUploadResponder::uploadUpload(const LLSD& content)
-{
- const std::string& uploader = content["uploader"].asStringRef();
- if (mFileName.empty())
- {
- LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this);
- }
- else
- {
- LLHTTPClient::postFile(uploader, mFileName, this);
- }
-}
-
-void LLAssetUploadResponder::uploadFailure(const LLSD& content)
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- // unfreeze script preview
- if(mAssetType == LLAssetType::AT_LSL_TEXT)
- {
- LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", mPostData["item_id"]);
- if (preview)
- {
- LLSD errors;
- errors.append(LLTrans::getString("UploadFailed") + content["message"].asString());
- preview->callbackLSLCompileFailed(errors);
- }
- }
-
- // remove the "Uploading..." message
- LLUploadDialog::modalUploadFinished();
-
- LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
- if (floater_snapshot)
- {
- floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory")));
- }
-
- const std::string& reason = content["state"].asStringRef();
- // deal with L$ errors
- if (reason == "insufficient funds")
- {
- S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
- LLStringUtil::format_map_t args;
- args["AMOUNT"] = llformat("%d", price);
- LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("uploading_costs", args), price );
- }
- else
- {
- LLSD args;
- args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName);
- args["REASON"] = content["message"].asString();
- LLNotificationsUtil::add("CannotUploadReason", args);
- }
-}
-
-void LLAssetUploadResponder::uploadComplete(const LLSD& content)
-{
-}
-
-LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
- const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type)
- : LLAssetUploadResponder(post_data, vfile_id, asset_type)
-{
-}
-
-LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
- const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type)
- : LLAssetUploadResponder(post_data, file_name, asset_type)
-{
-}
-
-// virtual
-void LLNewAgentInventoryResponder::httpFailure()
-{
- LLAssetUploadResponder::httpFailure();
- //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);
-}
-
-
-//virtual
-void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
-{
- LLAssetUploadResponder::uploadFailure(content);
-
- //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE);
-}
-
-//virtual
-void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
-{
- LL_DEBUGS() << "LLNewAgentInventoryResponder::result from capabilities" << LL_ENDL;
-
- //std::ostringstream llsdxml;
- //LLSDSerialize::toXML(content, llsdxml);
- //LL_INFOS() << "upload complete content:\n " << llsdxml.str() << LL_ENDL;
-
- LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString());
- LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString());
- S32 expected_upload_cost = 0;
-
- // Update L$ and ownership credit information
- // since it probably changed on the server
- if (asset_type == LLAssetType::AT_TEXTURE ||
- asset_type == LLAssetType::AT_SOUND ||
- asset_type == LLAssetType::AT_ANIMATION ||
- asset_type == LLAssetType::AT_MESH)
- {
- expected_upload_cost =
- LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
- }
-
- on_new_single_inventory_upload_complete(
- asset_type,
- inventory_type,
- mPostData["asset_type"].asString(),
- mPostData["folder_id"].asUUID(),
- mPostData["name"],
- mPostData["description"],
- content,
- expected_upload_cost);
-
- // continue uploading for bulk uploads
-
- // *FIX: This is a pretty big hack. What this does is check the
- // file picker if there are any more pending uploads. If so,
- // upload that file.
- std::string next_file = LLFilePicker::instance().getNextFile();
- if(!next_file.empty())
- {
- std::string name = gDirUtilp->getBaseFileName(next_file, true);
-
- std::string asset_name = name;
- LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
- LLStringUtil::replaceChar(asset_name, '|', '?');
- LLStringUtil::stripNonprintable(asset_name);
- LLStringUtil::trim(asset_name);
-
- // Continuing the horrible hack above, we need to extract the originally requested permissions data, if any,
- // and use them for each next file to be uploaded. Note the requested perms are not the same as the
- U32 everyone_perms =
- content.has("new_everyone_mask") ?
- content["new_everyone_mask"].asInteger() :
- PERM_NONE;
-
- U32 group_perms =
- content.has("new_group_mask") ?
- content["new_group_mask"].asInteger() :
- PERM_NONE;
-
- U32 next_owner_perms =
- content.has("new_next_owner_mask") ?
- content["new_next_owner_mask"].asInteger() :
- PERM_NONE;
-
- std::string display_name = LLStringUtil::null;
- LLAssetStorage::LLStoreAssetCallback callback = NULL;
- void *userdata = NULL;
-
- upload_new_resource(
- next_file,
- asset_name,
- asset_name,
- 0,
- LLFolderType::FT_NONE,
- LLInventoryType::IT_NONE,
- next_owner_perms,
- group_perms,
- everyone_perms,
- display_name,
- callback,
- LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(),
- userdata);
- }
-
- //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);
-}
-
-LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
- const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type)
- : LLAssetUploadResponder(post_data, vfile_id, asset_type)
-{
-}
-
-LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
- const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type)
- : LLAssetUploadResponder(post_data, file_name, asset_type)
-{
-}
-
-//virtual
-void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content)
-{
- LL_INFOS() << "LLUpdateAgentInventoryResponder::result from capabilities" << LL_ENDL;
- LLUUID item_id = mPostData["item_id"];
-
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(item_id);
- if(!item)
- {
- LL_WARNS() << "Inventory item for " << mVFileID
- << " is no longer in agent inventory." << LL_ENDL;
- return;
- }
-
- // Update viewer inventory item
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->setAssetUUID(content["new_asset"].asUUID());
- gInventory.updateItem(new_item);
- gInventory.notifyObservers();
-
- LL_INFOS() << "Inventory item " << item->getName() << " saved into "
- << content["new_asset"].asString() << LL_ENDL;
-
- LLInventoryType::EType inventory_type = new_item->getInventoryType();
- switch(inventory_type)
- {
- case LLInventoryType::IT_NOTECARD:
- {
- // Update the UI with the new asset.
- LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(item_id));
- if(nc)
- {
- // *HACK: we have to delete the asset in the VFS so
- // that the viewer will redownload it. This is only
- // really necessary if the asset had to be modified by
- // the uploader, so this can be optimized away in some
- // cases. A better design is to have a new uuid if the
- // script actually changed the asset.
- if(nc->hasEmbeddedInventory())
- {
- gVFS->removeFile(content["new_asset"].asUUID(), LLAssetType::AT_NOTECARD);
- }
- nc->refreshFromInventory(new_item->getUUID());
- }
- break;
- }
- case LLInventoryType::IT_LSL:
- {
- // Find our window and close it if requested.
- LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", LLSD(item_id));
- if (preview)
- {
- // Bytecode save completed
- if (content["compiled"])
- {
- preview->callbackLSLCompileSucceeded();
- }
- else
- {
- preview->callbackLSLCompileFailed(content["errors"]);
- }
- }
- break;
- }
-
- case LLInventoryType::IT_GESTURE:
- {
- // If this gesture is active, then we need to update the in-memory
- // active map with the new pointer.
- if (LLGestureMgr::instance().isGestureActive(item_id))
- {
- LLUUID asset_id = new_item->getAssetUUID();
- LLGestureMgr::instance().replaceGesture(item_id, asset_id);
- gInventory.notifyObservers();
- }
-
- //gesture will have a new asset_id
- LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id));
- if(previewp)
- {
- previewp->onUpdateSucceeded();
- }
-
- break;
- }
- case LLInventoryType::IT_WEARABLE:
- default:
- break;
- }
-}
-
-
-LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, vfile_id, asset_type)
-{
-}
-
-LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, file_name, asset_type)
-{
-}
-
-LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data,
- const std::string& file_name,
- const LLUUID& queue_id,
- LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, file_name, asset_type), mQueueId(queue_id)
-{
-}
-
-//virtual
-void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
-{
- LL_INFOS() << "LLUpdateTaskInventoryResponder::result from capabilities" << LL_ENDL;
- LLUUID item_id = mPostData["item_id"];
- LLUUID task_id = mPostData["task_id"];
-
- dialog_refresh_all();
-
- switch(mAssetType)
- {
- case LLAssetType::AT_NOTECARD:
- {
- // Update the UI with the new asset.
- LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(item_id));
- if(nc)
- {
- // *HACK: we have to delete the asset in the VFS so
- // that the viewer will redownload it. This is only
- // really necessary if the asset had to be modified by
- // the uploader, so this can be optimized away in some
- // cases. A better design is to have a new uuid if the
- // script actually changed the asset.
- if(nc->hasEmbeddedInventory())
- {
- gVFS->removeFile(content["new_asset"].asUUID(),
- LLAssetType::AT_NOTECARD);
- }
- nc->setAssetId(content["new_asset"].asUUID());
- nc->refreshFromInventory();
- }
- break;
- }
- case LLAssetType::AT_LSL_TEXT:
- {
- if(mQueueId.notNull())
- {
- LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", mQueueId);
- if(NULL != queue)
- {
- queue->removeItemByItemID(item_id);
- }
- }
- else
- {
- LLSD floater_key;
- floater_key["taskid"] = task_id;
- floater_key["itemid"] = item_id;
- LLLiveLSLEditor* preview = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", floater_key);
- if (preview)
- {
- // Bytecode save completed
- if (content["compiled"])
- {
- preview->callbackLSLCompileSucceeded(task_id, item_id, mPostData["is_script_running"]);
- }
- else
- {
- preview->callbackLSLCompileFailed(content["errors"]);
- }
- }
- }
- break;
- }
- default:
- break;
- }
-}
-
-
-/////////////////////////////////////////////////////
-// LLNewAgentInventoryVariablePriceResponder::Impl //
-/////////////////////////////////////////////////////
-class LLNewAgentInventoryVariablePriceResponder::Impl
-{
-public:
- Impl(
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type,
- const LLSD& inventory_data) :
- mVFileID(vfile_id),
- mAssetType(asset_type),
- mInventoryData(inventory_data),
- mFileName("")
- {
- if (!gVFS->getExists(vfile_id, asset_type))
- {
- LL_WARNS()
- << "LLAssetUploadResponder called with nonexistant "
- << "vfile_id " << vfile_id << LL_ENDL;
- mVFileID.setNull();
- mAssetType = LLAssetType::AT_NONE;
- }
- }
-
- Impl(
- const std::string& file_name,
- LLAssetType::EType asset_type,
- const LLSD& inventory_data) :
- mFileName(file_name),
- mAssetType(asset_type),
- mInventoryData(inventory_data)
- {
- mVFileID.setNull();
- }
-
- std::string getFilenameOrIDString() const
- {
- return (mFileName.empty() ? mVFileID.asString() : mFileName);
- }
-
- LLUUID getVFileID() const
- {
- return mVFileID;
- }
-
- std::string getFilename() const
- {
- return mFileName;
- }
-
- LLAssetType::EType getAssetType() const
- {
- return mAssetType;
- }
-
- LLInventoryType::EType getInventoryType() const
- {
- return LLInventoryType::lookup(
- mInventoryData["inventory_type"].asString());
- }
-
- std::string getInventoryTypeString() const
- {
- return mInventoryData["inventory_type"].asString();
- }
-
- LLUUID getFolderID() const
- {
- return mInventoryData["folder_id"].asUUID();
- }
-
- std::string getItemName() const
- {
- return mInventoryData["name"].asString();
- }
-
- std::string getItemDescription() const
- {
- return mInventoryData["description"].asString();
- }
-
- void displayCannotUploadReason(const std::string& reason)
- {
- LLSD args;
- args["FILE"] = getFilenameOrIDString();
- args["REASON"] = reason;
-
-
- LLNotificationsUtil::add("CannotUploadReason", args);
- LLUploadDialog::modalUploadFinished();
- }
-
- void onApplicationLevelError(const LLSD& error)
- {
- static const std::string _IDENTIFIER = "identifier";
-
- static const std::string _INSUFFICIENT_FUNDS =
- "NewAgentInventory_InsufficientLindenDollarBalance";
- static const std::string _MISSING_REQUIRED_PARAMETER =
- "NewAgentInventory_MissingRequiredParamater";
- static const std::string _INVALID_REQUEST_BODY =
- "NewAgentInventory_InvalidRequestBody";
- static const std::string _RESOURCE_COST_DIFFERS =
- "NewAgentInventory_ResourceCostDiffers";
-
- static const std::string _MISSING_PARAMETER = "missing_parameter";
- static const std::string _INVALID_PARAMETER = "invalid_parameter";
- static const std::string _MISSING_RESOURCE = "missing_resource";
- static const std::string _INVALID_RESOURCE = "invalid_resource";
-
- // TODO* Add the other error_identifiers
-
- std::string error_identifier = error[_IDENTIFIER].asString();
-
- // TODO*: Pull these user visible strings from an xml file
- // to be localized
- if ( _INSUFFICIENT_FUNDS == error_identifier )
- {
- displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload.");
- }
- else if ( _MISSING_REQUIRED_PARAMETER == error_identifier )
- {
- // Missing parameters
- if (error.has(_MISSING_PARAMETER) )
- {
- std::string message =
- "Upload request was missing required parameter '[P]'";
- LLStringUtil::replaceString(
- message,
- "[P]",
- error[_MISSING_PARAMETER].asString());
-
- displayCannotUploadReason(message);
- }
- else
- {
- std::string message =
- "Upload request was missing a required parameter";
- displayCannotUploadReason(message);
- }
- }
- else if ( _INVALID_REQUEST_BODY == error_identifier )
- {
- // Invalid request body, check to see if
- // a particular parameter was invalid
- if ( error.has(_INVALID_PARAMETER) )
- {
- std::string message = "Upload parameter '[P]' is invalid.";
- LLStringUtil::replaceString(
- message,
- "[P]",
- error[_INVALID_PARAMETER].asString());
-
- // See if the server also responds with what resource
- // is missing.
- if ( error.has(_MISSING_RESOURCE) )
- {
- message += "\nMissing resource '[R]'.";
-
- LLStringUtil::replaceString(
- message,
- "[R]",
- error[_MISSING_RESOURCE].asString());
- }
- else if ( error.has(_INVALID_RESOURCE) )
- {
- message += "\nInvalid resource '[R]'.";
-
- LLStringUtil::replaceString(
- message,
- "[R]",
- error[_INVALID_RESOURCE].asString());
- }
-
- displayCannotUploadReason(message);
- }
- else
- {
- std::string message = "Upload request was malformed";
- displayCannotUploadReason(message);
- }
- }
- else if ( _RESOURCE_COST_DIFFERS == error_identifier )
- {
- displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server.");
- }
- else
- {
- displayCannotUploadReason("Unknown Error");
- }
- }
-
- void onTransportError()
- {
- displayCannotUploadReason(
- "The server is experiencing unexpected difficulties.");
- }
-
- void onTransportError(const LLSD& error)
- {
- static const std::string _IDENTIFIER = "identifier";
-
- static const std::string _SERVER_ERROR_AFTER_CHARGE =
- "NewAgentInventory_ServerErrorAfterCharge";
-
- std::string error_identifier = error[_IDENTIFIER].asString();
-
- // TODO*: Pull the user visible strings from an xml file
- // to be localized
-
- if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier )
- {
- displayCannotUploadReason(
- "The server is experiencing unexpected difficulties. You may have been charged for the upload.");
- }
- else
- {
- displayCannotUploadReason(
- "The server is experiencing unexpected difficulties.");
- }
- }
-
- bool uploadConfirmationCallback(
- const LLSD& notification,
- const LLSD& response,
- LLPointer<LLNewAgentInventoryVariablePriceResponder> responder)
- {
- S32 option;
- std::string confirmation_url;
-
- option = LLNotificationsUtil::getSelectedOption(
- notification,
- response);
-
- confirmation_url =
- notification["payload"]["confirmation_url"].asString();
-
- // Yay! We are confirming or cancelling our upload
- switch(option)
- {
- case 0:
- {
- confirmUpload(confirmation_url, responder);
- }
- break;
- case 1:
- default:
- break;
- }
-
- return false;
- }
-
- void confirmUpload(
- const std::string& confirmation_url,
- LLPointer<LLNewAgentInventoryVariablePriceResponder> responder)
- {
- if ( getFilename().empty() )
- {
- // we have no filename, use virtual file ID instead
- LLHTTPClient::postFile(
- confirmation_url,
- getVFileID(),
- getAssetType(),
- responder);
- }
- else
- {
- LLHTTPClient::postFile(
- confirmation_url,
- getFilename(),
- responder);
- }
- }
-
-
-private:
- std::string mFileName;
-
- LLSD mInventoryData;
- LLAssetType::EType mAssetType;
- LLUUID mVFileID;
-};
-
-///////////////////////////////////////////////
-// LLNewAgentInventoryVariablePriceResponder //
-///////////////////////////////////////////////
-LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type,
- const LLSD& inventory_info)
-{
- mImpl = new Impl(
- vfile_id,
- asset_type,
- inventory_info);
-}
-
-LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
- const std::string& file_name,
- LLAssetType::EType asset_type,
- const LLSD& inventory_info)
-{
- mImpl = new Impl(
- file_name,
- asset_type,
- inventory_info);
-}
-
-LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder()
-{
- delete mImpl;
-}
-
-void LLNewAgentInventoryVariablePriceResponder::httpFailure()
-{
- const LLSD& content = getContent();
- LL_WARNS("Upload") << dumpResponse() << LL_ENDL;
-
- static const std::string _ERROR = "error";
- if ( content.has(_ERROR) )
- {
- mImpl->onTransportError(content[_ERROR]);
- }
- else
- {
- mImpl->onTransportError();
- }
-}
-
-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";
- static const std::string _STATE = "state";
-
- static const std::string _COMPLETE = "complete";
- static const std::string _CONFIRM_UPLOAD = "confirm_upload";
-
- static const std::string _UPLOAD_PRICE = "upload_price";
- static const std::string _RESOURCE_COST = "resource_cost";
- static const std::string _RSVP = "rsvp";
-
- // Check for application level errors
- if ( content.has(_ERROR) )
- {
- LL_WARNS("Upload") << dumpResponse() << LL_ENDL;
- onApplicationLevelError(content[_ERROR]);
- return;
- }
-
- std::string state = content[_STATE];
- LLAssetType::EType asset_type = mImpl->getAssetType();
-
- if ( _COMPLETE == state )
- {
- // rename file in VFS with new asset id
- if (mImpl->getFilename().empty())
- {
- // rename the file in the VFS to the actual asset id
- // LL_INFOS() << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << LL_ENDL;
- gVFS->renameFile(
- mImpl->getVFileID(),
- asset_type,
- content["new_asset"].asUUID(),
- asset_type);
- }
-
- on_new_single_inventory_upload_complete(
- asset_type,
- mImpl->getInventoryType(),
- mImpl->getInventoryTypeString(),
- mImpl->getFolderID(),
- mImpl->getItemName(),
- mImpl->getItemDescription(),
- content,
- content[_UPLOAD_PRICE].asInteger());
-
- // TODO* Add bulk (serial) uploading or add
- // a super class of this that does so
- }
- else if ( _CONFIRM_UPLOAD == state )
- {
- showConfirmationDialog(
- content[_UPLOAD_PRICE].asInteger(),
- content[_RESOURCE_COST].asInteger(),
- content[_RSVP].asString());
- }
- else
- {
- LL_WARNS("Upload") << dumpResponse() << LL_ENDL;
- onApplicationLevelError("");
- }
-}
-
-void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError(
- const LLSD& error)
-{
- mImpl->onApplicationLevelError(error);
-}
-
-void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(
- S32 upload_price,
- S32 resource_cost,
- const std::string& confirmation_url)
-{
- if ( 0 == upload_price )
- {
- // don't show confirmation dialog for free uploads, I mean,
- // they're free!
-
- // The creating of a new instrusive_ptr(this)
- // creates a new boost::intrusive_ptr
- // which is a copy of this. This code is required because
- // 'this' is always of type Class* and not the intrusive_ptr,
- // and thus, a reference to 'this' is not registered
- // by using just plain 'this'.
-
- // Since LLNewAgentInventoryVariablePriceResponder is a
- // reference counted class, it is possible (since the
- // reference to a plain 'this' would be missed here) that,
- // when using plain ol' 'this', that this object
- // would be deleted before the callback is triggered
- // and cause sadness.
- mImpl->confirmUpload(
- confirmation_url,
- LLPointer<LLNewAgentInventoryVariablePriceResponder>(this));
- }
- else
- {
- LLSD substitutions;
- LLSD payload;
-
- substitutions["PRICE"] = upload_price;
-
- payload["confirmation_url"] = confirmation_url;
-
- // The creating of a new instrusive_ptr(this)
- // creates a new boost::intrusive_ptr
- // which is a copy of this. This code is required because
- // 'this' is always of type Class* and not the intrusive_ptr,
- // and thus, a reference to 'this' is not registered
- // by using just plain 'this'.
-
- // Since LLNewAgentInventoryVariablePriceResponder is a
- // reference counted class, it is possible (since the
- // reference to a plain 'this' would be missed here) that,
- // when using plain ol' 'this', that this object
- // would be deleted before the callback is triggered
- // and cause sadness.
- LLNotificationsUtil::add(
- "UploadCostConfirmation",
- substitutions,
- payload,
- boost::bind(
- &LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback,
- mImpl,
- _1,
- _2,
- LLPointer<LLNewAgentInventoryVariablePriceResponder>(this)));
- }
-}
-
-
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
deleted file mode 100755
index 7fbebc7481..0000000000
--- a/indra/newview/llassetuploadresponders.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/**
- * @file llassetuploadresponders.h
- * @brief Processes responses received for asset upload requests.
- *
- * $LicenseInfo:firstyear=2007&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_LLASSETUPLOADRESPONDER_H
-#define LL_LLASSETUPLOADRESPONDER_H
-
-#include "llhttpclient.h"
-
-// Abstract class for supporting asset upload
-// via capabilities
-class LLAssetUploadResponder : public LLHTTPClient::Responder
-{
-protected:
- LOG_CLASS(LLAssetUploadResponder);
-public:
- LLAssetUploadResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type);
- LLAssetUploadResponder(const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type);
- ~LLAssetUploadResponder();
-
-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);
-
-protected:
- LLSD mPostData;
- LLAssetType::EType mAssetType;
- LLUUID mVFileID;
- std::string mFileName;
-};
-
-// TODO*: Remove this once deprecated
-class LLNewAgentInventoryResponder : public LLAssetUploadResponder
-{
- LOG_CLASS(LLNewAgentInventoryResponder);
-public:
- LLNewAgentInventoryResponder(
- const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type);
- LLNewAgentInventoryResponder(
- const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type);
- 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
-// actions for variable price uploads. If more specific actions
-// are needed (such as different confirmation messages, etc.)
-// the functions onApplicationLevelError and showConfirmationDialog.
-class LLNewAgentInventoryVariablePriceResponder :
- public LLHTTPClient::Responder
-{
- LOG_CLASS(LLNewAgentInventoryVariablePriceResponder);
-public:
- LLNewAgentInventoryVariablePriceResponder(
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type,
- const LLSD& inventory_info);
-
- LLNewAgentInventoryVariablePriceResponder(
- const std::string& file_name,
- LLAssetType::EType asset_type,
- const LLSD& inventory_info);
- virtual ~LLNewAgentInventoryVariablePriceResponder();
-
-private:
- /* virtual */ void httpFailure();
- /* virtual */ void httpSuccess();
-
-public:
- virtual void onApplicationLevelError(
- const LLSD& error);
- virtual void showConfirmationDialog(
- S32 upload_price,
- S32 resource_cost,
- const std::string& confirmation_url);
-
-private:
- class Impl;
- Impl* mImpl;
-};
-
-class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder
-{
-public:
- LLUpdateAgentInventoryResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type);
- LLUpdateAgentInventoryResponder(const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type);
- virtual void uploadComplete(const LLSD& content);
-};
-
-class LLUpdateTaskInventoryResponder : public LLAssetUploadResponder
-{
-public:
- LLUpdateTaskInventoryResponder(const LLSD& post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type);
- LLUpdateTaskInventoryResponder(const LLSD& post_data,
- const std::string& file_name,
- LLAssetType::EType asset_type);
- LLUpdateTaskInventoryResponder(const LLSD& post_data,
- const std::string& file_name,
- const LLUUID& queue_id,
- LLAssetType::EType asset_type);
-
- virtual void uploadComplete(const LLSD& content);
-
-private:
- LLUUID mQueueId;
-};
-
-#endif // LL_LLASSETUPLOADRESPONDER_H
diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp
index 38e153137c..470f516db2 100644
--- a/indra/newview/llavatarrenderinfoaccountant.cpp
+++ b/indra/newview/llavatarrenderinfoaccountant.cpp
@@ -35,7 +35,6 @@
// external library headers
// other Linden headers
#include "llcharacter.h"
-#include "llhttpclient.h"
#include "lltimer.h"
#include "llviewercontrol.h"
#include "llviewermenu.h"
@@ -43,7 +42,10 @@
#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llworld.h"
-
+#include "llhttpsdhandler.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
+#include "llcorehttputil.h"
static const std::string KEY_AGENTS = "agents"; // map
static const std::string KEY_WEIGHT = "weight"; // integer
@@ -55,166 +57,178 @@ static const std::string KEY_ERROR = "error";
// Send data updates about once per minute, only need per-frame resolution
LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer;
+//LLCore::HttpRequest::ptr_t LLAvatarRenderInfoAccountant::sHttpRequest;
-
-// HTTP responder class for GET request for avatar render weight information
-class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder
+//=========================================================================
+void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64 regionHandle)
{
-public:
- LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle)
- {
- }
-
- virtual void error(U32 statusNum, const std::string& reason)
- {
- LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if (regionp)
- {
- LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum
- << ", " << reason
- << " returned by region " << regionp->getName()
- << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Avatar render weight GET error recieved but region not found for "
- << mRegionHandle
- << ", error " << statusNum
- << ", " << reason
- << LL_ENDL;
- }
-
- }
-
- virtual void result(const LLSD& content)
- {
- LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if (regionp)
- {
- if (LLAvatarRenderInfoAccountant::logRenderInfo())
- {
- LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL;
- }
-
- if (content.isMap())
- {
- if (content.has(KEY_AGENTS))
- {
- const LLSD & agents = content[KEY_AGENTS];
- if (agents.isMap())
- {
- LLSD::map_const_iterator report_iter = agents.beginMap();
- while (report_iter != agents.endMap())
- {
- LLUUID target_agent_id = LLUUID(report_iter->first);
- const LLSD & agent_info_map = report_iter->second;
- LLViewerObject* avatarp = gObjectList.findObject(target_agent_id);
- if (avatarp &&
- avatarp->isAvatar() &&
- agent_info_map.isMap())
- { // Extract the data for this avatar
-
- if (LLAvatarRenderInfoAccountant::logRenderInfo())
- {
- LL_INFOS() << "LRI: Agent " << target_agent_id
- << ": " << agent_info_map << LL_ENDL;
- }
-
- if (agent_info_map.has(KEY_WEIGHT))
- {
- ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger());
- }
- }
- report_iter++;
- }
- }
- } // has "agents"
- else if (content.has(KEY_ERROR))
- {
- const LLSD & error = content[KEY_ERROR];
- LL_WARNS() << "Avatar render info GET error: "
- << error[KEY_IDENTIFIER]
- << ": " << error[KEY_MESSAGE]
- << " from region " << regionp->getName()
- << LL_ENDL;
- }
- }
- }
- else
- {
- LL_INFOS() << "Avatar render weight info recieved but region not found for "
- << mRegionHandle << LL_ENDL;
- }
- }
-
-private:
- U64 mRegionHandle;
-};
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp)
+ {
+ LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for "
+ << regionHandle << LL_ENDL;
+ return;
+ }
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("AvatarRenderInfoAccountant") << "HTTP status, " << status.toTerseString() << LL_ENDL;
+ return;
+ }
+
+ if (result.has(KEY_AGENTS))
+ {
+ const LLSD & agents = result[KEY_AGENTS];
+ if (agents.isMap())
+ {
+ LLSD::map_const_iterator report_iter = agents.beginMap();
+ while (report_iter != agents.endMap())
+ {
+ LLUUID target_agent_id = LLUUID(report_iter->first);
+ const LLSD & agent_info_map = report_iter->second;
+ LLViewerObject* avatarp = gObjectList.findObject(target_agent_id);
+ if (avatarp &&
+ avatarp->isAvatar() &&
+ agent_info_map.isMap())
+ { // Extract the data for this avatar
+
+ if (LLAvatarRenderInfoAccountant::logRenderInfo())
+ {
+ LL_INFOS() << "LRI: Agent " << target_agent_id
+ << ": " << agent_info_map << LL_ENDL;
+ }
+
+ if (agent_info_map.has(KEY_WEIGHT))
+ {
+ ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger());
+ }
+ }
+ report_iter++;
+ }
+ }
+ } // has "agents"
+ else if (result.has(KEY_ERROR))
+ {
+ const LLSD & error = result[KEY_ERROR];
+ LL_WARNS() << "Avatar render info GET error: "
+ << error[KEY_IDENTIFIER]
+ << ": " << error[KEY_MESSAGE]
+ << " from region " << regionp->getName()
+ << LL_ENDL;
+ }
+}
-// HTTP responder class for POST request for avatar render weight information
-class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder
+//-------------------------------------------------------------------------
+void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U64 regionHandle)
{
-public:
- LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle)
- {
- }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp)
+ {
+ LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but region not found for "
+ << regionHandle << LL_ENDL;
+ return;
+ }
+
+ if (logRenderInfo())
+ {
+ LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Sending avatar render info to region " << regionp->getName()
+ << " from " << url << LL_ENDL;
+ }
+
+ // Build the render info to POST to the region
+ LLSD report = LLSD::emptyMap();
+ LLSD agents = LLSD::emptyMap();
+
+ std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ while( iter != LLCharacter::sInstances.end() )
+ {
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter);
+ if (avatar &&
+ avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded)
+ !avatar->isDead() && // Not dead yet
+ avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region
+ {
+ avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date
+
+ LLSD info = LLSD::emptyMap();
+ if (avatar->getVisualComplexity() > 0)
+ {
+ info[KEY_WEIGHT] = avatar->getVisualComplexity();
+ agents[avatar->getID().asString()] = info;
+
+ if (logRenderInfo())
+ {
+ LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Sending avatar render info for " << avatar->getID()
+ << ": " << info << LL_ENDL;
+ LL_INFOS("AvatarRenderInfoAccountant") << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes()
+ << ", area " << avatar->getAttachmentSurfaceArea()
+ << LL_ENDL;
+ }
+ }
+ }
+ iter++;
+ }
+
+ if (agents.size() == 0)
+ return;
+
+ report[KEY_AGENTS] = agents;
+ regionp = NULL;
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, report);
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp)
+ {
+ LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for "
+ << regionHandle << LL_ENDL;
+ return;
+ }
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AvatarRenderInfoAccountant") << "HTTP status, " << status.toTerseString() << LL_ENDL;
+ return;
+ }
+
+ if (LLAvatarRenderInfoAccountant::logRenderInfo())
+ {
+ LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Result for avatar weights POST for region " << regionp->getName()
+ << ": " << result << LL_ENDL;
+ }
+
+ if (result.isMap())
+ {
+ if (result.has(KEY_ERROR))
+ {
+ const LLSD & error = result[KEY_ERROR];
+ LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render info POST error: "
+ << error[KEY_IDENTIFIER]
+ << ": " << error[KEY_MESSAGE]
+ << " from region " << regionp->getName()
+ << LL_ENDL;
+ }
+ }
- virtual void error(U32 statusNum, const std::string& reason)
- {
- LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if (regionp)
- {
- LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum
- << ", " << reason
- << " returned by region " << regionp->getName()
- << LL_ENDL;
- }
- else
- {
- LL_WARNS() << "Avatar render weight POST error recieved but region not found for "
- << mRegionHandle
- << ", error " << statusNum
- << ", " << reason
- << LL_ENDL;
- }
- }
-
- virtual void result(const LLSD& content)
- {
- LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if (regionp)
- {
- if (LLAvatarRenderInfoAccountant::logRenderInfo())
- {
- LL_INFOS() << "LRI: Result for avatar weights POST for region " << regionp->getName()
- << ": " << content << LL_ENDL;
- }
-
- if (content.isMap())
- {
- if (content.has(KEY_ERROR))
- {
- const LLSD & error = content[KEY_ERROR];
- LL_WARNS() << "Avatar render info POST error: "
- << error[KEY_IDENTIFIER]
- << ": " << error[KEY_MESSAGE]
- << " from region " << regionp->getName()
- << LL_ENDL;
- }
- }
- }
- else
- {
- LL_INFOS() << "Avatar render weight POST result recieved but region not found for "
- << mRegionHandle << LL_ENDL;
- }
- }
-
-private:
- U64 mRegionHandle;
-};
+}
// static
// Send request for one region, no timer checks
@@ -223,53 +237,9 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio
std::string url = regionp->getCapability("AvatarRenderInfo");
if (!url.empty())
{
- if (logRenderInfo())
- {
- LL_INFOS() << "LRI: Sending avatar render info to region "
- << regionp->getName()
- << " from " << url
- << LL_ENDL;
- }
-
- // Build the render info to POST to the region
- LLSD report = LLSD::emptyMap();
- LLSD agents = LLSD::emptyMap();
-
- std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- while( iter != LLCharacter::sInstances.end() )
- {
- LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter);
- if (avatar &&
- avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded)
- !avatar->isDead() && // Not dead yet
- avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region
- {
- avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date
-
- LLSD info = LLSD::emptyMap();
- if (avatar->getVisualComplexity() > 0)
- {
- info[KEY_WEIGHT] = avatar->getVisualComplexity();
- agents[avatar->getID().asString()] = info;
-
- if (logRenderInfo())
- {
- LL_INFOS() << "LRI: Sending avatar render info for " << avatar->getID()
- << ": " << info << LL_ENDL;
- LL_INFOS() << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes()
- << ", area " << avatar->getAttachmentSurfaceArea()
- << LL_ENDL;
- }
- }
- }
- iter++;
- }
-
- report[KEY_AGENTS] = agents;
- if (agents.size() > 0)
- {
- LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle()));
- }
+ std::string coroname =
+ LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro",
+ boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro, url, regionp->getHandle()));
}
}
@@ -292,7 +262,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi
}
// First send a request to get the latest data
- LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle()));
+ std::string coroname =
+ LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro",
+ boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro, url, regionp->getHandle()));
}
}
@@ -301,6 +273,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi
// Called every frame - send render weight requests to every region
void LLAvatarRenderInfoAccountant::idle()
{
+// if (!LLAvatarRenderInfoAccountant::sHttpRequest)
+// sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+
if (sRenderInfoReportTimer.hasExpired())
{
const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds
@@ -393,6 +368,7 @@ void LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer(const LLUUID& reg
// static
bool LLAvatarRenderInfoAccountant::logRenderInfo()
{
- static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false);
- return render_mute_logging_enabled;
+ return true;
+// static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false);
+// return render_mute_logging_enabled;
}
diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h
index d68f2dccfb..f7a04cca2c 100644
--- a/indra/newview/llavatarrenderinfoaccountant.h
+++ b/indra/newview/llavatarrenderinfoaccountant.h
@@ -29,6 +29,9 @@
#if ! defined(LL_llavatarrenderinfoaccountant_H)
#define LL_llavatarrenderinfoaccountant_H
+#include "httpcommon.h"
+#include "llcoros.h"
+
class LLViewerRegion;
// Class to gather avatar rendering information
@@ -36,8 +39,6 @@ class LLViewerRegion;
class LLAvatarRenderInfoAccountant
{
public:
- LLAvatarRenderInfoAccountant() {};
- ~LLAvatarRenderInfoAccountant() {};
static void sendRenderInfoToRegion(LLViewerRegion * regionp);
static void getRenderInfoFromRegion(LLViewerRegion * regionp);
@@ -49,8 +50,16 @@ public:
static bool logRenderInfo();
private:
+ LLAvatarRenderInfoAccountant() {};
+ ~LLAvatarRenderInfoAccountant() {};
+
// Send data updates about once per minute, only need per-frame resolution
static LLFrameTimer sRenderInfoReportTimer;
+
+ static void avatarRenderInfoGetCoro(std::string url, U64 regionHandle);
+ static void avatarRenderInfoReportCoro(std::string url, U64 regionHandle);
+
+
};
#endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */
diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp
deleted file mode 100755
index ef9b910ae5..0000000000
--- a/indra/newview/llcapabilitylistener.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/**
- * @file llcapabilitylistener.cpp
- * @author Nat Goodspeed
- * @date 2009-01-07
- * @brief Implementation for llcapabilitylistener.
- *
- * $LicenseInfo:firstyear=2009&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$
- */
-
-// Precompiled header
-#include "llviewerprecompiledheaders.h"
-// associated header
-#include "llcapabilitylistener.h"
-// STL headers
-#include <map>
-// std headers
-// external library headers
-#include <boost/bind.hpp>
-// other Linden headers
-#include "stringize.h"
-#include "llcapabilityprovider.h"
-#include "message.h"
-
-class LLCapabilityListener::CapabilityMappers: public LLSingleton<LLCapabilityListener::CapabilityMappers>
-{
-public:
- void registerMapper(const LLCapabilityListener::CapabilityMapper*);
- void unregisterMapper(const LLCapabilityListener::CapabilityMapper*);
- const LLCapabilityListener::CapabilityMapper* find(const std::string& cap) const;
-
- struct DupCapMapper: public std::runtime_error
- {
- DupCapMapper(const std::string& what):
- std::runtime_error(std::string("DupCapMapper: ") + what)
- {}
- };
-
-private:
- friend class LLSingleton<LLCapabilityListener::CapabilityMappers>;
- CapabilityMappers();
-
- typedef std::map<std::string, const LLCapabilityListener::CapabilityMapper*> CapabilityMap;
- CapabilityMap mMap;
-};
-
-LLCapabilityListener::LLCapabilityListener(const std::string& name,
- LLMessageSystem* messageSystem,
- const LLCapabilityProvider& provider,
- const LLUUID& agentID,
- const LLUUID& sessionID):
- mEventPump(name),
- mMessageSystem(messageSystem),
- mProvider(provider),
- mAgentID(agentID),
- mSessionID(sessionID)
-{
- mEventPump.listen("self", boost::bind(&LLCapabilityListener::capListener, this, _1));
-}
-
-bool LLCapabilityListener::capListener(const LLSD& request)
-{
- // Extract what we want from the request object. We do it all up front
- // partly to document what we expect.
- LLSD::String cap(request["message"]);
- LLSD payload(request["payload"]);
- LLSD::String reply(request["reply"]);
- LLSD::String error(request["error"]);
- LLSD::Real timeout(request["timeout"]);
- // If the LLSD doesn't even have a "message" key, we doubt it was intended
- // for this listener.
- if (cap.empty())
- {
- LL_ERRS("capListener") << "capability request event without 'message' key to '"
- << getCapAPI().getName()
- << "' on region\n" << mProvider.getDescription()
- << LL_ENDL;
- return false; // in case fatal-error function isn't
- }
- // Establish default timeout. This test relies on LLSD::asReal() returning
- // exactly 0.0 for an undef value.
- if (! timeout)
- {
- timeout = HTTP_REQUEST_EXPIRY_SECS;
- }
- // Look up the url for the requested capability name.
- std::string url = mProvider.getCapability(cap);
- if (! url.empty())
- {
- // This capability is supported by the region to which we're talking.
- LLHTTPClient::post(url, payload,
- new LLSDMessage::EventResponder(LLEventPumps::instance(),
- request,
- mProvider.getDescription(),
- cap, reply, error),
- LLSD(), // headers
- timeout);
- }
- else
- {
- // Capability not supported -- do we have a registered mapper?
- const CapabilityMapper* mapper = CapabilityMappers::instance().find(cap);
- if (! mapper) // capability neither supported nor mapped
- {
- LL_ERRS("capListener") << "unsupported capability '" << cap << "' request to '"
- << getCapAPI().getName() << "' on region\n"
- << mProvider.getDescription()
- << LL_ENDL;
- }
- else if (! mapper->getReplyName().empty()) // mapper expects reply support
- {
- LL_ERRS("capListener") << "Mapper for capability '" << cap
- << "' requires unimplemented support for reply message '"
- << mapper->getReplyName()
- << "' on '" << getCapAPI().getName() << "' on region\n"
- << mProvider.getDescription()
- << LL_ENDL;
- }
- else
- {
- LL_INFOS("capListener") << "fallback invoked for capability '" << cap
- << "' request to '" << getCapAPI().getName()
- << "' on region\n" << mProvider.getDescription()
- << LL_ENDL;
- mapper->buildMessage(mMessageSystem, mAgentID, mSessionID, cap, payload);
- mMessageSystem->sendReliable(mProvider.getHost());
- }
- }
- return false;
-}
-
-LLCapabilityListener::CapabilityMapper::CapabilityMapper(const std::string& cap, const std::string& reply):
- mCapName(cap),
- mReplyName(reply)
-{
- LLCapabilityListener::CapabilityMappers::instance().registerMapper(this);
-}
-
-LLCapabilityListener::CapabilityMapper::~CapabilityMapper()
-{
- LLCapabilityListener::CapabilityMappers::instance().unregisterMapper(this);
-}
-
-LLSD LLCapabilityListener::CapabilityMapper::readResponse(LLMessageSystem* messageSystem) const
-{
- return LLSD();
-}
-
-LLCapabilityListener::CapabilityMappers::CapabilityMappers() {}
-
-void LLCapabilityListener::CapabilityMappers::registerMapper(const LLCapabilityListener::CapabilityMapper* mapper)
-{
- // Try to insert a new map entry by which we can look up the passed mapper
- // instance.
- std::pair<CapabilityMap::iterator, bool> inserted =
- mMap.insert(CapabilityMap::value_type(mapper->getCapName(), mapper));
- // If we already have a mapper for that name, insert() merely located the
- // existing iterator and returned false. It is a coding error to try to
- // register more than one mapper for the same capability name.
- if (! inserted.second)
- {
- throw DupCapMapper(std::string("Duplicate capability name ") + mapper->getCapName());
- }
-}
-
-void LLCapabilityListener::CapabilityMappers::unregisterMapper(const LLCapabilityListener::CapabilityMapper* mapper)
-{
- CapabilityMap::iterator found = mMap.find(mapper->getCapName());
- if (found != mMap.end())
- {
- mMap.erase(found);
- }
-}
-
-const LLCapabilityListener::CapabilityMapper*
-LLCapabilityListener::CapabilityMappers::find(const std::string& cap) const
-{
- CapabilityMap::const_iterator found = mMap.find(cap);
- if (found != mMap.end())
- {
- return found->second;
- }
- return NULL;
-}
diff --git a/indra/newview/llcapabilitylistener.h b/indra/newview/llcapabilitylistener.h
deleted file mode 100755
index e7535013e7..0000000000
--- a/indra/newview/llcapabilitylistener.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * @file llcapabilitylistener.h
- * @author Nat Goodspeed
- * @date 2009-01-07
- * @brief Provide an event-based API for capability requests
- *
- * $LicenseInfo:firstyear=2009&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$
- */
-
-#if ! defined(LL_LLCAPABILITYLISTENER_H)
-#define LL_LLCAPABILITYLISTENER_H
-
-#include "llevents.h" // LLEventPump
-#include "llsdmessage.h" // LLSDMessage::ArgError
-#include "llerror.h" // LOG_CLASS()
-
-class LLCapabilityProvider;
-class LLMessageSystem;
-class LLSD;
-
-class LLCapabilityListener
-{
- LOG_CLASS(LLCapabilityListener);
-public:
- LLCapabilityListener(const std::string& name, LLMessageSystem* messageSystem,
- const LLCapabilityProvider& provider,
- const LLUUID& agentID, const LLUUID& sessionID);
-
- /// Capability-request exception
- typedef LLSDMessage::ArgError ArgError;
- /// Get LLEventPump on which we listen for capability requests
- /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
- LLEventPump& getCapAPI() { return mEventPump; }
-
- /**
- * Base class for mapping an as-yet-undeployed capability name to a (pair
- * of) LLMessageSystem message(s). To map a capability name to such
- * messages, derive a subclass of CapabilityMapper and declare a static
- * instance in a translation unit known to be loaded. The mapping is not
- * region-specific. If an LLViewerRegion's capListener() receives a
- * request for a supported capability, it will use the capability's URL.
- * If not, it will look for an applicable CapabilityMapper subclass
- * instance.
- */
- class CapabilityMapper
- {
- public:
- /**
- * Base-class constructor. Typically your subclass constructor will
- * pass these parameters as literals.
- * @param cap the capability name handled by this (subclass) instance
- * @param reply the name of the response LLMessageSystem message. Omit
- * if the LLMessageSystem message you intend to send doesn't prompt a
- * reply message, or if you already handle that message in some other
- * way.
- */
- CapabilityMapper(const std::string& cap, const std::string& reply = "");
- virtual ~CapabilityMapper();
- /// query the capability name
- std::string getCapName() const { return mCapName; }
- /// query the reply message name
- std::string getReplyName() const { return mReplyName; }
- /**
- * Override this method to build the LLMessageSystem message we should
- * send instead of the requested capability message. DO NOT send that
- * message: that will be handled by the caller.
- */
- virtual void buildMessage(LLMessageSystem* messageSystem,
- const LLUUID& agentID,
- const LLUUID& sessionID,
- const std::string& capabilityName,
- const LLSD& payload) const = 0;
- /**
- * Override this method if you pass a non-empty @a reply
- * LLMessageSystem message name to the constructor: that is, if you
- * expect to receive an LLMessageSystem message in response to the
- * message you constructed in buildMessage(). If you don't pass a @a
- * reply message name, you need not override this method as it won't
- * be called.
- *
- * Using LLMessageSystem message-reading operations, your
- * readResponse() override should construct and return an LLSD object
- * of the form you expect to receive from the real implementation of
- * the capability you intend to invoke, when it finally goes live.
- */
- virtual LLSD readResponse(LLMessageSystem* messageSystem) const;
-
- private:
- const std::string mCapName;
- const std::string mReplyName;
- };
-
-private:
- /// Bind the LLCapabilityProvider passed to our ctor
- const LLCapabilityProvider& mProvider;
-
- /// Post an event to this LLEventPump to invoke a capability message on
- /// the bound LLCapabilityProvider's server
- /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
- LLEventStream mEventPump;
-
- LLMessageSystem* mMessageSystem;
- LLUUID mAgentID, mSessionID;
-
- /// listener to process capability requests
- bool capListener(const LLSD&);
-
- /// helper class for capListener()
- class CapabilityMappers;
-};
-
-#endif /* ! defined(LL_LLCAPABILITYLISTENER_H) */
diff --git a/indra/newview/llcaphttpsender.cpp b/indra/newview/llcaphttpsender.cpp
deleted file mode 100755
index b2524d14f8..0000000000
--- a/indra/newview/llcaphttpsender.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file llcaphttpsender.cpp
- * @brief Abstracts details of sending messages via UntrustedMessage cap.
- *
- * $LicenseInfo:firstyear=2007&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 "llcaphttpsender.h"
-
-#include "llhost.h"
-
-LLCapHTTPSender::LLCapHTTPSender(const std::string& cap) :
- mCap(cap)
-{
-}
-
-//virtual
-void LLCapHTTPSender::send(const LLHost& host, const std::string& message,
- const LLSD& body,
- LLHTTPClient::ResponderPtr response) const
-{
- LL_INFOS() << "LLCapHTTPSender::send: message " << message
- << " to host " << host << LL_ENDL;
- LLSD llsd;
- llsd["message"] = message;
- llsd["body"] = body;
- LLHTTPClient::post(mCap, llsd, response);
-}
diff --git a/indra/newview/llcaphttpsender.h b/indra/newview/llcaphttpsender.h
deleted file mode 100755
index e1f4c813f6..0000000000
--- a/indra/newview/llcaphttpsender.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @file llcaphttpsender.h
- * @brief Abstracts details of sending messages via the
- * UntrustedMessage capability.
- *
- * $LicenseInfo:firstyear=2007&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_CAP_HTTP_SENDER_H
-#define LL_CAP_HTTP_SENDER_H
-
-#include "llhttpsender.h"
-
-class LLCapHTTPSender : public LLHTTPSender
-{
-public:
- LLCapHTTPSender(const std::string& cap);
-
- /** @brief Send message via UntrustedMessage capability with body,
- call response when done */
- virtual void send(const LLHost& host,
- const std::string& message, const LLSD& body,
- LLHTTPClient::ResponderPtr response) const;
-
-private:
- std::string mCap;
-};
-
-#endif // LL_CAP_HTTP_SENDER_H
diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp
deleted file mode 100755
index f1ef8e9a03..0000000000
--- a/indra/newview/llclassifiedstatsresponder.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file llclassifiedstatsresponder.cpp
- * @brief Receives information about classified ad click-through
- * counts for display in the classified information UI.
- *
- * $LicenseInfo:firstyear=2007&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 "llclassifiedstatsresponder.h"
-
-#include "llpanelclassified.h"
-#include "llpanel.h"
-#include "llhttpclient.h"
-#include "llsdserialize.h"
-#include "llviewerregion.h"
-#include "llview.h"
-#include "message.h"
-
-LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID classified_id)
-: mClassifiedID(classified_id)
-{}
-
-/*virtual*/
-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();
- S32 search_teleport = content["search_teleport_clicks"].asInteger();
- S32 search_map = content["search_map_clicks"].asInteger();
- S32 search_profile = content["search_profile_clicks"].asInteger();
-
- LLPanelClassifiedInfo::setClickThrough( mClassifiedID,
- teleport + search_teleport,
- map + search_map,
- profile + search_profile,
- true);
-}
-
-/*virtual*/
-void LLClassifiedStatsResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-}
-
diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h
deleted file mode 100755
index efa4d82411..0000000000
--- a/indra/newview/llclassifiedstatsresponder.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @file llclassifiedstatsresponder.h
- * @brief Receives information about classified ad click-through
- * counts for display in the classified information UI.
- *
- * $LicenseInfo:firstyear=2007&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_LLCLASSIFIEDSTATSRESPONDER_H
-#define LL_LLCLASSIFIEDSTATSRESPONDER_H
-
-#include "llhttpclient.h"
-#include "llview.h"
-#include "lluuid.h"
-
-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 httpSuccess();
- //If we get back an error (not found, etc...), handle it here
- virtual void httpFailure();
-
-protected:
- LLUUID mClassifiedID;
-};
-
-#endif // LL_LLCLASSIFIEDSTATSRESPONDER_H
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index d9fd4509a5..219bcf0eb0 100755
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -37,8 +37,6 @@
#include "llcompilequeue.h"
#include "llagent.h"
-#include "llassetuploadqueue.h"
-#include "llassetuploadresponders.h"
#include "llchat.h"
#include "llfloaterreg.h"
#include "llviewerwindow.h"
@@ -59,11 +57,54 @@
#include "lltrans.h"
#include "llselectmgr.h"
-#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
-// *TODO: This should be separated into the script queue, and the floater views of that queue.
-// There should only be one floater class that can view any queue type
+#include "llviewerassetupload.h"
+#include "llcorehttputil.h"
+
+// *NOTE$: A minor specialization of LLScriptAssetUpload, it does not require a buffer
+// (and does not save a buffer to the vFS) and it finds the compile queue window and
+// displays a compiling message.
+class LLQueuedScriptAssetUpload : public LLScriptAssetUpload
+{
+public:
+ LLQueuedScriptAssetUpload(LLUUID taskId, LLUUID itemId, LLUUID assetId, TargetType_t targetType,
+ bool isRunning, std::string scriptName, LLUUID queueId, LLUUID exerienceId, taskUploadFinish_f finish) :
+ LLScriptAssetUpload(taskId, itemId, targetType, isRunning,
+ exerienceId, std::string(), finish),
+ mScriptName(scriptName),
+ mQueueId(queueId)
+ {
+ setAssetId(assetId);
+ }
+
+ virtual LLSD prepareUpload()
+ {
+ /* *NOTE$: The parent class (LLScriptAssetUpload will attempt to save
+ * the script buffer into to the VFS. Since the resource is already in
+ * the VFS we don't want to do that. Just put a compiling message in
+ * the window and move on
+ */
+ LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId));
+ if (queue)
+ {
+ std::string message = std::string("Compiling \"") + getScriptName() + std::string("\"...");
+
+ queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
+ }
+
+ return LLSD().with("success", LLSD::Boolean(true));
+ }
+
+
+ std::string getScriptName() const { return mScriptName; }
+
+private:
+ void setScriptName(const std::string &scriptName) { mScriptName = scriptName; }
+
+ LLUUID mQueueId;
+ std::string mScriptName;
+};
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
@@ -127,7 +168,7 @@ void LLFloaterScriptQueue::inventoryChanged(LLViewerObject* viewer_object,
//which it internally stores.
//If we call this further down in the function, calls to handleInventory
- //and nextObject may update the interally stored viewer object causing
+ //and nextObject may update the internally stored viewer object causing
//the removal of the incorrect listener from an incorrect object.
//Fixes SL-6119:Recompile scripts fails to complete
@@ -242,81 +283,17 @@ BOOL LLFloaterScriptQueue::startQueue()
return nextObject();
}
-class CompileQueueExperienceResponder : public LLHTTPClient::Responder
-{
-public:
- CompileQueueExperienceResponder(const LLUUID& parent):mParent(parent)
- {
- }
-
- LLUUID mParent;
-
- /*virtual*/ void httpSuccess()
- {
- sendResult(getContent());
- }
- /*virtual*/ void httpFailure()
- {
- sendResult(LLSD());
- }
- void sendResult(const LLSD& content)
- {
- LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", mParent);
- if(!queue)
- return;
-
- queue->experienceIdsReceived(content["experience_ids"]);
- }
-};
-
-
-
///----------------------------------------------------------------------------
/// Class LLFloaterCompileQueue
///----------------------------------------------------------------------------
-
-class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier
-{
-public:
-
- LLCompileFloaterUploadQueueSupplier(const LLUUID& queue_id) :
- mQueueId(queue_id)
- {
- }
-
- virtual LLAssetUploadQueue* get() const
- {
- LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId));
- if(NULL == queue)
- {
- return NULL;
- }
- return queue->getUploadQueue();
- }
-
- virtual void log(std::string message) const
- {
- LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId));
- if(NULL == queue)
- {
- return;
- }
-
- queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
- }
-
-private:
- LLUUID mQueueId;
-};
-
LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key)
: LLFloaterScriptQueue(key)
{
setTitle(LLTrans::getString("CompileQueueTitle"));
setStartString(LLTrans::getString("CompileQueueStart"));
- mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID()));
+// mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID()));
}
LLFloaterCompileQueue::~LLFloaterCompileQueue()
@@ -380,8 +357,8 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
LLScriptQueueData* datap = new LLScriptQueueData(getKey().asUUID(),
viewer_object->getID(), itemp);
- ExperienceAssociationResponder::fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(),
- boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1));
+ LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(),
+ boost::bind(&LLFloaterCompileQueue::requestAsset, datap, _1));
}
}
}
@@ -423,6 +400,37 @@ void LLFloaterCompileQueue::requestAsset( LLScriptQueueData* datap, const LLSD&
(void*)datap);
}
+/*static*/
+void LLFloaterCompileQueue::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId)
+{
+
+ LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(queueId));
+ if (queue)
+ {
+ // Bytecode save completed
+ if (response["compiled"])
+ {
+ std::string message = std::string("Compilation of \"") + scriptName + std::string("\" succeeded");
+
+ queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
+ LL_INFOS() << message << LL_ENDL;
+ }
+ else
+ {
+ LLSD compile_errors = response["errors"];
+ for (LLSD::array_const_iterator line = compile_errors.beginArray();
+ line < compile_errors.endArray(); line++)
+ {
+ std::string str = line->asString();
+ str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
+
+ queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(str, ADD_BOTTOM);
+ }
+ LL_INFOS() << response["errors"] << LL_ENDL;
+ }
+
+ }
+}
// This is the callback for when each script arrives
// static
@@ -441,36 +449,21 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
std::string buffer;
if(queue && (0 == status))
{
- //LL_INFOS() << "ITEM NAME 3: " << data->mScriptName << LL_ENDL;
-
- // Dump this into a file on the local disk so we can compile it.
- std::string filename;
- LLVFile file(vfs, asset_id, type);
- std::string uuid_str;
- asset_id.toString(uuid_str);
- filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + llformat(".%s",LLAssetType::lookup(type));
-
- const bool is_running = true;
- LLViewerObject* object = gObjectList.findObject(data->mTaskId);
- if (object)
- {
- std::string url = object->getRegion()->getCapability("UpdateScriptTask");
- if(!url.empty())
- {
- // Read script source in to buffer.
- U32 script_size = file.getSize();
- U8* script_data = new U8[script_size];
- file.read(script_data, script_size);
-
- queue->mUploadQueue->queue(filename, data->mTaskId,
- data->mItem->getUUID(), is_running, queue->mMono, queue->getKey().asUUID(),
- script_data, script_size, data->mItem->getName(), data->mExperienceId);
- }
- else
- {
- buffer = LLTrans::getString("CompileQueueServiceUnavailable") + (": ") + data->mItem->getName();
- }
- }
+ LLViewerObject* object = gObjectList.findObject(data->mTaskId);
+ if (object)
+ {
+ std::string url = object->getRegion()->getCapability("UpdateScriptTask");
+ std::string scriptName = data->mItem->getName();
+
+ LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLFloaterCompileQueue::finishLSLUpload, _1, _2, _3, _4,
+ scriptName, data->mQueueID);
+
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(data->mTaskId, data->mItem->getUUID(), asset_id,
+ (queue->mMono) ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2,
+ true, scriptName, data->mQueueID, data->mExperienceId, proc));
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
}
else
{
@@ -653,14 +646,29 @@ BOOL LLFloaterCompileQueue::startQueue()
std::string lookup_url=region->getCapability("GetCreatorExperiences");
if(!lookup_url.empty())
{
- LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(getKey().asUUID()));
- return TRUE;
+ LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success =
+ boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, _1, getKey().asUUID());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t failure =
+ boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, LLSD(), getKey().asUUID());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url,
+ success, failure);
+ return TRUE;
}
}
return nextObject();
}
+/*static*/
+void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID parent)
+{
+ LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", parent);
+ if (!queue)
+ return;
+ queue->experienceIdsReceived(result["experience_ids"]);
+}
void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t* inv)
diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h
index 54842bb302..cee8efe9b0 100755
--- a/indra/newview/llcompilequeue.h
+++ b/indra/newview/llcompilequeue.h
@@ -118,8 +118,6 @@ struct LLCompileQueueData
mQueueID(q_id), mItemId(item_id) {}
};
-class LLAssetUploadQueue;
-
class LLFloaterCompileQueue : public LLFloaterScriptQueue
{
friend class LLFloaterReg;
@@ -131,8 +129,6 @@ public:
// remove any object in mScriptScripts with the matching uuid.
void removeItemByItemID(const LLUUID& item_id);
- LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; }
-
void experienceIdsReceived( const LLSD& content );
BOOL hasExperience(const LLUUID& id)const;
@@ -147,6 +143,8 @@ protected:
static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience);
+ static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId);
+
// This is the callback for when each script arrives
static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
LLAssetType::EType type,
@@ -157,7 +155,8 @@ protected:
LLViewerInventoryItem::item_array_t mCurrentScripts;
private:
- LLAssetUploadQueue* mUploadQueue;
+ static void processExperienceIdResults(LLSD result, LLUUID parent);
+
uuid_list_t mExperienceIds;
};
diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp
index 78d619a315..8f2eb41307 100755
--- a/indra/newview/llestateinfomodel.cpp
+++ b/indra/newview/llestateinfomodel.cpp
@@ -29,7 +29,6 @@
#include "llestateinfomodel.h"
// libs
-#include "llhttpclient.h"
#include "llregionflags.h"
#include "message.h"
@@ -38,6 +37,8 @@
#include "llfloaterregioninfo.h" // for invoice id
#include "llviewerregion.h"
+#include "llcorehttputil.h"
+
LLEstateInfoModel::LLEstateInfoModel()
: mID(0)
, mFlags(0)
@@ -110,24 +111,6 @@ void LLEstateInfoModel::notifyCommit()
//== PRIVATE STUFF ============================================================
-class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLEstateChangeInfoResponder);
-protected:
- // if we get a normal response, handle it here
- virtual void httpSuccesss()
- {
- LL_INFOS() << "Committed estate info" << LL_ENDL;
- LLEstateInfoModel::instance().notifyCommit();
- }
-
- // if we get an error response
- virtual void httpFailure()
- {
- LL_WARNS() << "Failed to commit estate info " << dumpResponse() << LL_ENDL;
- }
-};
-
// tries to send estate info using a cap; returns true if it succeeded
bool LLEstateInfoModel::commitEstateInfoCaps()
{
@@ -139,29 +122,53 @@ bool LLEstateInfoModel::commitEstateInfoCaps()
return false;
}
- LLSD body;
- body["estate_name" ] = getName();
- body["sun_hour" ] = getSunHour();
+ LLCoros::instance().launch("LLEstateInfoModel::commitEstateInfoCapsCoro",
+ boost::bind(&LLEstateInfoModel::commitEstateInfoCapsCoro, this, url));
- body["is_sun_fixed" ] = getUseFixedSun();
- body["is_externally_visible"] = getIsExternallyVisible();
- body["allow_direct_teleport"] = getAllowDirectTeleport();
- body["deny_anonymous" ] = getDenyAnonymous();
- body["deny_age_unverified" ] = getDenyAgeUnverified();
- body["allow_voice_chat" ] = getAllowVoiceChat();
-
- body["invoice" ] = LLFloaterRegionInfo::getLastInvoice();
-
- LL_DEBUGS("Windlight Sync") << "Sending estate caps: "
- << "is_sun_fixed = " << getUseFixedSun()
- << ", sun_hour = " << getSunHour() << LL_ENDL;
- LL_DEBUGS() << body << LL_ENDL;
-
- // we use a responder so that we can re-get the data after committing to the database
- LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder);
return true;
}
+void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EstateChangeInfo", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD body;
+ body["estate_name"] = getName();
+ body["sun_hour"] = getSunHour();
+
+ body["is_sun_fixed"] = getUseFixedSun();
+ body["is_externally_visible"] = getIsExternallyVisible();
+ body["allow_direct_teleport"] = getAllowDirectTeleport();
+ body["deny_anonymous"] = getDenyAnonymous();
+ body["deny_age_unverified"] = getDenyAgeUnverified();
+ body["allow_voice_chat"] = getAllowVoiceChat();
+
+ body["invoice"] = LLFloaterRegionInfo::getLastInvoice();
+
+ LL_DEBUGS("Windlight Sync") << "Sending estate caps: "
+ << "is_sun_fixed = " << getUseFixedSun()
+ << ", sun_hour = " << getSunHour() << LL_ENDL;
+ LL_DEBUGS() << body << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status)
+ {
+ LL_INFOS() << "Committed estate info" << LL_ENDL;
+ LLEstateInfoModel::instance().notifyCommit();
+ }
+ else
+ {
+ LL_WARNS() << "Failed to commit estate info " << LL_ENDL;
+ }
+}
+
/* This is the old way of doing things, is deprecated, and should be
deleted when the dataserver model can be removed */
// key = "estatechangeinfo"
diff --git a/indra/newview/llestateinfomodel.h b/indra/newview/llestateinfomodel.h
index 538f2f7c75..fcfbd1ce7d 100755
--- a/indra/newview/llestateinfomodel.h
+++ b/indra/newview/llestateinfomodel.h
@@ -30,6 +30,8 @@
class LLMessageSystem;
#include "llsingleton.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
/**
* Contains estate info, notifies interested parties of its changes.
@@ -73,7 +75,6 @@ protected:
friend class LLSingleton<LLEstateInfoModel>;
friend class LLDispatchEstateUpdateInfo;
- friend class LLEstateChangeInfoResponder;
LLEstateInfoModel();
@@ -99,6 +100,8 @@ private:
update_signal_t mUpdateSignal; /// emitted when we receive update from sim
update_signal_t mCommitSignal; /// emitted when our update gets applied to sim
+
+ void commitEstateInfoCapsCoro(std::string url);
};
inline bool LLEstateInfoModel::getFlag(U64 flag) const
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index 4de6ad4d2f..021d17251d 100755
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -30,261 +30,248 @@
#include "llappviewer.h"
#include "llagent.h"
-#include "llhttpclient.h"
-#include "llhttpconstants.h"
#include "llsdserialize.h"
#include "lleventtimer.h"
#include "llviewerregion.h"
#include "message.h"
#include "lltrans.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
+#include "lleventfilter.h"
-namespace
+namespace LLEventPolling
{
- // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
- // This means we attempt to recover relatively quickly but back off giving more time to recover
- // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
- const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
- const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
- const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
-
- class LLEventPollResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLEventPollResponder);
- public:
-
- static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
- void stop();
-
- 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 httpFailure();
- /* virtual */ void httpSuccess();
-
- private:
-
- bool mDone;
-
- std::string mPollURL;
- std::string mSender;
-
- LLSD mAcknowledge;
-
- // these are only here for debugging so we can see which poller is which
- static int sCount;
- int mCount;
- S32 mErrorCount;
- };
-
- class LLEventPollEventTimer : public LLEventTimer
- {
- typedef LLPointer<LLEventPollResponder> EventPollResponderPtr;
-
- public:
- LLEventPollEventTimer(F32 period, EventPollResponderPtr responder)
- : LLEventTimer(period), mResponder(responder)
- { }
-
- virtual BOOL tick()
- {
- mResponder->makeRequest();
- return TRUE; // Causes this instance to be deleted.
- }
-
- private:
-
- EventPollResponderPtr mResponder;
- };
-
- //static
- LLHTTPClient::ResponderPtr LLEventPollResponder::start(
- const std::string& pollURL, const LLHost& sender)
- {
- LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender);
- LL_INFOS() << "LLEventPollResponder::start <" << sCount << "> "
- << pollURL << LL_ENDL;
- return result;
- }
-
- void LLEventPollResponder::stop()
- {
- LL_INFOS() << "LLEventPollResponder::stop <" << mCount << "> "
- << mPollURL << LL_ENDL;
- // there should be a way to stop a LLHTTPClient request in progress
- mDone = true;
- }
-
- int LLEventPollResponder::sCount = 0;
-
- LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender)
- : mDone(false),
- mPollURL(pollURL),
- mCount(++sCount),
- mErrorCount(0)
- {
- //extract host and port of simulator to set as sender
- LLViewerRegion *regionp = gAgent.getRegion();
- if (!regionp)
- {
- LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL;
- }
- mSender = sender.getIPandPort();
- LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL;
- makeRequest();
- }
-
- LLEventPollResponder::~LLEventPollResponder()
- {
- stop();
- LL_DEBUGS() << "LLEventPollResponder::~Impl <" << mCount << "> "
- << mPollURL << LL_ENDL;
- }
-
- // virtual
- void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- if (getStatus() == HTTP_BAD_GATEWAY)
- {
- // These errors are not parsable as LLSD,
- // which LLHTTPClient::Responder::completedRaw will try to do.
- httpCompleted();
- }
- else
- {
- LLHTTPClient::Responder::completedRaw(channels,buffer);
- }
- }
-
- void LLEventPollResponder::makeRequest()
- {
- LLSD request;
- request["ack"] = mAcknowledge;
- request["done"] = mDone;
-
- LL_DEBUGS() << "LLEventPollResponder::makeRequest <" << mCount << "> ack = "
- << LLSDXMLStreamer(mAcknowledge) << LL_ENDL;
- LLHTTPClient::post(mPollURL, request, this);
- }
-
- void LLEventPollResponder::handleMessage(const LLSD& content)
- {
- std::string msg_name = content["message"];
- LLSD message;
- message["sender"] = mSender;
- message["body"] = content["body"];
- LLMessageSystem::dispatch(msg_name, message);
- }
-
- //virtual
- 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 ( getStatus() == HTTP_BAD_GATEWAY )
- {
- mErrorCount = 0;
- makeRequest();
- }
- else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS)
- {
- ++mErrorCount;
-
- // The 'tick' will return TRUE causing the timer to delete this.
- new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS
- + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
- , this);
-
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
- else
- {
- LL_WARNS() << dumpResponse()
- << " [count:" << mCount << "] "
- << (mDone ? " -- done" : "") << LL_ENDL;
- stop();
-
- // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
- // IMs, teleports, about land, selecing land, region crossing and more will all fail.
- // They are essentially disconnected from the region even though some things may still work.
- // Since things won't get better until they relog we force a disconnect now.
-
- // *NOTE:Mani - The following condition check to see if this failing event poll
- // is attached to the Agent's main region. If so we disconnect the viewer.
- // Else... its a child region and we just leave the dead event poll stopped and
- // continue running.
- if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender)
- {
- LL_WARNS() << "Forcing disconnect due to stalled main region event poll." << LL_ENDL;
- LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
- }
- }
- }
-
- //virtual
- void LLEventPollResponder::httpSuccess()
- {
- LL_DEBUGS() << "LLEventPollResponder::result <" << mCount << ">"
- << (mDone ? " -- done" : "") << LL_ENDL;
-
- if (mDone) return;
-
- mErrorCount = 0;
-
- const LLSD& content = getContent();
- if (!content.isMap() ||
- !content.get("events") ||
- !content.get("id"))
- {
- LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL;
- makeRequest();
- return;
- }
-
- mAcknowledge = content["id"];
- LLSD events = content["events"];
-
- if(mAcknowledge.isUndefined())
- {
- LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL;
- }
-
- // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
- LL_DEBUGS() << "LLEventPollResponder::httpSuccess <" << mCount << "> " << events.size() << "events (id "
- << LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL;
-
- LLSD::array_const_iterator i = events.beginArray();
- LLSD::array_const_iterator end = events.endArray();
- for (; i != end; ++i)
- {
- if (i->has("message"))
- {
- handleMessage(*i);
- }
- }
-
- makeRequest();
- }
+namespace Details
+{
+
+ class LLEventPollImpl
+ {
+ public:
+ LLEventPollImpl(const LLHost &sender);
+
+ void start(const std::string &url);
+ void stop();
+
+ private:
+ // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
+ // This means we attempt to recover relatively quickly but back off giving more time to recover
+ // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
+ static const F32 EVENT_POLL_ERROR_RETRY_SECONDS;
+ static const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC;
+ static const S32 MAX_EVENT_POLL_HTTP_ERRORS;
+
+ void eventPollCoro(std::string url);
+
+ void handleMessage(const LLSD &content);
+
+ bool mDone;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
+ std::string mSenderIp;
+ int mCounter;
+ LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mAdapter;
+
+ static int sNextCounter;
+ };
+
+
+ const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
+ const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
+ const S32 LLEventPollImpl::MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
+
+ int LLEventPollImpl::sNextCounter = 1;
+
+
+ LLEventPollImpl::LLEventPollImpl(const LLHost &sender) :
+ mDone(false),
+ mHttpRequest(),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mSenderIp(),
+ mCounter(sNextCounter++)
+
+ {
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
+ mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_LONG_POLL);
+ mSenderIp = sender.getIPandPort();
+ }
+
+ void LLEventPollImpl::handleMessage(const LLSD& content)
+ {
+ std::string msg_name = content["message"];
+ LLSD message;
+ message["sender"] = mSenderIp;
+ message["body"] = content["body"];
+ LLMessageSystem::dispatch(msg_name, message);
+ }
+
+ void LLEventPollImpl::start(const std::string &url)
+ {
+ if (!url.empty())
+ {
+ std::string coroname =
+ LLCoros::instance().launch("LLEventPollImpl::eventPollCoro",
+ boost::bind(&LLEventPollImpl::eventPollCoro, this, url));
+ LL_INFOS("LLEventPollImpl") << coroname << " with url '" << url << LL_ENDL;
+ }
+ }
+
+ void LLEventPollImpl::stop()
+ {
+ LL_INFOS() << "requesting stop for event poll coroutine <" << mCounter << ">" << LL_ENDL;
+ mDone = true;
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter = mAdapter.lock();
+ if (adapter)
+ {
+ // cancel the yielding operation if any.
+ adapter->cancelSuspendedOperation();
+ }
+ }
+
+ void LLEventPollImpl::eventPollCoro(std::string url)
+ {
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EventPoller", mHttpPolicy));
+ LLSD acknowledge;
+ int errorCount = 0;
+ int counter = mCounter; // saved on the stack for logging.
+
+ LL_INFOS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL;
+
+ mAdapter = httpAdapter;
+
+ // continually poll for a server update until we've been flagged as
+ // finished
+ while (!mDone)
+ {
+ LLSD request;
+ request["ack"] = acknowledge;
+ request["done"] = mDone;
+
+// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> request = "
+// << LLSDXMLStreamer(request) << LL_ENDL;
+
+ LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> posting and yielding." << LL_ENDL;
+ LLSD result = httpAdapter->postAndSuspend(mHttpRequest, url, request);
+
+// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = "
+// << LLSDXMLStreamer(result) << LL_ENDL;
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (status == LLCore::HttpStatus(HTTP_BAD_GATEWAY))
+ { // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
+ // we get this when there are no events.
+ errorCount = 0;
+ continue;
+ }
+ else if ((status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_OP_CANCELED)) ||
+ (status == LLCore::HttpStatus(HTTP_NOT_FOUND)))
+ { // Event polling for this server has been canceled. In
+ // some cases the server gets ahead of the viewer and will
+ // return a 404 error (Not Found) before the cancel event
+ // comes back in the queue
+ LL_WARNS() << "Canceling coroutine" << LL_ENDL;
+ break;
+ }
+ LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+ << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL;
+
+ if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS)
+ { // An unanticipated error has been received from our poll
+ // request. Calculate a timeout and wait for it to expire(sleep)
+ // before trying again. The sleep time is increased by 5 seconds
+ // for each consecutive error.
+ LLEventTimeout timeout;
+ ++errorCount;
+
+ F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS
+ + errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC;
+
+ LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry <<
+ " seconds, error count is now " << errorCount << LL_ENDL;
+
+ timeout.eventAfter(waitToRetry, LLSD());
+ llcoro::suspendUntilEventOn(timeout);
+
+ if (mDone)
+ break;
+ LL_INFOS("LLEventPollImpl") << "<" << counter << "> About to retry request." << LL_ENDL;
+ continue;
+ }
+ else
+ {
+ // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
+ // IMs, teleports, about land, selecting land, region crossing and more will all fail.
+ // They are essentially disconnected from the region even though some things may still work.
+ // Since things won't get better until they relog we force a disconnect now.
+ mDone = true;
+
+ // *NOTE:Mani - The following condition check to see if this failing event poll
+ // is attached to the Agent's main region. If so we disconnect the viewer.
+ // Else... its a child region and we just leave the dead event poll stopped and
+ // continue running.
+ if (gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSenderIp)
+ {
+ LL_WARNS("LLEventPollImpl") << "< " << counter << "> Forcing disconnect due to stalled main region event poll." << LL_ENDL;
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
+ }
+ break;
+ }
+ }
+
+ errorCount = 0;
+
+ if (!result.isMap() ||
+ !result.get("events") ||
+ !result.get("id"))
+ {
+ LL_WARNS("LLEventPollImpl") << " <" << counter << "> received event poll with no events or id key: " << LLSDXMLStreamer(result) << LL_ENDL;
+ continue;
+ }
+
+ acknowledge = result["id"];
+ LLSD events = result["events"];
+
+ if (acknowledge.isUndefined())
+ {
+ LL_WARNS("LLEventPollImpl") << " id undefined" << LL_ENDL;
+ }
+
+ // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
+ LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << LLSDXMLStreamer(acknowledge) << ")" << LL_ENDL;
+
+ LLSD::array_const_iterator i = events.beginArray();
+ LLSD::array_const_iterator end = events.endArray();
+ for (; i != end; ++i)
+ {
+ if (i->has("message"))
+ {
+ handleMessage(*i);
+ }
+ }
+ }
+ LL_INFOS("LLEventPollImpl") << " <" << counter << "> Leaving coroutine." << LL_ENDL;
+ }
+
+}
}
-LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender)
- : mImpl(LLEventPollResponder::start(poll_url, sender))
- { }
+LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender):
+ mImpl()
+{
+ mImpl = boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl>
+ (new LLEventPolling::Details::LLEventPollImpl(sender));
+ mImpl->start(poll_url);
+}
LLEventPoll::~LLEventPoll()
{
- LLHTTPClient::Responder* responderp = mImpl.get();
- LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp);
- if (event_poll_responder) event_poll_responder->stop();
+ mImpl->stop();
+
}
diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h
index e8d98062aa..e2afd9226b 100755
--- a/indra/newview/lleventpoll.h
+++ b/indra/newview/lleventpoll.h
@@ -27,10 +27,23 @@
#ifndef LL_LLEVENTPOLL_H
#define LL_LLEVENTPOLL_H
-#include "llhttpclient.h"
+#include "boost/move/unique_ptr.hpp"
+
+namespace boost
+{
+ using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace.
+}
class LLHost;
+namespace LLEventPolling
+{
+namespace Details
+{
+ class LLEventPollImpl;
+}
+}
+
class LLEventPoll
///< implements the viewer side of server-to-viewer pushed events.
@@ -40,11 +53,11 @@ public:
///< Start polling the URL.
virtual ~LLEventPoll();
- ///< will stop polling, cancelling any poll in progress.
+ ///< will stop polling, canceling any poll in progress.
private:
- LLHTTPClient::ResponderPtr mImpl;
+ boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl> mImpl;
};
diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp
deleted file mode 100644
index b50c81eedc..0000000000
--- a/indra/newview/llexperienceassociationresponder.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file llexperienceassociationresponder.cpp
- * @brief llexperienceassociationresponder implementation. This class combines
- * a lookup for a script association and an experience details request. The first
- * is always async, but the second may be cached locally.
- *
- * $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 "llexperienceassociationresponder.h"
-#include "llexperiencecache.h"
-#include "llviewerregion.h"
-#include "llagent.h"
-
-ExperienceAssociationResponder::ExperienceAssociationResponder(ExperienceAssociationResponder::callback_t callback):mCallback(callback)
-{
- ref();
-}
-
-void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& object_id, const LLUUID& item_id, callback_t callback )
-{
- LLSD request;
- request["object-id"]=object_id;
- request["item-id"]=item_id;
- fetchAssociatedExperience(request, callback);
-}
-
-void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback)
-{
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- std::string lookup_url=region->getCapability("GetMetadata");
- if(!lookup_url.empty())
- {
- LLSD fields;
- fields.append("experience");
- request["fields"] = fields;
- LLHTTPClient::post(lookup_url, request, new ExperienceAssociationResponder(callback));
- }
- }
-}
-
-void ExperienceAssociationResponder::httpFailure()
-{
- LLSD msg;
- msg["error"]=(LLSD::Integer)getStatus();
- msg["message"]=getReason();
- LL_INFOS("ExperienceAssociation") << "Failed to look up associated experience: " << getStatus() << ": " << getReason() << LL_ENDL;
-
- sendResult(msg);
-
-}
-void ExperienceAssociationResponder::httpSuccess()
-{
- if(!getContent().has("experience"))
- {
-
- LLSD msg;
- msg["message"]="no experience";
- msg["error"]=-1;
- sendResult(msg);
- return;
- }
-
- LLExperienceCache::get(getContent()["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1));
-
-}
-
-void ExperienceAssociationResponder::sendResult( const LLSD& experience )
-{
- mCallback(experience);
- unref();
-}
-
-
-
diff --git a/indra/newview/llexperienceassociationresponder.h b/indra/newview/llexperienceassociationresponder.h
deleted file mode 100644
index 2bdc3d251b..0000000000
--- a/indra/newview/llexperienceassociationresponder.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "llhttpclient.h"
-#include "llsd.h"
-/**
- * @file llexperienceassociationresponder.h
- * @brief llexperienceassociationresponder and related class definitions
- *
- * $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_LLEXPERIENCEASSOCIATIONRESPONDER_H
-#define LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
-
-#include "llhttpclient.h"
-#include "llsd.h"
-
-class ExperienceAssociationResponder : public LLHTTPClient::Responder
-{
-public:
- typedef boost::function<void(const LLSD& experience)> callback_t;
-
- ExperienceAssociationResponder(callback_t callback);
-
- /*virtual*/ void httpSuccess();
- /*virtual*/ void httpFailure();
-
- static void fetchAssociatedExperience(const LLUUID& object_it, const LLUUID& item_id, callback_t callback);
-
-private:
- static void fetchAssociatedExperience(LLSD& request, callback_t callback);
-
- void sendResult(const LLSD& experience);
-
- callback_t mCallback;
-
-};
-
-#endif // LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp
index 28319564e4..1de4102dba 100755
--- a/indra/newview/llfacebookconnect.cpp
+++ b/indra/newview/llfacebookconnect.cpp
@@ -34,7 +34,6 @@
#include "llagent.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcommandhandler.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llurlaction.h"
#include "llimagepng.h"
@@ -42,9 +41,11 @@
#include "lltrans.h"
#include "llevents.h"
#include "llviewerregion.h"
+#include "llviewercontrol.h"
#include "llfloaterwebcontent.h"
#include "llfloaterreg.h"
+#include "llcorehttputil.h"
boost::scoped_ptr<LLEventPump> LLFacebookConnect::sStateWatcher(new LLEventStream("FacebookConnectState"));
boost::scoped_ptr<LLEventPump> LLFacebookConnect::sInfoWatcher(new LLEventStream("FacebookConnectInfo"));
@@ -67,6 +68,24 @@ void toast_user_for_facebook_success()
LLNotificationsUtil::add("FacebookConnect", args);
}
+LLCore::HttpHeaders::ptr_t get_headers()
+{
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ // The DebugSlshareLogTag mechanism is intended to trigger slshare-service
+ // debug logging. slshare-service is coded to respond to an X-debug-tag
+ // header by engaging debug logging for that request only. This way a
+ // developer need not muck with the slshare-service image to engage debug
+ // logging. Moreover, the value of X-debug-tag is embedded in each such
+ // log line so the developer can quickly find the log lines pertinent to
+ // THIS session.
+ std::string logtag(gSavedSettings.getString("DebugSlshareLogTag"));
+ if (! logtag.empty())
+ {
+ httpHeaders->append("X-debug-tag", logtag);
+ }
+ return httpHeaders;
+}
+
///////////////////////////////////////////////////////////////////////////////
//
class LLFacebookConnectHandler : public LLCommandHandler
@@ -125,266 +144,349 @@ LLFacebookConnectHandler gFacebookConnectHandler;
///////////////////////////////////////////////////////////////////////////////
//
-class LLFacebookConnectResponder : public LLHTTPClient::Responder
+void LLFacebookConnect::facebookConnectCoro(std::string authCode, std::string authState)
{
- LOG_CLASS(LLFacebookConnectResponder);
-public:
-
- LLFacebookConnectResponder()
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ LLSD putData;
+ if (!authCode.empty())
{
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
+ putData["code"] = authCode;
+ }
+ if (!authState.empty())
+ {
+ putData["state"] = authState;
}
-
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
- }
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- 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;
- 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"));
- }
- }
-};
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->putAndSuspend(httpRequest, getFacebookConnectURL("/connection"), putData, httpOpts, get_headers());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFacebookWeb(location);
+ }
+ }
+ }
+ else
+ {
+ LL_INFOS("FacebookConnect") << "Connect successful. " << LL_ENDL;
+ setConnectionState(LLFacebookConnect::FB_CONNECTED);
+ }
+
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFacebookShareResponder : public LLHTTPClient::Responder
+bool LLFacebookConnect::testShareStatus(LLSD &result)
{
- LOG_CLASS(LLFacebookShareResponder);
-public:
-
- LLFacebookShareResponder()
- {
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING);
- }
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- /* virtual */ void httpSuccess()
- {
- toast_user_for_facebook_success();
- LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED);
- }
+ if (status)
+ return true;
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- 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 ( HTTP_NOT_FOUND == getStatus() )
- {
- LLFacebookConnect::instance().connectToFacebook();
- }
- else
- {
- 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"));
- }
- }
-};
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFacebookWeb(location);
+ }
+ }
+ if (status == LLCore::HttpStatus(HTTP_NOT_FOUND))
+ {
+ LL_DEBUGS("FacebookConnect") << "Not connected. " << LL_ENDL;
+ connectToFacebook();
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "HTTP Status error " << status.toString() << LL_ENDL;
+ setConnectionState(LLFacebookConnect::FB_POST_FAILED);
+ log_facebook_connect_error("Share", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ return false;
+}
-///////////////////////////////////////////////////////////////////////////////
-//
-class LLFacebookDisconnectResponder : public LLHTTPClient::Responder
+void LLFacebookConnect::facebookShareCoro(std::string route, LLSD share)
{
- LOG_CLASS(LLFacebookDisconnectResponder);
-public:
-
- LLFacebookDisconnectResponder()
- {
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECTING);
- }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- void setUserDisconnected()
- {
- // Clear data
- LLFacebookConnect::instance().clearInfo();
- LLFacebookConnect::instance().clearContent();
- //Notify state change
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
- }
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL;
- setUserDisconnected();
- }
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFacebookConnectURL(route, true), share, httpOpts, get_headers());
- /* virtual */ void httpFailure()
- {
- //User not found so already disconnected
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;
- setUserDisconnected();
- }
- else
- {
- LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED);
- const LLSD& content = getContent();
- log_facebook_connect_error("Disconnect", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ if (testShareStatus(result))
+ {
+ toast_user_for_facebook_success();
+ LL_DEBUGS("FacebookConnect") << "Post successful. " << LL_ENDL;
+ setConnectionState(LLFacebookConnect::FB_POSTED);
+ }
+}
+
+void LLFacebookConnect::facebookShareImageCoro(std::string route, LLPointer<LLImageFormatted> image, std::string caption)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(get_headers());
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ std::string imageFormat;
+ if (dynamic_cast<LLImagePNG*>(image.get()))
+ {
+ imageFormat = "png";
+ }
+ else if (dynamic_cast<LLImageJPEG*>(image.get()))
+ {
+ imageFormat = "jpg";
+ }
+ else
+ {
+ LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL;
+ return;
+ }
+
+ // All this code is mostly copied from LLWebProfile::post()
+ static const std::string boundary = "----------------------------0123abcdefab";
+
+ std::string contentType = "multipart/form-data; boundary=" + boundary;
+ httpHeaders->append("Content-Type", contentType.c_str());
+
+ LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); //
+ LLCore::BufferArrayStream body(raw.get());
+
+ // *NOTE: The order seems to matter.
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"caption\"\r\n\r\n"
+ << caption << "\r\n";
+
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
+ << "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+ // Insert the image data.
+ // *FIX: Treating this as a string will probably screw it up ...
+ U8* image_data = image->getData();
+ for (S32 i = 0; i < image->getDataSize(); ++i)
+ {
+ body << image_data[i];
+ }
+
+ body << "\r\n--" << boundary << "--\r\n";
+
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFacebookConnectURL(route, true), raw, httpOpts, httpHeaders);
+
+ if (testShareStatus(result))
+ {
+ toast_user_for_facebook_success();
+ LL_DEBUGS("FacebookConnect") << "Post successful. " << LL_ENDL;
+ setConnectionState(LLFacebookConnect::FB_POSTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFacebookConnectedResponder : public LLHTTPClient::Responder
+void LLFacebookConnect::facebookDisconnectCoro()
{
- LOG_CLASS(LLFacebookConnectedResponder);
-public:
-
- LLFacebookConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFacebookConnectURL("/connection"), httpOpts, get_headers());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status && (status != LLCore::HttpStatus(HTTP_FOUND)))
+ {
+ LL_WARNS("FacebookConnect") << "Failed to disconnect:" << status.toTerseString() << LL_ENDL;
+ setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED);
+ log_facebook_connect_error("Disconnect", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
{
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
+ LL_DEBUGS("FacebookConnect") << "Facebook Disconnect successful. " << LL_ENDL;
+ clearInfo();
+ clearContent();
+ //Notify state change
+ setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
}
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED);
- }
+}
- /* virtual */ void httpFailure()
- {
- // show the facebook login page if not connected yet
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL;
- if (mAutoConnect)
- {
- LLFacebookConnect::instance().connectToFacebook();
- }
- else
- {
- LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
- }
- }
- else
- {
- 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"));
- }
- }
-
-private:
- bool mAutoConnect;
-};
+///////////////////////////////////////////////////////////////////////////////
+//
+void LLFacebookConnect::facebookConnectedCheckCoro(bool autoConnect)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
+
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/connection", true), httpOpts, get_headers());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if ( status == LLCore::HttpStatus(HTTP_NOT_FOUND) )
+ {
+ LL_DEBUGS("FacebookConnect") << "Not connected. " << LL_ENDL;
+ if (autoConnect)
+ {
+ connectToFacebook();
+ }
+ else
+ {
+ setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);
+ }
+ }
+ else
+ {
+ LL_WARNS("FacebookConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL;
+
+ setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED);
+ log_facebook_connect_error("Connected", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ }
+ else
+ {
+ LL_DEBUGS("FacebookConnect") << "Connect successful. " << LL_ENDL;
+ setConnectionState(LLFacebookConnect::FB_CONNECTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFacebookInfoResponder : public LLHTTPClient::Responder
+void LLFacebookConnect::facebookConnectInfoCoro()
{
- LOG_CLASS(LLFacebookInfoResponder);
-public:
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- /* virtual */ void httpSuccess()
- {
- LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL;
- LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL;
- LLFacebookConnect::instance().storeInfo(getContent());
- }
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- 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"));
- }
- }
-};
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/info", true), httpOpts, get_headers());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFacebookWeb(location);
+ }
+ }
+ else if (!status)
+ {
+ LL_WARNS("FacebookConnect") << "Facebook Info failed: " << status.toString() << LL_ENDL;
+ log_facebook_connect_error("Info", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
+ {
+ LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL;
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ storeInfo(result);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFacebookFriendsResponder : public LLHTTPClient::Responder
+void LLFacebookConnect::facebookConnectFriendsCoro()
{
- LOG_CLASS(LLFacebookFriendsResponder);
-public:
-
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL;
- LLFacebookConnect::instance().storeContent(getContent());
- }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- 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("Friends", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/friends", true), httpOpts, get_headers());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFacebookWeb(location);
+ }
+ }
+ else if (!status)
+ {
+ LL_WARNS("FacebookConnect") << "Facebook Friends failed: " << status.toString() << LL_ENDL;
+ log_facebook_connect_error("Info", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
+ {
+ LL_INFOS("FacebookConnect") << "Facebook: Friends received" << LL_ENDL;
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ LLSD content = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT];
+ storeContent(content);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
@@ -439,40 +541,32 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b
void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state)
{
- LLSD body;
- if (!auth_code.empty())
- {
- body["code"] = auth_code;
- }
- if (!auth_state.empty())
- {
- body["state"] = auth_state;
- }
-
- LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder());
+ setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);
+
+ LLCoros::instance().launch("LLFacebookConnect::facebookConnectCoro",
+ boost::bind(&LLFacebookConnect::facebookConnectCoro, this, auth_code, auth_state));
}
void LLFacebookConnect::disconnectFromFacebook()
{
- LLHTTPClient::del(getFacebookConnectURL("/connection"), new LLFacebookDisconnectResponder());
+ LLCoros::instance().launch("LLFacebookConnect::facebookDisconnectCoro",
+ boost::bind(&LLFacebookConnect::facebookDisconnectCoro, this));
}
void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect),
- LLSD(), timeout, follow_redirects);
+ setConnectionState(LLFacebookConnect::FB_DISCONNECTING);
+
+ LLCoros::instance().launch("LLFacebookConnect::facebookConnectedCheckCoro",
+ boost::bind(&LLFacebookConnect::facebookConnectedCheckCoro, this, auto_connect));
}
void LLFacebookConnect::loadFacebookInfo()
{
if(mRefreshInfo)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getFacebookConnectURL("/info", true), new LLFacebookInfoResponder(),
- LLSD(), timeout, follow_redirects);
+ LLCoros::instance().launch("LLFacebookConnect::facebookConnectInfoCoro",
+ boost::bind(&LLFacebookConnect::facebookConnectInfoCoro, this));
}
}
@@ -480,15 +574,16 @@ void LLFacebookConnect::loadFacebookFriends()
{
if(mRefreshContent)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getFacebookConnectURL("/friends", true), new LLFacebookFriendsResponder(),
- LLSD(), timeout, follow_redirects);
+ LLCoros::instance().launch("LLFacebookConnect::facebookConnectFriendsCoro",
+ boost::bind(&LLFacebookConnect::facebookConnectFriendsCoro, this));
}
}
-void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& image, const std::string& message)
+void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name,
+ const std::string& description, const std::string& image, const std::string& message)
{
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
LLSD body;
if (!location.empty())
{
@@ -511,80 +606,39 @@ void LLFacebookConnect::postCheckin(const std::string& location, const std::stri
body["message"] = message;
}
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder());
+ LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro",
+ boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/checkin", body));
}
void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::string& caption)
{
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
LLSD body;
body["image"] = image_url;
body["caption"] = caption;
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::post(getFacebookConnectURL("/share/photo", true), body, new LLFacebookShareResponder());
+ LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro",
+ boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/photo", body));
}
void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption)
{
- std::string imageFormat;
- if (dynamic_cast<LLImagePNG*>(image.get()))
- {
- imageFormat = "png";
- }
- else if (dynamic_cast<LLImageJPEG*>(image.get()))
- {
- imageFormat = "jpg";
- }
- else
- {
- LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL;
- return;
- }
-
- // All this code is mostly copied from LLWebProfile::post()
- const std::string boundary = "----------------------------0123abcdefab";
-
- LLSD headers;
- headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
-
- std::ostringstream body;
-
- // *NOTE: The order seems to matter.
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"caption\"\r\n\r\n"
- << caption << "\r\n";
-
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
- << "Content-Type: image/" << imageFormat << "\r\n\r\n";
-
- // Insert the image data.
- // *FIX: Treating this as a string will probably screw it up ...
- U8* image_data = image->getData();
- for (S32 i = 0; i < image->getDataSize(); ++i)
- {
- body << image_data[i];
- }
+ setConnectionState(LLFacebookConnect::FB_POSTING);
- body << "\r\n--" << boundary << "--\r\n";
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = body.str().size();
- U8 *data = new U8[size];
- memcpy(data, body.str().data(), size);
-
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::postRaw(getFacebookConnectURL("/share/photo", true), data, size, new LLFacebookShareResponder(), headers);
+ LLCoros::instance().launch("LLFacebookConnect::facebookShareImageCoro",
+ boost::bind(&LLFacebookConnect::facebookShareImageCoro, this, "/share/photo", image, caption));
}
void LLFacebookConnect::updateStatus(const std::string& message)
{
LLSD body;
body["message"] = message;
-
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::post(getFacebookConnectURL("/share/wall", true), body, new LLFacebookShareResponder());
+
+ setConnectionState(LLFacebookConnect::FB_POSTING);
+
+ LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro",
+ boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/wall", body));
}
void LLFacebookConnect::storeInfo(const LLSD& info)
diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h
index c157db2178..2a2cdb5499 100644
--- a/indra/newview/llfacebookconnect.h
+++ b/indra/newview/llfacebookconnect.h
@@ -30,6 +30,8 @@
#include "llsingleton.h"
#include "llimage.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLEventPump;
@@ -101,6 +103,15 @@ private:
static boost::scoped_ptr<LLEventPump> sStateWatcher;
static boost::scoped_ptr<LLEventPump> sInfoWatcher;
static boost::scoped_ptr<LLEventPump> sContentWatcher;
+
+ bool testShareStatus(LLSD &results);
+ void facebookConnectCoro(std::string authCode, std::string authState);
+ void facebookConnectedCheckCoro(bool autoConnect);
+ void facebookDisconnectCoro();
+ void facebookShareCoro(std::string route, LLSD share);
+ void facebookShareImageCoro(std::string route, LLPointer<LLImageFormatted> image, std::string caption);
+ void facebookConnectInfoCoro();
+ void facebookConnectFriendsCoro();
};
#endif // LL_LLFACEBOOKCONNECT_H
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index ea39f812fd..f08064d9b5 100755
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -40,7 +40,6 @@
#include "llappviewer.h"
#include "llbufferstream.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llviewercontrol.h"
#include "llworld.h"
@@ -55,6 +54,7 @@
#include "llviewershadermgr.h"
#include "llstring.h"
#include "stringize.h"
+#include "llcorehttputil.h"
#if LL_WINDOWS
#include "lldxhardware.h"
@@ -492,95 +492,70 @@ bool LLFeatureManager::loadGPUClass()
return true; // indicates that a gpu value was established
}
-
-// responder saves table into file
-class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
+void LLFeatureManager::fetchFeatureTableCoro(std::string tableName)
{
- LOG_CLASS(LLHTTPFeatureTableResponder);
-public:
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FeatureManagerHTTPTable", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLHTTPFeatureTableResponder(std::string filename) :
- mFilename(filename)
- {
- }
+ const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable");
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- if (isGoodStatus())
- {
- // write to file
-
- LL_INFOS() << "writing feature table to " << mFilename << LL_ENDL;
-
- S32 file_size = buffer->countAfter(channels.in(), NULL);
- if (file_size > 0)
- {
- // read from buffer
- U8* copy_buffer = new U8[file_size];
- buffer->readAfter(channels.in(), NULL, copy_buffer, file_size);
-
- // write to file
- LLAPRFile out(mFilename, LL_APR_WB);
- out.write(copy_buffer, file_size);
- 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;
- }
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
- }
-
-private:
- std::string mFilename;
-};
-
-void fetch_feature_table(std::string table)
-{
- const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable");
#if LL_WINDOWS
- std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
- std::string filename;
- if (os_string.find("Microsoft Windows XP") == 0)
- {
- filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str());
- }
- else
- {
- filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str());
- }
+ std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
+ std::string filename;
+
+ if (os_string.find("Microsoft Windows XP") == 0)
+ {
+ filename = llformat(tableName.c_str(), "_xp", LLVersionInfo::getVersion().c_str());
+ }
+ else
+ {
+ filename = llformat(tableName.c_str(), "", LLVersionInfo::getVersion().c_str());
+ }
#else
- const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
+ const std::string filename = llformat(tableName.c_str(), LLVersionInfo::getVersion().c_str());
#endif
- const std::string url = base + "/" + filename;
+ std::string url = base + "/" + filename;
+ // testing url below
+ //url = "http://viewer-settings.secondlife.com/featuretable.2.1.1.208406.txt";
+ const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
- const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
- LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL;
-
- LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
-}
+ LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL;
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status)
+ { // There was a newer feature table on the server. We've grabbed it and now should write it.
+ // write to file
+ const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary();
+ LL_INFOS() << "writing feature table to " << path << LL_ENDL;
+
+ S32 size = raw.size();
+ if (size > 0)
+ {
+ // write to file
+ LLAPRFile out(path, LL_APR_WB);
+ out.write(raw.data(), size);
+ out.close();
+ }
+ }
+}
// fetch table(s) from a website (S3)
void LLFeatureManager::fetchHTTPTables()
{
- fetch_feature_table(FEATURE_TABLE_VER_FILENAME);
+ LLCoros::instance().launch("LLFeatureManager::fetchFeatureTableCoro",
+ boost::bind(&LLFeatureManager::fetchFeatureTableCoro, this, FEATURE_TABLE_VER_FILENAME));
}
-
void LLFeatureManager::cleanupFeatureTables()
{
std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer());
diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h
index 69078ccc21..12ea691b49 100755
--- a/indra/newview/llfeaturemanager.h
+++ b/indra/newview/llfeaturemanager.h
@@ -32,6 +32,8 @@
#include "llsingleton.h"
#include "llstring.h"
#include <map>
+#include "llcoros.h"
+#include "lleventcoro.h"
typedef enum EGPUClass
{
@@ -164,6 +166,7 @@ protected:
void initBaseMask();
+ void fetchFeatureTableCoro(std::string name);
std::map<std::string, LLFeatureList *> mMaskList;
std::set<std::string> mSkippedFeatures;
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index ef50594feb..a7236d1778 100755
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -40,6 +40,10 @@
#include "llwindowsdl.h" // for some X/GTK utils to help with filepickers
#endif // LL_SDL
+#if LL_LINUX || LL_SOLARIS
+#include "llhttpconstants.h" // file picker uses some of thes constants on Linux
+#endif
+
//
// Globals
//
diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp
index b75660ea00..c0ca5b8cf8 100644
--- a/indra/newview/llflickrconnect.cpp
+++ b/indra/newview/llflickrconnect.cpp
@@ -32,7 +32,6 @@
#include "llagent.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcommandhandler.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llurlaction.h"
#include "llimagepng.h"
@@ -43,6 +42,7 @@
#include "llfloaterwebcontent.h"
#include "llfloaterreg.h"
+#include "llcorehttputil.h"
boost::scoped_ptr<LLEventPump> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState"));
boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo"));
@@ -67,228 +67,322 @@ void toast_user_for_flickr_success()
///////////////////////////////////////////////////////////////////////////////
//
-class LLFlickrConnectResponder : public LLHTTPClient::Responder
+void LLFlickrConnect::flickrConnectCoro(std::string requestToken, std::string oauthVerifier)
{
- LOG_CLASS(LLFlickrConnectResponder);
-public:
-
- LLFlickrConnectResponder()
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD body;
+ if (!requestToken.empty())
+ body["request_token"] = requestToken;
+ if (!oauthVerifier.empty())
+ body["oauth_verifier"] = oauthVerifier;
+
+ setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+
+ LLSD result = httpAdapter->putAndSuspend(httpRequest, getFlickrConnectURL("/connection"), body, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if ( status == LLCore::HttpStatus(HTTP_FOUND) )
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFlickrWeb(location);
+ }
+ }
+ else
+ {
+ LL_WARNS("FlickrConnect") << "Connection failed " << status.toString() << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+ log_flickr_connect_error("Connect", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ }
+ else
{
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+ LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
}
-
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
- }
-
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse()
- << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- else
- {
- LLFlickrConnect::instance().openFlickrWeb(location);
- }
- }
- else
- {
- LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
- const LLSD& content = getContent();
- log_flickr_connect_error("Connect", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFlickrShareResponder : public LLHTTPClient::Responder
+bool LLFlickrConnect::testShareStatus(LLSD &result)
{
- LOG_CLASS(LLFlickrShareResponder);
-public:
-
- LLFlickrShareResponder()
- {
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTING);
- }
-
- /* virtual */ void httpSuccess()
- {
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status)
+ return true;
+
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFlickrWeb(location);
+ }
+ }
+ if (status == LLCore::HttpStatus(HTTP_NOT_FOUND))
+ {
+ LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL;
+ connectToFlickr();
+ }
+ else
+ {
+ LL_WARNS("FlickrConnect") << "HTTP Status error " << status.toString() << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED);
+ log_flickr_connect_error("Share", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ return false;
+}
+
+void LLFlickrConnect::flickrShareCoro(LLSD share)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), share, httpOpts);
+
+ if (testShareStatus(result))
+ {
toast_user_for_flickr_success();
- LL_DEBUGS("FlickrConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTED);
- }
-
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse()
- << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- else
- {
- LLFlickrConnect::instance().openFlickrWeb(location);
- }
- }
- else if ( HTTP_NOT_FOUND == getStatus() )
- {
- LLFlickrConnect::instance().connectToFlickr();
- }
- else
- {
- LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED);
- const LLSD& content = getContent();
- log_flickr_connect_error("Share", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_POSTED);
+ }
+
+}
+
+void LLFlickrConnect::flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ std::string imageFormat;
+ if (dynamic_cast<LLImagePNG*>(image.get()))
+ {
+ imageFormat = "png";
+ }
+ else if (dynamic_cast<LLImageJPEG*>(image.get()))
+ {
+ imageFormat = "jpg";
+ }
+ else
+ {
+ LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL;
+ return;
+ }
+
+ // All this code is mostly copied from LLWebProfile::post()
+ const std::string boundary = "----------------------------0123abcdefab";
+
+ std::string contentType = "multipart/form-data; boundary=" + boundary;
+ httpHeaders->append("Content-Type", contentType.c_str());
+
+ LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); //
+ LLCore::BufferArrayStream body(raw.get());
+
+ // *NOTE: The order seems to matter.
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"title\"\r\n\r\n"
+ << title << "\r\n";
+
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"description\"\r\n\r\n"
+ << description << "\r\n";
+
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n"
+ << tags << "\r\n";
+
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n"
+ << safetyLevel << "\r\n";
+
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
+ << "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+ // Insert the image data.
+ // *FIX: Treating this as a string will probably screw it up ...
+ U8* image_data = image->getData();
+ for (S32 i = 0; i < image->getDataSize(); ++i)
+ {
+ body << image_data[i];
+ }
+
+ body << "\r\n--" << boundary << "--\r\n";
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), raw, httpOpts, httpHeaders);
+
+ if (testShareStatus(result))
+ {
+ toast_user_for_flickr_success();
+ LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_POSTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFlickrDisconnectResponder : public LLHTTPClient::Responder
+void LLFlickrConnect::flickrDisconnectCoro()
{
- LOG_CLASS(LLFlickrDisconnectResponder);
-public:
-
- LLFlickrDisconnectResponder()
- {
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING);
- }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- void setUserDisconnected()
- {
- // Clear data
- LLFlickrConnect::instance().clearInfo();
+ setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING);
+ httpOpts->setFollowRedirects(false);
- //Notify state change
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
- }
+ LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFlickrConnectURL("/connection"), httpOpts);
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL;
- setUserDisconnected();
- }
-
- /* virtual */ void httpFailure()
- {
- //User not found so already disconnected
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- LL_DEBUGS("FlickrConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;
- setUserDisconnected();
- }
- else
- {
- LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED);
- const LLSD& content = getContent();
- log_flickr_connect_error("Disconnect", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND)))
+ {
+ LL_WARNS("FlickrConnect") << "Disconnect failed!" << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED);
+
+ log_flickr_connect_error("Disconnect", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
+ {
+ LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << LL_ENDL;
+ clearInfo();
+ setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFlickrConnectedResponder : public LLHTTPClient::Responder
+void LLFlickrConnect::flickrConnectedCoro(bool autoConnect)
{
- LOG_CLASS(LLFlickrConnectedResponder);
-public:
-
- LLFlickrConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/connection", true), httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
{
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS);
+ if (status == LLCore::HttpStatus(HTTP_NOT_FOUND))
+ {
+ LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL;
+ if (autoConnect)
+ {
+ connectToFlickr();
+ }
+ else
+ {
+ setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
+ }
+ }
+ else
+ {
+ LL_WARNS("FlickrConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL;
+
+ setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
+ log_flickr_connect_error("Connected", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ }
+ else
+ {
+ LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL;
+ setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
}
-
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);
- }
-
- /* virtual */ void httpFailure()
- {
- // show the facebook login page if not connected yet
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- LL_DEBUGS("FlickrConnect") << "Not connected. " << dumpResponse() << LL_ENDL;
- if (mAutoConnect)
- {
- LLFlickrConnect::instance().connectToFlickr();
- }
- else
- {
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED);
- }
- }
- else
- {
- LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED);
- const LLSD& content = getContent();
- log_flickr_connect_error("Connected", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-
-private:
- bool mAutoConnect;
-};
+
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLFlickrInfoResponder : public LLHTTPClient::Responder
+void LLFlickrConnect::flickrInfoCoro()
{
- LOG_CLASS(LLFlickrInfoResponder);
-public:
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- /* virtual */ void httpSuccess()
- {
- LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL;
- LL_DEBUGS("FlickrConnect") << "Getting Flickr info successful. " << dumpResponse() << LL_ENDL;
- LLFlickrConnect::instance().storeInfo(getContent());
- }
-
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse()
- << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- else
- {
- LLFlickrConnect::instance().openFlickrWeb(location);
- }
- }
- else
- {
- LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL;
- const LLSD& content = getContent();
- log_flickr_connect_error("Info", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/info", true), httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openFlickrWeb(location);
+ }
+ }
+ else if (!status)
+ {
+ LL_WARNS("FlickrConnect") << "Flickr Info failed: " << status.toString() << LL_ENDL;
+ log_flickr_connect_error("Info", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
+ {
+ LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL;
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ storeInfo(result);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
@@ -341,36 +435,28 @@ std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool
void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier)
{
- LLSD body;
- if (!request_token.empty())
- body["request_token"] = request_token;
- if (!oauth_verifier.empty())
- body["oauth_verifier"] = oauth_verifier;
-
- LLHTTPClient::put(getFlickrConnectURL("/connection"), body, new LLFlickrConnectResponder());
+ LLCoros::instance().launch("LLFlickrConnect::flickrConnectCoro",
+ boost::bind(&LLFlickrConnect::flickrConnectCoro, this, request_token, oauth_verifier));
}
void LLFlickrConnect::disconnectFromFlickr()
{
- LLHTTPClient::del(getFlickrConnectURL("/connection"), new LLFlickrDisconnectResponder());
+ LLCoros::instance().launch("LLFlickrConnect::flickrDisconnectCoro",
+ boost::bind(&LLFlickrConnect::flickrDisconnectCoro, this));
}
void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getFlickrConnectURL("/connection", true), new LLFlickrConnectedResponder(auto_connect),
- LLSD(), timeout, follow_redirects);
+ LLCoros::instance().launch("LLFlickrConnect::flickrConnectedCoro",
+ boost::bind(&LLFlickrConnect::flickrConnectedCoro, this, auto_connect));
}
void LLFlickrConnect::loadFlickrInfo()
{
if(mRefreshInfo)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getFlickrConnectURL("/info", true), new LLFlickrInfoResponder(),
- LLSD(), timeout, follow_redirects);
+ LLCoros::instance().launch("LLFlickrConnect::flickrInfoCoro",
+ boost::bind(&LLFlickrConnect::flickrInfoCoro, this));
}
}
@@ -382,74 +468,20 @@ void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::strin
body["description"] = description;
body["tags"] = tags;
body["safety_level"] = safety_level;
-
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::post(getFlickrConnectURL("/share/photo", true), body, new LLFlickrShareResponder());
+
+ setConnectionState(LLFlickrConnect::FLICKR_POSTING);
+
+ LLCoros::instance().launch("LLFlickrConnect::flickrShareCoro",
+ boost::bind(&LLFlickrConnect::flickrShareCoro, this, body));
}
void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level)
{
- std::string imageFormat;
- if (dynamic_cast<LLImagePNG*>(image.get()))
- {
- imageFormat = "png";
- }
- else if (dynamic_cast<LLImageJPEG*>(image.get()))
- {
- imageFormat = "jpg";
- }
- else
- {
- LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL;
- return;
- }
-
- // All this code is mostly copied from LLWebProfile::post()
- const std::string boundary = "----------------------------0123abcdefab";
-
- LLSD headers;
- headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
-
- std::ostringstream body;
-
- // *NOTE: The order seems to matter.
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"title\"\r\n\r\n"
- << title << "\r\n";
-
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"description\"\r\n\r\n"
- << description << "\r\n";
-
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n"
- << tags << "\r\n";
-
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n"
- << safety_level << "\r\n";
-
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
- << "Content-Type: image/" << imageFormat << "\r\n\r\n";
-
- // Insert the image data.
- // *FIX: Treating this as a string will probably screw it up ...
- U8* image_data = image->getData();
- for (S32 i = 0; i < image->getDataSize(); ++i)
- {
- body << image_data[i];
- }
-
- body << "\r\n--" << boundary << "--\r\n";
+ setConnectionState(LLFlickrConnect::FLICKR_POSTING);
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = body.str().size();
- U8 *data = new U8[size];
- memcpy(data, body.str().data(), size);
-
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::postRaw(getFlickrConnectURL("/share/photo", true), data, size, new LLFlickrShareResponder(), headers);
+ LLCoros::instance().launch("LLFlickrConnect::flickrShareImageCoro",
+ boost::bind(&LLFlickrConnect::flickrShareImageCoro, this, image,
+ title, description, tags, safety_level));
}
void LLFlickrConnect::storeInfo(const LLSD& info)
diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h
index b127e6e104..0155804da0 100644
--- a/indra/newview/llflickrconnect.h
+++ b/indra/newview/llflickrconnect.h
@@ -30,6 +30,8 @@
#include "llsingleton.h"
#include "llimage.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLEventPump;
@@ -93,6 +95,15 @@ private:
static boost::scoped_ptr<LLEventPump> sStateWatcher;
static boost::scoped_ptr<LLEventPump> sInfoWatcher;
static boost::scoped_ptr<LLEventPump> sContentWatcher;
+
+ bool testShareStatus(LLSD &result);
+ void flickrConnectCoro(std::string requestToken, std::string oauthVerifier);
+ void flickrShareCoro(LLSD share);
+ void flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel);
+ void flickrDisconnectCoro();
+ void flickrConnectedCoro(bool autoConnect);
+ void flickrInfoCoro();
+
};
#endif // LL_LLFLICKRCONNECT_H
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index e71daa6067..7bd01f6beb 100755
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -48,7 +48,6 @@
// Linden library includes
#include "llaudioengine.h"
#include "llbutton.h"
-#include "llcurl.h"
#include "llglheaders.h"
#include "llfloater.h"
#include "llfloaterreg.h"
@@ -61,6 +60,7 @@
#include "stringize.h"
#include "llsdutil_math.h"
#include "lleventapi.h"
+#include "llcorehttputil.h"
#if LL_WINDOWS
#include "lldxhardware.h"
@@ -70,18 +70,6 @@ extern LLMemoryInfo gSysMemory;
extern U32 gPacketsIn;
///----------------------------------------------------------------------------
-/// Class LLServerReleaseNotesURLFetcher
-///----------------------------------------------------------------------------
-class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLServerReleaseNotesURLFetcher);
-public:
- static void startFetch();
-private:
- /* virtual */ void httpCompleted();
-};
-
-///----------------------------------------------------------------------------
/// Class LLFloaterAbout
///----------------------------------------------------------------------------
class LLFloaterAbout
@@ -102,6 +90,9 @@ public:
private:
void setSupportText(const std::string& server_release_notes_url);
+
+ static void startFetchServerReleaseNotes();
+ static void handleServerReleaseNotes(LLSD results);
};
@@ -138,7 +129,7 @@ BOOL LLFloaterAbout::postBuild()
{
// start fetching server release notes URL
setSupportText(LLTrans::getString("RetrievingData"));
- LLServerReleaseNotesURLFetcher::startFetch();
+ startFetchServerReleaseNotes();
}
else // not logged in
{
@@ -201,6 +192,50 @@ LLSD LLFloaterAbout::getInfo()
return LLAppViewer::instance()->getViewerInfo();
}
+/*static*/
+void LLFloaterAbout::startFetchServerReleaseNotes()
+{
+ LLViewerRegion* region = gAgent.getRegion();
+ if (!region) return;
+
+ // We cannot display the URL returned by the ServerReleaseNotes capability
+ // because opening it in an external browser will trigger a warning about untrusted
+ // SSL certificate.
+ // So we query the URL ourselves, expecting to find
+ // an URL suitable for external browsers in the "Location:" HTTP header.
+ std::string cap_url = region->getCapability("ServerReleaseNotes");
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(cap_url,
+ &LLFloaterAbout::handleServerReleaseNotes, &LLFloaterAbout::handleServerReleaseNotes);
+
+}
+
+/*static*/
+void LLFloaterAbout::handleServerReleaseNotes(LLSD results)
+{
+// LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about");
+// if (floater_about)
+// {
+ LLSD http_headers;
+ if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS))
+ {
+ LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+ }
+ else
+ {
+ http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+ }
+
+ std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString();
+ if (location.empty())
+ {
+ location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL");
+ }
+ LLAppViewer::instance()->setServerReleaseNotesURL(location);
+// }
+}
+
class LLFloaterAboutListener: public LLEventAPI
{
public:
@@ -265,35 +300,3 @@ void LLFloaterAboutUtil::registerFloater()
}
-///----------------------------------------------------------------------------
-/// Class LLServerReleaseNotesURLFetcher implementation
-///----------------------------------------------------------------------------
-// static
-void LLServerReleaseNotesURLFetcher::startFetch()
-{
- LLViewerRegion* region = gAgent.getRegion();
- if (!region) return;
-
- // We cannot display the URL returned by the ServerReleaseNotes capability
- // because opening it in an external browser will trigger a warning about untrusted
- // SSL certificate.
- // So we query the URL ourselves, expecting to find
- // an URL suitable for external browsers in the "Location:" HTTP header.
- std::string cap_url = region->getCapability("ServerReleaseNotes");
- LLHTTPClient::get(cap_url, new LLServerReleaseNotesURLFetcher);
-}
-
-// virtual
-void LLServerReleaseNotesURLFetcher::httpCompleted()
-{
- LL_DEBUGS("ServerReleaseNotes") << dumpResponse()
- << " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
-
- std::string location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL");
- }
- LLAppViewer::instance()->setServerReleaseNotesURL(location);
-}
-
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index b661fed276..56619e818a 100755
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -57,6 +57,7 @@
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "lltrans.h"
+#include "llcorehttputil.h"
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
@@ -361,7 +362,10 @@ void LLFloaterAuction::doResetParcel()
LL_INFOS() << "Sending parcel update to reset for auction via capability to: "
<< mParcelUpdateCapUrl << LL_ENDL;
- LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::Responder());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(mParcelUpdateCapUrl, body,
+ "Parcel reset for auction",
+ "Parcel not set for auction.");
// Send a message to clear the object return time
LLMessageSystem *msg = gMessageSystem;
@@ -490,7 +494,10 @@ void LLFloaterAuction::doSellToAnyone()
LL_INFOS() << "Sending parcel update to sell to anyone for L$1 via capability to: "
<< mParcelUpdateCapUrl << LL_ENDL;
- LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::Responder());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(mParcelUpdateCapUrl, body,
+ "Parcel set as sell to everyone.",
+ "Parcel sell to everyone failed.");
// clean up floater, and get out
cleanupAndClose();
diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp
index 6e56e929df..5830f2f711 100755
--- a/indra/newview/llfloaterautoreplacesettings.cpp
+++ b/indra/newview/llfloaterautoreplacesettings.cpp
@@ -36,7 +36,6 @@
#include "llcolorswatch.h"
#include "llcombobox.h"
#include "llview.h"
-#include "llhttpclient.h"
#include "llbufferstream.h"
#include "llcheckboxctrl.h"
#include "llviewercontrol.h"
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 566a3c9cd3..72892b47a4 100755
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -42,7 +42,6 @@
#include "llavatarnamecache.h" // IDEVO
#include "llbutton.h"
#include "llcachename.h"
-#include "llhttpclient.h" // IDEVO
#include "lllineeditor.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
@@ -52,6 +51,7 @@
#include "llfocusmgr.h"
#include "lldraghandle.h"
#include "message.h"
+#include "llcorehttputil.h"
//#include "llsdserialize.h"
@@ -456,39 +456,33 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const
return FALSE;
}
-class LLAvatarPickerResponder : public LLHTTPClient::Responder
+/*static*/
+void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::string name)
{
- LOG_CLASS(LLAvatarPickerResponder);
-public:
- LLUUID mQueryID;
- std::string mName;
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { }
+ LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
-protected:
- /*virtual*/ void httpCompleted()
- {
- //std::ostringstream ss;
- //LLSDSerialize::toPrettyXML(content, ss);
- //LL_INFOS() << ss.str() << LL_ENDL;
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST)))
+ {
+ LLFloaterAvatarPicker* floater =
+ LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name);
+ if (floater)
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ floater->processResponse(queryID, result);
+ }
+ }
+}
- // in case of invalid characters, the avatar picker returns a 400
- // just set it to process so it displays 'not found'
- if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST)
- {
- LLFloaterAvatarPicker* floater =
- LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName);
- if (floater)
- {
- floater->processResponse(mQueryID, getContent());
- }
- }
- else
- {
- LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL;
- }
- }
-};
void LLFloaterAvatarPicker::find()
{
@@ -517,7 +511,9 @@ void LLFloaterAvatarPicker::find()
std::replace(text.begin(), text.end(), '.', ' ');
url += LLURI::escape(text);
LL_INFOS() << "avatar picker " << url << LL_ENDL;
- LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID, getKey().asString()));
+
+ LLCoros::instance().launch("LLFloaterAvatarPicker::findCoro",
+ boost::bind(&LLFloaterAvatarPicker::findCoro, url, mQueryID, getKey().asString()));
}
else
{
diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h
index ed3e51c56f..fbee61b054 100755
--- a/indra/newview/llfloateravatarpicker.h
+++ b/indra/newview/llfloateravatarpicker.h
@@ -28,6 +28,8 @@
#define LLFLOATERAVATARPICKER_H
#include "llfloater.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
#include <vector>
@@ -84,6 +86,7 @@ private:
void populateFriend();
BOOL visibleItemsSelected() const; // Returns true if any items in the current tab are selected.
+ static void findCoro(std::string url, LLUUID mQueryID, std::string mName);
void find();
void setAllowMultiple(BOOL allow_multiple);
LLScrollListCtrl* getActiveList();
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index 669ffa7c59..e5df417ca9 100755
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -992,20 +992,16 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata)
{
std::string name = floaterp->getChild<LLUICtrl>("name_form")->getValue().asString();
std::string desc = floaterp->getChild<LLUICtrl>("description_form")->getValue().asString();
- LLAssetStorage::LLStoreAssetCallback callback = NULL;
S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
- void *userdata = NULL;
- upload_new_resource(floaterp->mTransactionID, // tid
- LLAssetType::AT_ANIMATION,
- name,
- desc,
- 0,
- LLFolderType::FT_NONE,
- LLInventoryType::IT_ANIMATION,
- LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"),
- name,
- callback, expected_upload_cost, userdata);
+ LLResourceUploadInfo::ptr_t assetUpdloadInfo(new LLResourceUploadInfo(
+ floaterp->mTransactionID, LLAssetType::AT_ANIMATION,
+ name, desc, 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost));
+
+ upload_new_resource(assetUpdloadInfo);
}
else
{
diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp
deleted file mode 100755
index 596e8c0dbe..0000000000
--- a/indra/newview/llfloaterdisplayname.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * @file llfloaterdisplayname.cpp
- * @author Leyla Farazha
- * @brief Implementation of the LLFloaterDisplayName class.
- *
- * $LicenseInfo:firstyear=2002&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 "llfloaterreg.h"
-#include "llfloater.h"
-
-#include "llnotificationsutil.h"
-#include "llviewerdisplayname.h"
-
-#include "llnotifications.h"
-#include "llfloaterdisplayname.h"
-#include "llavatarnamecache.h"
-
-#include "llagent.h"
-
-
-class LLFloaterDisplayName : public LLFloater
-{
-public:
- LLFloaterDisplayName(const LLSD& key);
- virtual ~LLFloaterDisplayName() { }
- /*virtual*/ BOOL postBuild();
- void onSave();
- void onReset();
- void onCancel();
- /*virtual*/ void onOpen(const LLSD& key);
-
-private:
-
- void onCacheSetName(bool success,
- const std::string& reason,
- const LLSD& content);
-};
-
-LLFloaterDisplayName::LLFloaterDisplayName(const LLSD& key) :
- LLFloater(key)
-{
-}
-
-void LLFloaterDisplayName::onOpen(const LLSD& key)
-{
- getChild<LLUICtrl>("display_name_editor")->clear();
- getChild<LLUICtrl>("display_name_confirm")->clear();
-
- LLAvatarName av_name;
- LLAvatarNameCache::get(gAgent.getID(), &av_name);
-
- F64 now_secs = LLDate::now().secondsSinceEpoch();
-
- if (now_secs < av_name.mNextUpdate)
- {
- // ...can't update until some time in the future
- F64 next_update_local_secs =
- av_name.mNextUpdate - LLStringOps::getLocalTimeOffset();
- LLDate next_update_local(next_update_local_secs);
- // display as "July 18 12:17 PM"
- std::string next_update_string =
- next_update_local.toHTTPDateString("%B %d %I:%M %p");
- getChild<LLUICtrl>("lockout_text")->setTextArg("[TIME]", next_update_string);
- getChild<LLUICtrl>("lockout_text")->setVisible(true);
- getChild<LLUICtrl>("save_btn")->setEnabled(false);
- getChild<LLUICtrl>("display_name_editor")->setEnabled(false);
- getChild<LLUICtrl>("display_name_confirm")->setEnabled(false);
- getChild<LLUICtrl>("cancel_btn")->setFocus(TRUE);
-
- }
- else
- {
- getChild<LLUICtrl>("lockout_text")->setVisible(false);
- getChild<LLUICtrl>("save_btn")->setEnabled(true);
- getChild<LLUICtrl>("display_name_editor")->setEnabled(true);
- getChild<LLUICtrl>("display_name_confirm")->setEnabled(true);
-
- }
-}
-
-BOOL LLFloaterDisplayName::postBuild()
-{
- getChild<LLUICtrl>("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this));
- getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this));
- getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this));
-
- center();
-
- return TRUE;
-}
-
-void LLFloaterDisplayName::onCacheSetName(bool success,
- const std::string& reason,
- const LLSD& content)
-{
- if (success)
- {
- // Inform the user that the change took place, but will take a while
- // to percolate.
- LLSD args;
- args["DISPLAY_NAME"] = content["display_name"];
- LLNotificationsUtil::add("SetDisplayNameSuccess", args);
- return;
- }
-
- // Request failed, notify the user
- std::string error_tag = content["error_tag"].asString();
- LL_INFOS() << "set name failure error_tag " << error_tag << LL_ENDL;
-
- // We might have a localized string for this message
- // error_args will usually be empty from the server.
- if (!error_tag.empty()
- && LLNotifications::getInstance()->templateExists(error_tag))
- {
- LLNotificationsUtil::add(error_tag);
- return;
- }
-
- // The server error might have a localized message for us
- std::string lang_code = LLUI::getLanguage();
- LLSD error_desc = content["error_description"];
- if (error_desc.has( lang_code ))
- {
- LLSD args;
- args["MESSAGE"] = error_desc[lang_code].asString();
- LLNotificationsUtil::add("GenericAlert", args);
- return;
- }
-
- // No specific error, throw a generic one
- LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
-}
-
-void LLFloaterDisplayName::onCancel()
-{
- setVisible(false);
-}
-
-void LLFloaterDisplayName::onReset()
-{
- if (LLAvatarNameCache::hasNameLookupURL())
- {
- LLViewerDisplayName::set("",boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3));
- }
- else
- {
- LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
- }
-
- setVisible(false);
-}
-
-
-void LLFloaterDisplayName::onSave()
-{
- std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString();
- std::string display_name_confirm = getChild<LLUICtrl>("display_name_confirm")->getValue().asString();
-
- if (display_name_utf8.compare(display_name_confirm))
- {
- LLNotificationsUtil::add("SetDisplayNameMismatch");
- return;
- }
-
- const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes
- LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8);
- if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH)
- {
- LLSD args;
- args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH);
- LLNotificationsUtil::add("SetDisplayNameFailedLength", args);
- return;
- }
-
- if (LLAvatarNameCache::hasNameLookupURL())
- {
- LLViewerDisplayName::set(display_name_utf8,boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3));
- }
- else
- {
- LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
- }
-
- setVisible(false);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-// LLInspectObjectUtil
-//////////////////////////////////////////////////////////////////////////////
-void LLFloaterDisplayNameUtil::registerFloater()
-{
- LLFloaterReg::add("display_name", "floater_display_name.xml",
- &LLFloaterReg::build<LLFloaterDisplayName>);
-}
diff --git a/indra/newview/llfloaterdisplayname.h b/indra/newview/llfloaterdisplayname.h
deleted file mode 100755
index a00bf56712..0000000000
--- a/indra/newview/llfloaterdisplayname.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * @file llfloaterdisplayname.h
- *
- * $LicenseInfo:firstyear=2009&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 LLFLOATERDISPLAYNAME_H
-#define LLFLOATERDISPLAYNAME_H
-
-
-namespace LLFloaterDisplayNameUtil
-{
- // Register with LLFloaterReg
- void registerFloater();
-}
-
-
-
-#endif
diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp
index 197162487d..d44eb4310d 100644
--- a/indra/newview/llfloaterexperienceprofile.cpp
+++ b/indra/newview/llfloaterexperienceprofile.cpp
@@ -36,7 +36,6 @@
#include "llexpandabletextbox.h"
#include "llexperiencecache.h"
#include "llfloaterreg.h"
-#include "llhttpclient.h"
#include "lllayoutstack.h"
#include "lllineeditor.h"
#include "llnotificationsutil.h"
@@ -99,7 +98,7 @@ public:
if(params.size() != 2 || params[1].asString() != "profile")
return false;
- LLExperienceCache::get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
+ LLExperienceCache::instance().get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
return true;
}
@@ -131,175 +130,20 @@ LLFloaterExperienceProfile::~LLFloaterExperienceProfile()
}
-template<class T>
-class HandleResponder : public LLHTTPClient::Responder
-{
-public:
- HandleResponder(const LLHandle<T>& parent):mParent(parent){}
- LLHandle<T> mParent;
-
- virtual void httpFailure()
- {
- LL_WARNS() << "HandleResponder failed with code: " << getStatus() << ", reason: " << getReason() << LL_ENDL;
- }
-};
-
-class ExperienceUpdateResponder : public HandleResponder<LLFloaterExperienceProfile>
-{
-public:
- ExperienceUpdateResponder(const LLHandle<LLFloaterExperienceProfile>& parent):HandleResponder<LLFloaterExperienceProfile>(parent)
- {
- }
-
- virtual void httpSuccess()
- {
- LLFloaterExperienceProfile* parent=mParent.get();
- if(parent)
- {
- parent->onSaveComplete(getContent());
- }
- }
-};
-
-
-
-class ExperiencePreferencesResponder : public LLHTTPClient::Responder
-{
-public:
- ExperiencePreferencesResponder(const LLUUID& single = LLUUID::null):mId(single)
- {
- }
-
- bool sendSingle(const LLSD& content, const LLSD& permission, const char* name)
- {
- if(!content.has(name))
- return false;
-
- LLEventPump& pump = LLEventPumps::instance().obtain("experience_permission");
- const LLSD& list = content[name];
- LLSD::array_const_iterator it = list.beginArray();
- while(it != list.endArray())
- {
- if(it->asUUID() == mId)
- {
- LLSD message;
- message[it->asString()] = permission;
- message["experience"] = mId;
- pump.post(message);
- return true;
- }
- ++it;
- }
- return false;
- }
-
- bool hasPermission(const LLSD& content, const char* name)
- {
- if(!content.has(name))
- return false;
-
- const LLSD& list = content[name];
- LLSD::array_const_iterator it = list.beginArray();
- while(it != list.endArray())
- {
- if(it->asUUID() == mId)
- {
- return true;
- }
- ++it;
- }
- return false;
- }
-
- const char* getPermission(const LLSD& content)
- {
- if(hasPermission(content, "experiences"))
- {
- return "Allow";
- }
- else if(hasPermission(content, "blocked"))
- {
- return "Block";
- }
- return "Forget";
- }
-
-
- virtual void httpSuccess()
- {
- if(mId.notNull())
- {
- post(getPermission(getContent()));
- return;
- }
- LLEventPumps::instance().obtain("experience_permission").post(getContent());
- }
-
- void post( const char* perm )
- {
- LLSD experience;
- LLSD message;
- experience["permission"]=perm;
- message["experience"] = mId;
- message[mId.asString()] = experience;
- LLEventPumps::instance().obtain("experience_permission").post(message);
- }
-
-private:
- LLUUID mId;
-};
-
-
-class IsAdminResponder : public HandleResponder<LLFloaterExperienceProfile>
-{
-public:
- IsAdminResponder(const LLHandle<LLFloaterExperienceProfile>& parent):HandleResponder<LLFloaterExperienceProfile>(parent)
- {
- }
-
- virtual void httpSuccess()
- {
- LLFloaterExperienceProfile* parent = mParent.get();
- if(!parent)
- return;
-
- bool enabled = true;
- LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- {
- enabled = false;
- }
- else
- {
- std::string url=region->getCapability("UpdateExperience");
- if(url.empty())
- enabled = false;
- }
- if(enabled && getContent()["status"].asBoolean())
- {
- parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE);
- parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE);
- }
- }
-};
-
BOOL LLFloaterExperienceProfile::postBuild()
{
if (mExperienceId.notNull())
{
- LLExperienceCache::fetch(mExperienceId, true);
- LLExperienceCache::get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback,
+ LLExperienceCache::instance().fetch(mExperienceId, true);
+ LLExperienceCache::instance().get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback,
getDerivedHandle<LLFloaterExperienceProfile>(), _1));
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- std::string lookup_url=region->getCapability("IsExperienceAdmin");
- if(!lookup_url.empty())
- {
- LLHTTPClient::get(lookup_url+"?experience_id="+mExperienceId.asString(), new IsAdminResponder(getDerivedHandle<LLFloaterExperienceProfile>()));
- }
+ LLExperienceCache::instance().getExperienceAdmin(mExperienceId, boost::bind(
+ &LLFloaterExperienceProfile::experienceIsAdmin, getDerivedHandle<LLFloaterExperienceProfile>(), _1));
}
}
@@ -372,23 +216,13 @@ void LLFloaterExperienceProfile::onClickSave()
doSave(NOTHING);
}
-
void LLFloaterExperienceProfile::onClickPermission(const char* perm)
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
-
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(lookup_url.empty())
- return;
- LLSD permission;
- LLSD data;
- permission["permission"]=perm;
-
- data[mExperienceId.asString()]=permission;
- LLHTTPClient::put(lookup_url, data, new ExperiencePreferencesResponder(mExperienceId));
-
+ LLExperienceCache::instance().setExperiencePermission(mExperienceId, perm, boost::bind(
+ &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
@@ -398,11 +232,8 @@ void LLFloaterExperienceProfile::onClickForget()
if (!region)
return;
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(lookup_url.empty())
- return;
-
- LLHTTPClient::del(lookup_url+"?"+mExperienceId.asString(), new ExperiencePreferencesResponder(mExperienceId));
+ LLExperienceCache::instance().forgetExperiencePermission(mExperienceId, boost::bind(
+ &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
bool LLFloaterExperienceProfile::setMaturityString( U8 maturity, LLTextBox* child, LLComboBox* combo )
@@ -549,11 +380,8 @@ void LLFloaterExperienceProfile::refreshExperience( const LLSD& experience )
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(!lookup_url.empty())
- {
- LLHTTPClient::get(lookup_url+"?"+mExperienceId.asString(), new ExperiencePreferencesResponder(mExperienceId));
- }
+ LLExperienceCache::instance().getExperiencePermission(mExperienceId, boost::bind(
+ &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
}
@@ -733,15 +561,9 @@ void LLFloaterExperienceProfile::doSave( int success_action )
if (!region)
return;
- std::string url=region->getCapability("UpdateExperience");
- if(url.empty())
- return;
-
- mPackage.erase(LLExperienceCache::QUOTA);
- mPackage.erase(LLExperienceCache::EXPIRES);
- mPackage.erase(LLExperienceCache::AGENT_ID);
-
- LLHTTPClient::post(url, mPackage, new ExperienceUpdateResponder(getDerivedHandle<LLFloaterExperienceProfile>()));
+ LLExperienceCache::instance().updateExperience(mPackage, boost::bind(
+ &LLFloaterExperienceProfile::experienceUpdateResult,
+ getDerivedHandle<LLFloaterExperienceProfile>(), _1));
}
void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content )
@@ -799,8 +621,8 @@ void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content )
}
refreshExperience(*it);
- LLExperienceCache::insert(*it);
- LLExperienceCache::fetch(id, true);
+ LLExperienceCache::instance().insert(*it);
+ LLExperienceCache::instance().fetch(id, true);
if(mSaveCompleteAction==VIEW)
{
@@ -1002,3 +824,76 @@ void LLFloaterExperienceProfile::onReportExperience()
{
LLFloaterReporter::showFromExperience(mExperienceId);
}
+
+/*static*/
+bool LLFloaterExperienceProfile::hasPermission(const LLSD& content, const std::string &name, const LLUUID &test)
+{
+ if (!content.has(name))
+ return false;
+
+ const LLSD& list = content[name];
+ LLSD::array_const_iterator it = list.beginArray();
+ while (it != list.endArray())
+ {
+ if (it->asUUID() == test)
+ {
+ return true;
+ }
+ ++it;
+ }
+ return false;
+}
+
+/*static*/
+void LLFloaterExperienceProfile::experiencePermissionResults(LLUUID exprienceId, LLSD result)
+{
+ std::string permission("Forget");
+ if (hasPermission(result, "experiences", exprienceId))
+ permission = "Allow";
+ else if (hasPermission(result, "blocked", exprienceId))
+ permission = "Block";
+
+ LLSD experience;
+ LLSD message;
+ experience["permission"] = permission;
+ message["experience"] = exprienceId;
+ message[exprienceId.asString()] = experience;
+
+ LLEventPumps::instance().obtain("experience_permission").post(message);
+}
+
+/*static*/
+void LLFloaterExperienceProfile::experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result)
+{
+ LLFloaterExperienceProfile* parent = handle.get();
+ if (!parent)
+ return;
+
+ bool enabled = true;
+ LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ enabled = false;
+ }
+ else
+ {
+ std::string url = region->getCapability("UpdateExperience");
+ if (url.empty())
+ enabled = false;
+ }
+ if (enabled && result["status"].asBoolean())
+ {
+ parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE);
+ parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE);
+ }
+}
+
+/*static*/
+void LLFloaterExperienceProfile::experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result)
+{
+ LLFloaterExperienceProfile* parent = handle.get();
+ if (parent)
+ {
+ parent->onSaveComplete(result);
+ }
+}
diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h
index 78d54eb447..7a5ced546b 100644
--- a/indra/newview/llfloaterexperienceprofile.h
+++ b/indra/newview/llfloaterexperienceprofile.h
@@ -99,6 +99,12 @@ protected:
int mSaveCompleteAction;
bool mDirty;
bool mForceClose;
+
+private:
+ static bool hasPermission(const LLSD& content, const std::string &name, const LLUUID &test);
+ static void experiencePermissionResults(LLUUID exprienceId, LLSD result);
+ static void experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result);
+ static void experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result);
};
#endif // LL_LLFLOATEREXPERIENCEPROFILE_H
diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp
index 777dc382cd..fbe00beddd 100644
--- a/indra/newview/llfloaterexperiences.cpp
+++ b/indra/newview/llfloaterexperiences.cpp
@@ -32,7 +32,6 @@
#include "llevents.h"
#include "llexperiencecache.h"
#include "llfloaterregioninfo.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llpanelexperiencelog.h"
#include "llpanelexperiencepicker.h"
@@ -43,59 +42,6 @@
#define SHOW_RECENT_TAB (0)
-
-class LLExperienceListResponder : public LLHTTPClient::Responder
-{
-public:
- typedef std::map<std::string, std::string> NameMap;
- typedef boost::function<void(LLPanelExperiences*, const LLSD&)> Callback;
- LLExperienceListResponder(const LLHandle<LLFloaterExperiences>& parent, NameMap& nameMap, const std::string& errorMessage="ErrorMessage"):mParent(parent),mErrorMessage(errorMessage)
- {
- mNameMap.swap(nameMap);
- }
-
- Callback mCallback;
- LLHandle<LLFloaterExperiences> mParent;
- NameMap mNameMap;
- const std::string mErrorMessage;
- /*virtual*/ void httpSuccess()
- {
- if(mParent.isDead())
- return;
-
- LLFloaterExperiences* parent=mParent.get();
- LLTabContainer* tabs = parent->getChild<LLTabContainer>("xp_tabs");
-
- NameMap::iterator it = mNameMap.begin();
- while(it != mNameMap.end())
- {
- if(getContent().has(it->first))
- {
- LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it->second);
- if(tab)
- {
- const LLSD& ids = getContent()[it->first];
- tab->setExperienceList(ids);
- if(!mCallback.empty())
- {
- mCallback(tab, getContent());
- }
- }
- }
- ++it;
- }
- }
-
- /*virtual*/ void httpFailure()
- {
- LLSD subs;
- subs["ERROR_MESSAGE"] = getReason();
- LLNotificationsUtil::add(mErrorMessage, subs);
- }
-};
-
-
-
LLFloaterExperiences::LLFloaterExperiences(const LLSD& data)
:LLFloater(data)
{
@@ -198,26 +144,20 @@ void LLFloaterExperiences::refreshContents()
if (region)
{
- LLExperienceListResponder::NameMap nameMap;
- std::string lookup_url=region->getCapability("GetExperiences");
- if(!lookup_url.empty())
- {
- nameMap["experiences"]="Allowed_Experiences_Tab";
- nameMap["blocked"]="Blocked_Experiences_Tab";
- LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap));
- }
+ NameMap_t tabMap;
+ LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>();
+
+ tabMap["experiences"]="Allowed_Experiences_Tab";
+ tabMap["blocked"]="Blocked_Experiences_Tab";
+ tabMap["experience_ids"]="Owned_Experiences_Tab";
+
+ retrieveExperienceList(region->getCapability("GetExperiences"), handle, tabMap);
updateInfo("GetAdminExperiences","Admin_Experiences_Tab");
updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab");
- lookup_url = region->getCapability("AgentExperiences");
- if(!lookup_url.empty())
- {
- nameMap["experience_ids"]="Owned_Experiences_Tab";
- LLExperienceListResponder* responder = new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap, "ExperienceAcquireFailed");
- responder->mCallback = boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2);
- LLHTTPClient::get(lookup_url, responder);
- }
+ retrieveExperienceList(region->getCapability("AgentExperiences"), handle, tabMap,
+ "ExperienceAcquireFailed", boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2));
}
}
@@ -303,38 +243,139 @@ void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel, const LL
LLFloaterExperiences::findInstance()->updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab");
}
-void LLFloaterExperiences::updateInfo(std::string experiences, std::string tab)
+void LLFloaterExperiences::updateInfo(std::string experienceCap, std::string tab)
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- LLExperienceListResponder::NameMap nameMap;
- std::string lookup_url = region->getCapability(experiences);
- if(!lookup_url.empty())
- {
- nameMap["experience_ids"]=tab;
- LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap));
- }
- }
+ NameMap_t tabMap;
+ LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>();
+
+ tabMap["experience_ids"] = tab;
+
+ retrieveExperienceList(region->getCapability(experienceCap), handle, tabMap);
+ }
}
-void LLFloaterExperiences::sendPurchaseRequest() const
+void LLFloaterExperiences::sendPurchaseRequest()
{
- LLViewerRegion* region = gAgent.getRegion();
- std::string url = region->getCapability("AgentExperiences");
- if(!url.empty())
- {
- LLSD content;
-
- LLExperienceListResponder::NameMap nameMap;
- nameMap["experience_ids"]="Owned_Experiences_Tab";
- LLExperienceListResponder* responder = new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap, "ExperienceAcquireFailed");
- responder->mCallback = boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2);
- LLHTTPClient::post(url, content, responder);
- }
+ LLViewerRegion* region = gAgent.getRegion();
+
+ if (region)
+ {
+ NameMap_t tabMap;
+ LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>();
+
+ tabMap["experience_ids"] = "Owned_Experiences_Tab";
+
+ requestNewExperience(region->getCapability("AgentExperiences"), handle, tabMap, "ExperienceAcquireFailed",
+ boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2));
+ }
}
LLFloaterExperiences* LLFloaterExperiences::findInstance()
{
return LLFloaterReg::findTypedInstance<LLFloaterExperiences>("experiences");
}
+
+
+void LLFloaterExperiences::retrieveExperienceList(const std::string &url,
+ const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
+ const std::string &errorNotify, Callback_t cback)
+
+{
+ invokationFn_t getFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> httpOptions
+ // _5 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _4, _5);
+
+ LLCoros::instance().launch("LLFloaterExperiences::retrieveExperienceList",
+ boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro,
+ url, hparent, tabMapping, errorNotify, cback, getFn));
+
+}
+
+void LLFloaterExperiences::requestNewExperience(const std::string &url,
+ const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
+ const std::string &errorNotify, Callback_t cback)
+{
+ invokationFn_t postFn = boost::bind(
+ // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+ static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+ //----
+ // _1 -> httpAdapter
+ // _2 -> httpRequest
+ // _3 -> url
+ // _4 -> httpOptions
+ // _5 -> httpHeaders
+ (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, LLSD(), _4, _5);
+
+ LLCoros::instance().launch("LLFloaterExperiences::requestNewExperience",
+ boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro,
+ url, hparent, tabMapping, errorNotify, cback, postFn));
+
+}
+
+
+void LLFloaterExperiences::retrieveExperienceListCoro(std::string url,
+ LLHandle<LLFloaterExperiences> hparent, NameMap_t tabMapping,
+ std::string errorNotify, Callback_t cback, invokationFn_t invoker)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("retrieveExperienceListCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+
+ if (url.empty())
+ {
+ LL_WARNS() << "retrieveExperienceListCoro called with empty capability!" << LL_ENDL;
+ return;
+ }
+
+ LLSD result = invoker(httpAdapter, httpRequest, url, httpOptions, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LLSD subs;
+ subs["ERROR_MESSAGE"] = status.getType();
+ LLNotificationsUtil::add(errorNotify, subs);
+
+ return;
+ }
+
+ if (hparent.isDead())
+ return;
+
+ LLFloaterExperiences* parent = hparent.get();
+ LLTabContainer* tabs = parent->getChild<LLTabContainer>("xp_tabs");
+
+ for (NameMap_t::iterator it = tabMapping.begin(); it != tabMapping.end(); ++it)
+ {
+ if (result.has(it->first))
+ {
+ LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it->second);
+ if (tab)
+ {
+ const LLSD& ids = result[it->first];
+ tab->setExperienceList(ids);
+ if (!cback.empty())
+ {
+ cback(tab, result);
+ }
+ }
+ }
+ }
+
+}
diff --git a/indra/newview/llfloaterexperiences.h b/indra/newview/llfloaterexperiences.h
index 769283ff07..c038aa6375 100644
--- a/indra/newview/llfloaterexperiences.h
+++ b/indra/newview/llfloaterexperiences.h
@@ -28,6 +28,7 @@
#define LL_LLFLOATEREXPERIENCES_H
#include "llfloater.h"
+#include "llcorehttputil.h"
class LLPanelExperiences;
@@ -41,6 +42,9 @@ public:
virtual void onOpen(const LLSD& key);
static LLFloaterExperiences* findInstance();
protected:
+ typedef std::map<std::string, std::string> NameMap_t;
+ typedef boost::function<void(LLPanelExperiences*, const LLSD&)> Callback_t;
+
void clearFromRecent(const LLSD& ids);
void resizeToTabs();
/*virtual*/ BOOL postBuild();
@@ -49,11 +53,22 @@ protected:
LLPanelExperiences* addTab(const std::string& name, bool select);
bool updatePermissions(const LLSD& permission);
- void sendPurchaseRequest() const;
+ void sendPurchaseRequest();
void checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content)const;
void updateInfo(std::string experiences, std::string tab);
+ void retrieveExperienceList(const std::string &url, const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
+ const std::string &errorNotify = std::string("ErrorMessage"), Callback_t cback = Callback_t());
+
+ void requestNewExperience(const std::string &url, const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
+ const std::string &errorNotify, Callback_t cback);
+
private:
+ typedef boost::function < LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t, LLCore::HttpRequest::ptr_t,
+ const std::string, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) > invokationFn_t;
+
+ static void retrieveExperienceListCoro(std::string url, LLHandle<LLFloaterExperiences> hparent,
+ NameMap_t tabMapping, std::string errorNotify, Callback_t cback, invokationFn_t invoker);
};
diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp
index 37774fbc5c..adc7f71586 100755
--- a/indra/newview/llfloatergodtools.cpp
+++ b/indra/newview/llfloatergodtools.cpp
@@ -115,7 +115,7 @@ void LLFloaterGodTools::refreshAll()
LLFloaterGodTools::LLFloaterGodTools(const LLSD& key)
: LLFloater(key),
- mCurrentHost(LLHost::invalid),
+ mCurrentHost(LLHost()),
mUpdateTimer()
{
mFactoryMap["grid"] = LLCallbackMap(createPanelGrid, this);
@@ -180,7 +180,7 @@ void LLFloaterGodTools::updatePopup(LLCoordGL center, MASK mask)
// virtual
void LLFloaterGodTools::draw()
{
- if (mCurrentHost == LLHost::invalid)
+ if (mCurrentHost == LLHost())
{
if (mUpdateTimer.getElapsedTimeF32() > SECONDS_BETWEEN_UPDATE_REQUESTS)
{
@@ -325,7 +325,7 @@ void LLFloaterGodTools::sendRegionInfoRequest()
{
if (mPanelRegionTools) mPanelRegionTools->clearAllWidgets();
if (mPanelObjectTools) mPanelObjectTools->clearAllWidgets();
- mCurrentHost = LLHost::invalid;
+ mCurrentHost = LLHost();
mUpdateTimer.reset();
LLMessageSystem* msg = gMessageSystem;
diff --git a/indra/newview/llfloaterhoverheight.cpp b/indra/newview/llfloaterhoverheight.cpp
index 8908626de6..003a22fa04 100755
--- a/indra/newview/llfloaterhoverheight.cpp
+++ b/indra/newview/llfloaterhoverheight.cpp
@@ -31,7 +31,6 @@
#include "llsliderctrl.h"
#include "llviewercontrol.h"
#include "llsdserialize.h"
-#include "llhttpclient.h"
#include "llagent.h"
#include "llviewerregion.h"
#include "llvoavatarself.h"
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index fc7fcf3ab9..6623ce0f80 100755
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -41,7 +41,6 @@
#include "llchicletbar.h"
#include "lldonotdisturbnotificationstorage.h"
#include "llfloaterreg.h"
-#include "llhttpclient.h"
#include "llfloateravatarpicker.h"
#include "llfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container
#include "llinventoryfunctions.h"
@@ -62,6 +61,7 @@
#include "llviewerchat.h"
#include "llnotificationmanager.h"
#include "llautoreplace.h"
+#include "llcorehttputil.h"
const F32 ME_TYPING_TIMEOUT = 4.0f;
const F32 OTHER_TYPING_TIMEOUT = 9.0f;
@@ -1178,26 +1178,6 @@ BOOL LLFloaterIMSession::isInviteAllowed() const
|| mIsP2PChat);
}
-class LLSessionInviteResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSessionInviteResponder);
-public:
- LLSessionInviteResponder(const LLUUID& session_id)
- {
- mSessionID = session_id;
- }
-
-protected:
- void httpFailure()
- {
- LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL;
- //throw something back to the viewer here?
- }
-
-private:
- LLUUID mSessionID;
-};
-
BOOL LLFloaterIMSession::inviteToSession(const uuid_vec_t& ids)
{
LLViewerRegion* region = gAgent.getRegion();
@@ -1221,7 +1201,9 @@ BOOL LLFloaterIMSession::inviteToSession(const uuid_vec_t& ids)
}
data["method"] = "invite";
data["session-id"] = mSessionID;
- LLHTTPClient::post(url, data,new LLSessionInviteResponder(mSessionID));
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data,
+ "Session invite sent", "Session invite failed");
}
else
{
diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp
index b2d36479cd..18f0bc4498 100755
--- a/indra/newview/llfloatermarketplacelistings.cpp
+++ b/indra/newview/llfloatermarketplacelistings.cpp
@@ -572,7 +572,7 @@ void LLFloaterMarketplaceListings::updateView()
std::string title;
std::string tooltip;
- const LLSD& subs = getMarketplaceStringSubstitutions();
+ const LLSD& subs = LLMarketplaceData::getMarketplaceStringSubstitutions();
// Update the top message or flip to the tabs and folders view
// *TODO : check those messages and create better appropriate ones in strings.xml
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 918dc98a3a..449d5e7d64 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -4436,6 +4436,15 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)
// BAP HACK: handle "" for case that MeshUploadFlag cap is broken.
mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status));
+ if (!mHasUploadPerm)
+ {
+ LL_WARNS() << "Upload permission set to false because upload_status=\"" << upload_status << "\"" << LL_ENDL;
+ }
+ else if (mHasUploadPerm && mUploadModelUrl.empty())
+ {
+ LL_WARNS() << "Upload permission set to true but uploadModelUrl is empty!" << LL_ENDL;
+ }
+
// isModelUploadAllowed() includes mHasUploadPerm
mUploadBtn->setEnabled(isModelUploadAllowed());
getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);
diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp
index 22a8ac4705..0fe97fd610 100755
--- a/indra/newview/llfloatermodeluploadbase.cpp
+++ b/indra/newview/llfloatermodeluploadbase.cpp
@@ -30,6 +30,7 @@
#include "llagent.h"
#include "llviewerregion.h"
#include "llnotificationsutil.h"
+#include "llcorehttputil.h"
LLFloaterModelUploadBase::LLFloaterModelUploadBase(const LLSD& key)
:LLFloater(key),
@@ -47,7 +48,8 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()
LL_INFOS()<< typeid(*this).name()
<< "::requestAgentUploadPermissions() requesting for upload model permissions from: "
<< url << LL_ENDL;
- LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle()));
+ LLCoros::instance().launch("LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro",
+ boost::bind(&LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro, this, url, getPermObserverHandle()));
}
else
{
@@ -58,3 +60,34 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()
mHasUploadPerm = true;
}
}
+
+void LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro(std::string url,
+ LLHandle<LLUploadPermissionsObserver> observerHandle)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("MeshUploadFlag", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ LLUploadPermissionsObserver* observer = observerHandle.get();
+
+ if (!observer)
+ {
+ LL_WARNS("MeshUploadFlag") << "Unable to get observer after call to '" << url << "' aborting." << LL_ENDL;
+ }
+
+ if (!status)
+ {
+ observer->setPermissonsErrorStatus(status.getStatus(), status.getMessage());
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ observer->onPermissionsReceived(result);
+}
diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h
index d9a8879687..0d4c834122 100755
--- a/indra/newview/llfloatermodeluploadbase.h
+++ b/indra/newview/llfloatermodeluploadbase.h
@@ -28,6 +28,8 @@
#define LL_LLFLOATERMODELUPLOADBASE_H
#include "lluploadfloaterobservers.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObserver, public LLWholeModelFeeObserver, public LLWholeModelUploadObserver
{
@@ -54,6 +56,8 @@ protected:
// requests agent's permissions to upload model
void requestAgentUploadPermissions();
+ void requestAgentUploadPermissionsCoro(std::string url, LLHandle<LLUploadPermissionsObserver> observerHandle);
+
std::string mUploadModelUrl;
bool mHasUploadPerm;
};
diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp
index 0cca715fe2..135bbb335e 100755
--- a/indra/newview/llfloaternamedesc.cpp
+++ b/indra/newview/llfloaternamedesc.cpp
@@ -164,14 +164,18 @@ void LLFloaterNameDesc::onBtnOK( )
void *nruserdata = NULL;
std::string display_name = LLStringUtil::null;
- upload_new_resource(mFilenameAndPath, // file
- getChild<LLUICtrl>("name_form")->getValue().asString(),
- getChild<LLUICtrl>("description_form")->getValue().asString(),
- 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- display_name, callback, expected_upload_cost, nruserdata);
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
+ mFilenameAndPath,
+ getChild<LLUICtrl>("name_form")->getValue().asString(),
+ getChild<LLUICtrl>("description_form")->getValue().asString(), 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost));
+
+ upload_new_resource(uploadInfo, callback, nruserdata);
+
closeFloater(false);
}
diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp
deleted file mode 100755
index b7b1634a5f..0000000000
--- a/indra/newview/llfloateroutbox.cpp
+++ /dev/null
@@ -1,623 +0,0 @@
-/**
- * @file llfloateroutbox.cpp
- * @brief Implementation of the merchant outbox window
- *
- * $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 "llfloateroutbox.h"
-
-#include "llfloaterreg.h"
-#include "llfolderview.h"
-#include "llinventorybridge.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llinventoryobserver.h"
-#include "llinventorypanel.h"
-#include "llmarketplacefunctions.h"
-#include "llnotificationhandler.h"
-#include "llnotificationmanager.h"
-#include "llnotificationsutil.h"
-#include "lltextbox.h"
-#include "lltransientfloatermgr.h"
-#include "lltrans.h"
-#include "llviewernetwork.h"
-#include "llwindowshade.h"
-
-
-///----------------------------------------------------------------------------
-/// LLOutboxNotification class
-///----------------------------------------------------------------------------
-
-LLNotificationsUI::LLOutboxNotification::LLOutboxNotification()
- : LLSystemNotificationHandler("Outbox", "outbox")
-{
-}
-
-bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLNotificationPtr& notify)
-{
- LLFloaterOutbox* outbox_floater = LLFloaterReg::getTypedInstance<LLFloaterOutbox>("outbox");
-
- outbox_floater->showNotification(notify);
-
- return false;
-}
-
-void LLNotificationsUI::LLOutboxNotification::onDelete(LLNotificationPtr p)
-{
- LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
- if (notification_handler)
- {
- notification_handler->onDelete(p);
- }
-}
-
-///----------------------------------------------------------------------------
-/// LLOutboxAddedObserver helper class
-///----------------------------------------------------------------------------
-
-class LLOutboxAddedObserver : public LLInventoryCategoryAddedObserver
-{
-public:
- LLOutboxAddedObserver(LLFloaterOutbox * outboxFloater)
- : LLInventoryCategoryAddedObserver()
- , mOutboxFloater(outboxFloater)
- {
- }
-
- void done()
- {
- for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it)
- {
- LLViewerInventoryCategory* added_category = *it;
-
- LLFolderType::EType added_category_type = added_category->getPreferredType();
-
- if (added_category_type == LLFolderType::FT_OUTBOX)
- {
- mOutboxFloater->initializeMarketPlace();
- }
- }
- }
-
-private:
- LLFloaterOutbox * mOutboxFloater;
-};
-
-///----------------------------------------------------------------------------
-/// LLFloaterOutbox
-///----------------------------------------------------------------------------
-
-LLFloaterOutbox::LLFloaterOutbox(const LLSD& key)
- : LLFloater(key)
- , mCategoriesObserver(NULL)
- , mCategoryAddedObserver(NULL)
- , mImportBusy(false)
- , mImportButton(NULL)
- , mInventoryFolderCountText(NULL)
- , mInventoryImportInProgress(NULL)
- , mInventoryPlaceholder(NULL)
- , mInventoryText(NULL)
- , mInventoryTitle(NULL)
- , mOutboxId(LLUUID::null)
- , mOutboxItemCount(0)
- , mOutboxTopLevelDropZone(NULL)
- , mWindowShade(NULL)
-{
-}
-
-LLFloaterOutbox::~LLFloaterOutbox()
-{
- if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
- {
- gInventory.removeObserver(mCategoriesObserver);
- }
- delete mCategoriesObserver;
-
- if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
- {
- gInventory.removeObserver(mCategoryAddedObserver);
- }
- delete mCategoryAddedObserver;
-}
-
-BOOL LLFloaterOutbox::postBuild()
-{
- mInventoryFolderCountText = getChild<LLTextBox>("outbox_folder_count");
- mInventoryImportInProgress = getChild<LLView>("import_progress_indicator");
- mInventoryPlaceholder = getChild<LLView>("outbox_inventory_placeholder_panel");
- mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_text");
- mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_title");
-
- mImportButton = getChild<LLButton>("outbox_import_btn");
- mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this));
-
- mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target");
-
- LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this));
-
- // Observe category creation to catch outbox creation (moot if already existing)
- mCategoryAddedObserver = new LLOutboxAddedObserver(this);
- gInventory.addObserver(mCategoryAddedObserver);
-
- // Setup callbacks for importer
- LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance();
- importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2));
- importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1));
- importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2));
-
- return TRUE;
-}
-
-void LLFloaterOutbox::cleanOutbox()
-{
- // Note: we cannot delete the mOutboxInventoryPanel as that point
- // as this is called through callback observers of the panel itself.
- // Doing so would crash rapidly.
-
- // Invalidate the outbox data
- mOutboxId.setNull();
- mOutboxItemCount = 0;
-}
-
-void LLFloaterOutbox::onClose(bool app_quitting)
-{
- if (mWindowShade)
- {
- delete mWindowShade;
-
- mWindowShade = NULL;
- }
-}
-
-void LLFloaterOutbox::onOpen(const LLSD& key)
-{
- //
- // Initialize the Market Place or go update the outbox
- //
- if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
- {
- initializeMarketPlace();
- }
- else
- {
- setupOutbox();
- }
-
- //
- // Update the floater view
- //
- updateView();
-
- //
- // Trigger fetch of outbox contents
- //
- fetchOutboxContents();
-}
-
-void LLFloaterOutbox::onFocusReceived()
-{
- fetchOutboxContents();
-}
-
-void LLFloaterOutbox::fetchOutboxContents()
-{
- if (mOutboxId.notNull())
- {
- LLInventoryModelBackgroundFetch::instance().start(mOutboxId);
- }
-}
-
-void LLFloaterOutbox::setupOutbox()
-{
- if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)
- {
- // If we are *not* a merchant or we have no market place connection established yet, do nothing
- return;
- }
-
- // We are a merchant. Get the outbox, create it if needs be.
- LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true);
- if (outbox_id.isNull())
- {
- // We should never get there unless the inventory fails badly
- LL_ERRS() << "Inventory problem: failure to create the outbox for a merchant!" << LL_ENDL;
- return;
- }
-
- // Consolidate Merchant Outbox
- // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, things get messy and conventions get broken down eventually
- gInventory.consolidateForType(outbox_id, LLFolderType::FT_OUTBOX);
-
- if (outbox_id == mOutboxId)
- {
- LL_WARNS() << "Inventory warning: Merchant outbox already set" << LL_ENDL;
- return;
- }
- mOutboxId = outbox_id;
-
- // No longer need to observe new category creation
- if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver))
- {
- gInventory.removeObserver(mCategoryAddedObserver);
- delete mCategoryAddedObserver;
- mCategoryAddedObserver = NULL;
- }
- llassert(!mCategoryAddedObserver);
-
- // Create observer for outbox modifications : clear the old one and create a new one
- if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver))
- {
- gInventory.removeObserver(mCategoriesObserver);
- delete mCategoriesObserver;
- }
- mCategoriesObserver = new LLInventoryCategoriesObserver();
- gInventory.addObserver(mCategoriesObserver);
- mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this));
- llassert(mCategoriesObserver);
-
- // Set up the outbox inventory view
- LLInventoryPanel* inventory_panel = mOutboxInventoryPanel.get();
- if (inventory_panel)
- {
- delete inventory_panel;
- }
- inventory_panel = LLUICtrlFactory::createFromFile<LLInventoryPanel>("panel_outbox_inventory.xml", mInventoryPlaceholder->getParent(), LLInventoryPanel::child_registry_t::instance());
- mOutboxInventoryPanel = inventory_panel->getInventoryPanelHandle();
- llassert(mOutboxInventoryPanel.get() != NULL);
-
- // Reshape the inventory to the proper size
- LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect();
- inventory_panel->setShape(inventory_placeholder_rect);
-
- // Set the sort order newest to oldest
- inventory_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME);
- inventory_panel->getFilter().markDefault();
-
- // Get the content of the outbox
- fetchOutboxContents();
-}
-
-void LLFloaterOutbox::initializeMarketPlace()
-{
- //
- // Initialize the marketplace import API
- //
- LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance();
- if (!importer.isInitialized())
- {
- importer.initialize();
- }
-}
-
-void LLFloaterOutbox::setStatusString(const std::string& statusString)
-{
- llassert(mInventoryFolderCountText != NULL);
-
- mInventoryFolderCountText->setText(statusString);
-}
-
-void LLFloaterOutbox::updateFolderCount()
-{
- if (mOutboxInventoryPanel.get() && mOutboxId.notNull())
- {
- U32 item_count = 0;
-
- if (mOutboxId.notNull())
- {
- LLInventoryModel::cat_array_t * cats;
- LLInventoryModel::item_array_t * items;
- gInventory.getDirectDescendentsOf(mOutboxId, cats, items);
-
- item_count = cats->size() + items->size();
- }
-
- mOutboxItemCount = item_count;
- }
- else
- {
- // If there's no outbox, the number of items in it should be set to 0 for consistency
- mOutboxItemCount = 0;
- }
-
- if (!mImportBusy)
- {
- updateFolderCountStatus();
- }
-}
-
-void LLFloaterOutbox::updateFolderCountStatus()
-{
- if (mOutboxInventoryPanel.get() && mOutboxId.notNull())
- {
- switch (mOutboxItemCount)
- {
- case 0: setStatusString(getString("OutboxFolderCount0")); break;
- case 1: setStatusString(getString("OutboxFolderCount1")); break;
- default:
- {
- std::string item_count_str = llformat("%d", mOutboxItemCount);
-
- LLStringUtil::format_map_t args;
- args["[NUM]"] = item_count_str;
-
- setStatusString(getString("OutboxFolderCountN", args));
- break;
- }
- }
- }
-
- mImportButton->setEnabled(mOutboxItemCount > 0);
-}
-
-void LLFloaterOutbox::updateView()
-{
- updateFolderCount();
- LLInventoryPanel* panel = mOutboxInventoryPanel.get();
-
- if (mOutboxItemCount > 0)
- {
- panel->setVisible(TRUE);
- mInventoryPlaceholder->setVisible(FALSE);
- mOutboxTopLevelDropZone->setVisible(TRUE);
- }
- else
- {
- if (panel)
- {
- panel->setVisible(FALSE);
- }
-
- // Show the drop zone if there is an outbox folder
- mOutboxTopLevelDropZone->setVisible(mOutboxId.notNull());
-
- mInventoryPlaceholder->setVisible(TRUE);
-
- std::string outbox_text;
- std::string outbox_title;
- std::string outbox_tooltip;
-
- const LLSD& subs = getMarketplaceStringSubstitutions();
- U32 mkt_status = LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus();
-
- if (mOutboxId.notNull())
- {
- // Does the outbox needs recreation?
- if ((mOutboxInventoryPanel.get() == NULL) || !gInventory.getCategory(mOutboxId))
- {
- setupOutbox();
- }
- // "Outbox is empty!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxNoItems", subs);
- outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip");
- }
- else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING)
- {
- // "Initializing!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxInitializing", subs);
- outbox_title = LLTrans::getString("InventoryOutboxInitializingTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip");
- }
- else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT)
- {
- // "Not a merchant!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxNotMerchant", subs);
- outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip");
- }
- else
- {
- // "Errors!" message strings
- outbox_text = LLTrans::getString("InventoryOutboxError", subs);
- outbox_title = LLTrans::getString("InventoryOutboxErrorTitle");
- outbox_tooltip = LLTrans::getString("InventoryOutboxErrorTooltip");
- }
-
- mInventoryText->setValue(outbox_text);
- mInventoryTitle->setValue(outbox_title);
- mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip);
- }
-}
-
-bool isAccepted(EAcceptance accept)
-{
- return (accept >= ACCEPT_YES_COPY_SINGLE);
-}
-
-BOOL LLFloaterOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- if ((mOutboxInventoryPanel.get() == NULL) ||
- (mWindowShade && mWindowShade->isShown()) ||
- LLMarketplaceInventoryImporter::getInstance()->isImportInProgress() ||
- mOutboxId.isNull())
- {
- return FALSE;
- }
-
- LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- BOOL handled = (handled_view != NULL);
-
- // Determine if the mouse is inside the inventory panel itself or just within the floater
- bool pointInInventoryPanel = false;
- bool pointInInventoryPanelChild = false;
- LLInventoryPanel* panel = mOutboxInventoryPanel.get();
- LLFolderView* root_folder = panel->getRootFolder();
- if (panel->getVisible())
- {
- S32 inv_x, inv_y;
- localPointToOtherView(x, y, &inv_x, &inv_y, panel);
-
- pointInInventoryPanel = panel->getRect().pointInRect(inv_x, inv_y);
-
- LLView * inventory_panel_child_at_point = panel->childFromPoint(inv_x, inv_y, true);
- pointInInventoryPanelChild = (inventory_panel_child_at_point != root_folder);
- }
-
- // Pass all drag and drop for this floater to the outbox inventory control
- if (!handled || !isAccepted(*accept))
- {
- // Handle the drag and drop directly to the root of the outbox if we're not in the inventory panel
- // (otherwise the inventory panel itself will handle the drag and drop operation, without any override)
- if (!pointInInventoryPanel)
- {
- handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- }
-
- mOutboxTopLevelDropZone->setBackgroundVisible(handled && !drop && isAccepted(*accept));
- }
- else
- {
- mOutboxTopLevelDropZone->setBackgroundVisible(!pointInInventoryPanelChild);
- }
-
- return handled;
-}
-
-BOOL LLFloaterOutbox::handleHover(S32 x, S32 y, MASK mask)
-{
- mOutboxTopLevelDropZone->setBackgroundVisible(FALSE);
-
- return LLFloater::handleHover(x, y, mask);
-}
-
-void LLFloaterOutbox::onMouseLeave(S32 x, S32 y, MASK mask)
-{
- mOutboxTopLevelDropZone->setBackgroundVisible(FALSE);
-
- LLFloater::onMouseLeave(x, y, mask);
-}
-
-void LLFloaterOutbox::onImportButtonClicked()
-{
- if (mOutboxInventoryPanel.get())
- {
- mOutboxInventoryPanel.get()->clearSelection();
- }
-
- mImportBusy = LLMarketplaceInventoryImporter::instance().triggerImport();
-}
-
-void LLFloaterOutbox::onOutboxChanged()
-{
- LLViewerInventoryCategory* category = gInventory.getCategory(mOutboxId);
- if (mOutboxId.notNull() && category)
- {
- fetchOutboxContents();
- updateView();
- }
- else
- {
- cleanOutbox();
- }
-}
-
-void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content)
-{
- if (status == MarketplaceErrorCodes::IMPORT_DONE)
- {
- LLNotificationsUtil::add("OutboxImportComplete");
- }
- else if (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS)
- {
- const LLSD& subs = getMarketplaceStringSubstitutions();
-
- LLNotificationsUtil::add("OutboxImportHadErrors", subs);
- }
- else
- {
- char status_string[16];
- sprintf(status_string, "%d", status);
-
- LLSD subs;
- subs["[ERROR_CODE]"] = status_string;
-
- LLNotificationsUtil::add("OutboxImportFailed", subs);
- }
-
- updateView();
-}
-
-void LLFloaterOutbox::importStatusChanged(bool inProgress)
-{
- if (mOutboxId.isNull() && (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT))
- {
- setupOutbox();
- }
-
- if (inProgress)
- {
- if (mImportBusy)
- {
- setStatusString(getString("OutboxImporting"));
- }
- else
- {
- setStatusString(getString("OutboxInitializing"));
- }
-
- mImportBusy = true;
- mImportButton->setEnabled(false);
- mInventoryImportInProgress->setVisible(true);
- }
- else
- {
- setStatusString("");
- mImportBusy = false;
- mImportButton->setEnabled(mOutboxItemCount > 0);
- mInventoryImportInProgress->setVisible(false);
- }
-
- updateView();
-}
-
-void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content)
-{
- if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
- {
- char status_string[16];
- sprintf(status_string, "%d", status);
-
- LLSD subs;
- subs["[ERROR_CODE]"] = status_string;
-
- LLNotificationsUtil::add("OutboxInitFailed", subs);
- }
-
- updateView();
-}
-
-void LLFloaterOutbox::showNotification(const LLNotificationPtr& notification)
-{
- LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get());
- llassert(notification_handler);
-
- notification_handler->processNotification(notification);
-}
-
-
-
diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h
deleted file mode 100755
index 2cf69fc3cc..0000000000
--- a/indra/newview/llfloateroutbox.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file llfloateroutbox.h
- * @brief Implementation of the merchant outbox window
- *
- * $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
- * ABILITY 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_LLFLOATEROUTBOX_H
-#define LL_LLFLOATEROUTBOX_H
-
-#include "llfloater.h"
-#include "llfoldertype.h"
-#include "llinventoryfilter.h"
-#include "llnotificationptr.h"
-
-
-class LLButton;
-class LLInventoryCategoriesObserver;
-class LLInventoryCategoryAddedObserver;
-class LLInventoryPanel;
-class LLLoadingIndicator;
-class LLNotification;
-class LLTextBox;
-class LLView;
-class LLWindowShade;
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLFloaterOutbox
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLFloaterOutbox : public LLFloater
-{
-public:
- LLFloaterOutbox(const LLSD& key);
- ~LLFloaterOutbox();
-
- void initializeMarketPlace();
-
- // virtuals
- BOOL postBuild();
- BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg);
-
- void showNotification(const LLNotificationPtr& notification);
-
- BOOL handleHover(S32 x, S32 y, MASK mask);
- void onMouseLeave(S32 x, S32 y, MASK mask);
-
-protected:
- void setupOutbox();
- void cleanOutbox();
- void fetchOutboxContents();
-
- void importReportResults(U32 status, const LLSD& content);
- void importStatusChanged(bool inProgress);
- void initializationReportError(U32 status, const LLSD& content);
-
- void onClose(bool app_quitting);
- void onOpen(const LLSD& key);
-
- void onFocusReceived();
-
- void onImportButtonClicked();
- void onOutboxChanged();
-
- void setStatusString(const std::string& statusString);
-
- void updateFolderCount();
- void updateFolderCountStatus();
- void updateView();
-
-private:
- LLInventoryCategoriesObserver * mCategoriesObserver;
- LLInventoryCategoryAddedObserver * mCategoryAddedObserver;
-
- bool mImportBusy;
- LLButton * mImportButton;
-
- LLTextBox * mInventoryFolderCountText;
- LLView * mInventoryImportInProgress;
- LLView * mInventoryPlaceholder;
- LLTextBox * mInventoryText;
- LLTextBox * mInventoryTitle;
-
- LLUUID mOutboxId;
- LLHandle<LLInventoryPanel> mOutboxInventoryPanel;
- U32 mOutboxItemCount;
- LLPanel * mOutboxTopLevelDropZone;
-
- LLWindowShade * mWindowShade;
-};
-
-#endif // LL_LLFLOATEROUTBOX_H
diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp
index 042cf47070..31c2a6f9aa 100755
--- a/indra/newview/llfloaterperms.cpp
+++ b/indra/newview/llfloaterperms.cpp
@@ -37,6 +37,7 @@
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llvoavatar.h"
+#include "llcorehttputil.h"
LLFloaterPerms::LLFloaterPerms(const LLSD& seed)
: LLFloater(seed)
@@ -166,41 +167,6 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data)
xfer->setEnabled(copyable);
}
-class LLFloaterPermsResponder : public LLHTTPClient::Responder
-{
-public:
- LLFloaterPermsResponder(): LLHTTPClient::Responder() {}
-private:
- static std::string sPreviousReason;
-
- void httpFailure()
- {
- const std::string& reason = getReason();
- // Do not display the same error more than once in a row
- if (reason != sPreviousReason)
- {
- sPreviousReason = reason;
- LLSD args;
- args["REASON"] = reason;
- LLNotificationsUtil::add("DefaultObjectPermissions", args);
- }
- }
-
- void httpSuccess()
- {
- //const LLSD& content = getContent();
- //dump_sequential_xml("perms_responder_result.xml", content);
-
- // Since we have had a successful POST call be sure to display the next error message
- // even if it is the same as a previous one.
- sPreviousReason = "";
- LLFloaterPermsDefault::setCapSent(true);
- LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL;
- }
-};
-
- std::string LLFloaterPermsResponder::sPreviousReason;
-
void LLFloaterPermsDefault::sendInitialPerms()
{
if(!mCapSent)
@@ -215,23 +181,8 @@ void LLFloaterPermsDefault::updateCap()
if(!object_url.empty())
{
- LLSD report = LLSD::emptyMap();
- report["default_object_perm_masks"]["Group"] =
- (LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]);
- report["default_object_perm_masks"]["Everyone"] =
- (LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]);
- report["default_object_perm_masks"]["NextOwner"] =
- (LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]);
-
- {
- LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '"
- << object_url << "'\n";
- std::ostringstream sent_perms_log;
- LLSDSerialize::toPrettyXML(report, sent_perms_log);
- LL_CONT << sent_perms_log.str() << LL_ENDL;
- }
-
- LLHTTPClient::post(object_url, report, new LLFloaterPermsResponder());
+ LLCoros::instance().launch("LLFloaterPermsDefault::updateCapCoro",
+ boost::bind(&LLFloaterPermsDefault::updateCapCoro, object_url));
}
else
{
@@ -239,6 +190,57 @@ void LLFloaterPermsDefault::updateCap()
}
}
+/*static*/
+void LLFloaterPermsDefault::updateCapCoro(std::string url)
+{
+ static std::string previousReason;
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD postData = LLSD::emptyMap();
+ postData["default_object_perm_masks"]["Group"] =
+ (LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]);
+ postData["default_object_perm_masks"]["Everyone"] =
+ (LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]);
+ postData["default_object_perm_masks"]["NextOwner"] =
+ (LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]);
+
+ {
+ LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '"
+ << url << "'\n";
+ std::ostringstream sent_perms_log;
+ LLSDSerialize::toPrettyXML(postData, sent_perms_log);
+ LL_CONT << sent_perms_log.str() << LL_ENDL;
+ }
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ const std::string& reason = status.toString();
+ // Do not display the same error more than once in a row
+ if (reason != previousReason)
+ {
+ previousReason = reason;
+ LLSD args;
+ args["REASON"] = reason;
+ LLNotificationsUtil::add("DefaultObjectPermissions", args);
+ }
+ return;
+ }
+
+ // Since we have had a successful POST call be sure to display the next error message
+ // even if it is the same as a previous one.
+ previousReason.clear();
+ LLFloaterPermsDefault::setCapSent(true);
+ LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL;
+}
+
void LLFloaterPermsDefault::setCapSent(bool cap_sent)
{
mCapSent = cap_sent;
diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h
index 2bb0a19dc1..e866b6de7d 100755
--- a/indra/newview/llfloaterperms.h
+++ b/indra/newview/llfloaterperms.h
@@ -29,6 +29,8 @@
#define LL_LLFLOATERPERMPREFS_H
#include "llfloater.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLFloaterPerms : public LLFloater
{
@@ -80,6 +82,8 @@ private:
void refresh();
static const std::string sCategoryNames[CAT_LAST];
+ static void updateCapCoro(std::string url);
+
// cached values only for implementing cancel.
bool mShareWithGroup[CAT_LAST];
diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp
index 40757a4d04..271fb2f9a3 100755
--- a/indra/newview/llfloaterregiondebugconsole.cpp
+++ b/indra/newview/llfloaterregiondebugconsole.cpp
@@ -30,11 +30,11 @@
#include "llfloaterregiondebugconsole.h"
#include "llagent.h"
-#include "llhttpclient.h"
#include "llhttpnode.h"
#include "lllineeditor.h"
#include "lltexteditor.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
// Two versions of the sim console API are supported.
//
@@ -68,58 +68,6 @@ namespace
const std::string CONSOLE_NOT_SUPPORTED(
"This region does not support the simulator console.");
- // This responder handles the initial response. Unless error() is called
- // we assume that the simulator has received our request. Error will be
- // called if this request times out.
- class AsyncConsoleResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(AsyncConsoleResponder);
- protected:
- /* virtual */
- 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 httpFailure()
- {
- LL_WARNS("Console") << dumpResponse() << LL_ENDL;
- if (mOutput)
- {
- mOutput->appendText(
- UNABLE_TO_SEND_COMMAND + PROMPT,
- false);
- }
- }
-
- /*virtual*/
- void httpSuccess()
- {
- const LLSD& content = getContent();
- LL_DEBUGS("Console") << content << LL_ENDL;
- if (mOutput)
- {
- mOutput->appendText(
- content.asString() + PROMPT, false);
- }
- }
-
- public:
- LLTextEditor * mOutput;
- };
-
// This handles responses for console commands sent via the asynchronous
// API.
class ConsoleResponseNode : public LLHTTPNode
@@ -202,26 +150,57 @@ void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param)
}
else
{
- // Using SimConsole (deprecated)
- LLHTTPClient::post(
- url,
- LLSD(input->getText()),
- new ConsoleResponder(mOutput));
+ LLSD postData = LLSD(input->getText());
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, postData,
+ boost::bind(&LLFloaterRegionDebugConsole::onConsoleSuccess, this, _1),
+ boost::bind(&LLFloaterRegionDebugConsole::onConsoleError, this, _1));
}
}
else
{
- // Using SimConsoleAsync
- LLHTTPClient::post(
- url,
- LLSD(input->getText()),
- new AsyncConsoleResponder);
+ LLSD postData = LLSD(input->getText());
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, postData,
+ NULL,
+ boost::bind(&LLFloaterRegionDebugConsole::onAsyncConsoleError, this, _1));
+
}
mOutput->appendText(text, false);
input->clear();
}
+void LLFloaterRegionDebugConsole::onAsyncConsoleError(LLSD result)
+{
+ LL_WARNS("Console") << UNABLE_TO_SEND_COMMAND << LL_ENDL;
+ sConsoleReplySignal(UNABLE_TO_SEND_COMMAND);
+}
+
+void LLFloaterRegionDebugConsole::onConsoleError(LLSD result)
+{
+ LL_WARNS("Console") << UNABLE_TO_SEND_COMMAND << LL_ENDL;
+ if (mOutput)
+ {
+ mOutput->appendText(
+ UNABLE_TO_SEND_COMMAND + PROMPT,
+ false);
+ }
+
+}
+
+void LLFloaterRegionDebugConsole::onConsoleSuccess(LLSD result)
+{
+ if (mOutput)
+ {
+ LLSD response = result;
+ if (response.isMap() && response.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT))
+ {
+ response = response[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT];
+ }
+ mOutput->appendText(
+ response.asString() + PROMPT, false);
+ }
+}
+
void LLFloaterRegionDebugConsole::onReplyReceived(const std::string& output)
{
mOutput->appendText(output + PROMPT, false);
diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h
index fd3af4152e..f55d964924 100755
--- a/indra/newview/llfloaterregiondebugconsole.h
+++ b/indra/newview/llfloaterregiondebugconsole.h
@@ -31,14 +31,13 @@
#include <boost/signals2.hpp>
#include "llfloater.h"
-#include "llhttpclient.h"
class LLTextEditor;
typedef boost::signals2::signal<
void (const std::string& output)> console_reply_signal_t;
-class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Responder
+class LLFloaterRegionDebugConsole : public LLFloater
{
public:
LLFloaterRegionDebugConsole(LLSD const & key);
@@ -56,6 +55,10 @@ public:
private:
void onReplyReceived(const std::string& output);
+ void onAsyncConsoleError(LLSD result);
+ void onConsoleError(LLSD result);
+ void onConsoleSuccess(LLSD result);
+
boost::signals2::connection mReplySignalConnection;
};
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 5d1e01c1f7..94f3a45d88 100755
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -97,6 +97,7 @@
#include "llpanelexperiencepicker.h"
#include "llexperiencecache.h"
#include "llpanelexperiences.h"
+#include "llcorehttputil.h"
const S32 TERRAIN_TEXTURE_COUNT = 4;
const S32 CORNER_COUNT = 4;
@@ -803,30 +804,6 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L
return false;
}
-class ConsoleRequestResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(ConsoleRequestResponder);
-protected:
- /*virtual*/
- void httpFailure()
- {
- LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL;
- }
-};
-
-
-// called if this request times out.
-class ConsoleUpdateResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(ConsoleUpdateResponder);
-protected:
- /* virtual */
- void httpFailure()
- {
- LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL;
- }
-};
-
void LLFloaterRegionInfo::requestMeshRezInfo()
{
std::string sim_console_url = gAgent.getRegion()->getCapability("SimConsoleAsync");
@@ -835,10 +812,8 @@ void LLFloaterRegionInfo::requestMeshRezInfo()
{
std::string request_str = "get mesh_rez_enabled";
- LLHTTPClient::post(
- sim_console_url,
- LLSD(request_str),
- new ConsoleRequestResponder);
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(sim_console_url, LLSD(request_str),
+ "Requested mesh_rez_enabled", "Error requesting mesh_rez_enabled");
}
}
@@ -874,7 +849,8 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate()
body["allow_parcel_changes"] = getChild<LLUICtrl>("allow_parcel_changes_check")->getValue();
body["block_parcel_search"] = getChild<LLUICtrl>("block_parcel_search_check")->getValue();
- LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+ "Region info update posted.", "Region info update not posted.");
}
else
{
@@ -2303,36 +2279,6 @@ 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 httpSuccess()
- {
- LL_INFOS("Windlight") << "Successfully committed estate info" << LL_ENDL;
-
- // refresh the panel from the database
- LLPanelEstateInfo* panel = dynamic_cast<LLPanelEstateInfo*>(mpPanel.get());
- if (panel)
- panel->refresh();
- }
-
- // if we get an error response
- virtual void httpFailure()
- {
- LL_WARNS("Windlight") << dumpResponse() << LL_ENDL;
- }
-private:
- LLHandle<LLPanel> mpPanel;
-};
-
const std::string LLPanelEstateInfo::getOwnerName() const
{
return getChild<LLUICtrl>("estate_owner")->getValue().asString();
@@ -3640,29 +3586,6 @@ void LLPanelRegionExperiences::processResponse( const LLSD& content )
}
-
-class LLRegionExperienceResponder : public LLHTTPClient::Responder
-{
-public:
- typedef boost::function<void (const LLSD&)> callback_t;
-
- callback_t mCallback;
-
- LLRegionExperienceResponder(callback_t callback) : mCallback(callback) { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- mCallback(getContent());
- }
-
- /*virtual*/ void httpFailure()
- {
- LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-};
-
-
// Used for both access add and remove operations, depending on the flag
// passed in (ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE, etc.)
// static
@@ -3745,6 +3668,13 @@ void LLPanelRegionExperiences::infoCallback(LLHandle<LLPanelRegionExperiences> h
}
}
+/*static*/
+std::string LLPanelRegionExperiences::regionCapabilityQuery(LLViewerRegion* region, const std::string &cap)
+{
+ // region->getHandle() How to get a region * from a handle?
+
+ return region->getCapability(cap);
+}
bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
{
@@ -3769,13 +3699,10 @@ bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
mTrusted->loading();
mTrusted->setReadonly(!allow_modify);
- std::string url = region->getCapability("RegionExperiences");
- if (!url.empty())
- {
- LLHTTPClient::get(url, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
- getDerivedHandle<LLPanelRegionExperiences>(), _1)));
- }
- return LLPanelRegionInfo::refreshFromRegion(region);
+ LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1),
+ boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1));
+
+ return LLPanelRegionInfo::refreshFromRegion(region);
}
LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
@@ -3793,18 +3720,15 @@ LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
BOOL LLPanelRegionExperiences::sendUpdate()
{
LLViewerRegion* region = gAgent.getRegion();
- std::string url = region->getCapability("RegionExperiences");
- if (!url.empty())
- {
- LLSD content;
- content["allowed"]=addIds(mAllowed);
- content["blocked"]=addIds(mBlocked);
- content["trusted"]=addIds(mTrusted);
+ LLSD content;
- LLHTTPClient::post(url, content, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
- getDerivedHandle<LLPanelRegionExperiences>(), _1)));
- }
+ content["allowed"]=addIds(mAllowed);
+ content["blocked"]=addIds(mBlocked);
+ content["trusted"]=addIds(mTrusted);
+
+ LLExperienceCache::instance().setRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1),
+ content, boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1));
return TRUE;
}
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index e7b49d8553..3c74618fff 100755
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -36,6 +36,7 @@
#include "llextendedstatus.h"
#include "llenvmanager.h" // for LLEnvironmentSettings
+#include "lleventcoro.h"
class LLAvatarName;
class LLDispatcher;
@@ -107,6 +108,8 @@ private:
LLFloaterRegionInfo(const LLSD& seed);
~LLFloaterRegionInfo();
+
+
protected:
void onTabSelected(const LLSD& param);
@@ -476,6 +479,8 @@ public:
private:
void refreshRegionExperiences();
+ static std::string regionCapabilityQuery(LLViewerRegion* region, const std::string &cap);
+
LLPanelExperienceListEditor* setupList(const char* control_name, U32 add_id, U32 remove_id);
static LLSD addIds( LLPanelExperienceListEditor* panel );
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 2f4d2a93b2..1c2340b0ef 100755
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -77,12 +77,66 @@
#include "lluictrlfactory.h"
#include "llviewernetwork.h"
-#include "llassetuploadresponders.h"
#include "llagentui.h"
#include "lltrans.h"
#include "llexperiencecache.h"
+#include "llcorehttputil.h"
+#include "llviewerassetupload.h"
+
+
+//=========================================================================
+//-----------------------------------------------------------------------------
+// Support classes
+//-----------------------------------------------------------------------------
+class LLARScreenShotUploader : public LLResourceUploadInfo
+{
+public:
+ LLARScreenShotUploader(LLSD report, LLUUID assetId, LLAssetType::EType assetType);
+
+ virtual LLSD prepareUpload();
+ virtual LLSD generatePostBody();
+ virtual S32 getEconomyUploadCost();
+ virtual LLUUID finishUpload(LLSD &result);
+
+ virtual bool showInventoryPanel() const { return false; }
+ virtual std::string getDisplayName() const { return "Abuse Report"; }
+
+private:
+
+ LLSD mReport;
+};
+
+LLARScreenShotUploader::LLARScreenShotUploader(LLSD report, LLUUID assetId, LLAssetType::EType assetType) :
+ LLResourceUploadInfo(assetId, assetType, "Abuse Report"),
+ mReport(report)
+{
+}
+
+LLSD LLARScreenShotUploader::prepareUpload()
+{
+ return LLSD().with("success", LLSD::Boolean(true));
+}
+
+LLSD LLARScreenShotUploader::generatePostBody()
+{ // The report was pregenerated and passed in the constructor.
+ return mReport;
+}
+
+S32 LLARScreenShotUploader::getEconomyUploadCost()
+{ // Abuse report screen shots do not cost anything to upload.
+ return 0;
+}
+
+LLUUID LLARScreenShotUploader::finishUpload(LLSD &result)
+{
+ /* *TODO$: Report success or failure. Carried over from previous todo on responder*/
+ return LLUUID::null;
+}
+
+
+//=========================================================================
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
@@ -214,7 +268,7 @@ void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id)
if (LLUUID::null != mExperienceID)
{
- const LLSD& experience = LLExperienceCache::get(mExperienceID);
+ const LLSD& experience = LLExperienceCache::instance().get(mExperienceID);
std::stringstream desc;
if(experience.isDefined())
@@ -706,59 +760,25 @@ void LLFloaterReporter::sendReportViaLegacy(const LLSD & report)
msg->sendReliable(regionp->getHost());
}
-class LLUserReportScreenshotResponder : public LLAssetUploadResponder
+void LLFloaterReporter::finishedARPost(const LLSD &)
{
-public:
- LLUserReportScreenshotResponder(const LLSD & post_data,
- const LLUUID & vfile_id,
- LLAssetType::EType asset_type):
- LLAssetUploadResponder(post_data, vfile_id, asset_type)
- {
- }
- void uploadFailed(const LLSD& content)
- {
- // *TODO pop up a dialog so the user knows their report screenshot didn't make it
- LLUploadDialog::modalUploadFinished();
- }
- void uploadComplete(const LLSD& content)
- {
- // we don't care about what the server returns from this post, just clean up the UI
- LLUploadDialog::modalUploadFinished();
- }
-};
+ LLUploadDialog::modalUploadFinished();
-class LLUserReportResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLUserReportResponder);
-public:
- LLUserReportResponder(): LLHTTPClient::Responder() {}
-
-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();
- }
-};
+}
void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report)
{
if(getChild<LLUICtrl>("screen_check")->getValue().asBoolean() && !sshot_url.empty())
- {
+ {
// try to upload screenshot
- LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report,
- mResourceDatap->mAssetInfo.mUuid,
- mResourceDatap->mAssetInfo.mType));
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLARScreenShotUploader(report, mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType));
+ LLViewerAssetUpload::EnqueueInventoryUpload(sshot_url, uploadInfo);
}
else
{
- // screenshot not wanted or we don't have screenshot cap
- LLHTTPClient::post(url, report, new LLUserReportResponder());
+ LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t proc = boost::bind(&LLFloaterReporter::finishedARPost, _1);
+ LLUploadDialog::modalUploadDialog("Abuse Report");
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, report, proc, proc);
}
}
diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h
index d857528f10..1aff07bd37 100755
--- a/indra/newview/llfloaterreporter.h
+++ b/indra/newview/llfloaterreporter.h
@@ -122,6 +122,8 @@ private:
void setFromAvatarID(const LLUUID& avatar_id);
void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);
+ static void finishedARPost(const LLSD &);
+
private:
EReportType mReportType;
LLUUID mObjectID;
diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp
index 5fbdd75e97..7b8fc5b35b 100755
--- a/indra/newview/llfloaterscriptlimits.cpp
+++ b/indra/newview/llfloaterscriptlimits.cpp
@@ -50,6 +50,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
+#include "llcorehttputil.h"
///----------------------------------------------------------------------------
/// LLFloaterScriptLimits
@@ -180,372 +181,6 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)
}
///----------------------------------------------------------------------------
-// Responders
-///----------------------------------------------------------------------------
-
-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
-
- LLSDNotationStreamer notation_streamer(content);
- std::ostringstream nice_llsd;
- nice_llsd << notation_streamer;
-
- OSMessageBox(nice_llsd.str(), "main cap response:", 0);
-
- LL_INFOS() << "main cap response:" << content << LL_ENDL;
-
-#endif
-
- // at this point we have an llsd which should contain ether one or two urls to the services we want.
- // first we look for the details service:
- if(content.has("ScriptResourceDetails"))
- {
- LLHTTPClient::get(content["ScriptResourceDetails"], new fetchScriptLimitsRegionDetailsResponder(mInfo));
- }
- else
- {
- LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
- if(!instance)
- {
- LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
- }
- }
-
- // then the summary service:
- if(content.has("ScriptResourceSummary"))
- {
- LLHTTPClient::get(content["ScriptResourceSummary"], new fetchScriptLimitsRegionSummaryResponder(mInfo));
- }
-}
-
-void fetchScriptLimitsRegionInfoResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-}
-
-void fetchScriptLimitsRegionSummaryResponder::httpSuccess()
-{
- const LLSD& content_ref = getContent();
-#ifdef USE_FAKE_RESPONSES
-
- LLSD fake_content;
- LLSD summary = LLSD::emptyMap();
- LLSD available = LLSD::emptyArray();
- LLSD available_urls = LLSD::emptyMap();
- LLSD available_memory = LLSD::emptyMap();
- LLSD used = LLSD::emptyArray();
- LLSD used_urls = LLSD::emptyMap();
- LLSD used_memory = LLSD::emptyMap();
-
- used_urls["type"] = "urls";
- used_urls["amount"] = FAKE_NUMBER_OF_URLS;
- available_urls["type"] = "urls";
- available_urls["amount"] = FAKE_AVAILABLE_URLS;
- used_memory["type"] = "memory";
- used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY;
- available_memory["type"] = "memory";
- available_memory["amount"] = FAKE_AVAILABLE_MEMORY;
-
-//summary response:{'summary':{'available':[{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'},{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'}],'used':[{'amount':i329,'type':'urls'},{'amount':i66741,'type':'memory'}]}}
-
- used.append(used_urls);
- used.append(used_memory);
- available.append(available_urls);
- available.append(available_memory);
-
- summary["available"] = available;
- summary["used"] = used;
-
- fake_content["summary"] = summary;
-
- const LLSD& content = fake_content;
-
-#else
-
- const LLSD& content = content_ref;
-
-#endif
-
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
-
-
-#ifdef DUMP_REPLIES_TO_LLINFOS
-
- LLSDNotationStreamer notation_streamer(content);
- std::ostringstream nice_llsd;
- nice_llsd << notation_streamer;
-
- OSMessageBox(nice_llsd.str(), "summary response:", 0);
-
- LL_WARNS() << "summary response:" << *content << LL_ENDL;
-
-#endif
-
- LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
- if(!instance)
- {
- LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
- }
- else
- {
- LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
- if(tab)
- {
- 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("")));
-
- LLButton* btn = panel_memory->getChild<LLButton>("refresh_list_btn");
- if(btn)
- {
- btn->setEnabled(true);
- }
-
- panel_memory->setRegionSummary(content);
- }
- }
- }
-}
-
-void fetchScriptLimitsRegionSummaryResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-}
-
-void fetchScriptLimitsRegionDetailsResponder::httpSuccess()
-{
- const LLSD& content_ref = getContent();
-#ifdef USE_FAKE_RESPONSES
-/*
-Updated detail service, ** denotes field added:
-
-result (map)
-+-parcels (array of maps)
- +-id (uuid)
- +-local_id (S32)**
- +-name (string)
- +-owner_id (uuid) (in ERS as owner, but owner_id in code)
- +-objects (array of maps)
- +-id (uuid)
- +-name (string)
- +-owner_id (uuid) (in ERS as owner, in code as owner_id)
- +-owner_name (sting)**
- +-location (map)**
- +-x (float)
- +-y (float)
- +-z (float)
- +-resources (map) (this is wrong in the ERS but right in code)
- +-type (string)
- +-amount (int)
-*/
- LLSD fake_content;
- LLSD resource = LLSD::emptyMap();
- LLSD location = LLSD::emptyMap();
- LLSD object = LLSD::emptyMap();
- LLSD objects = LLSD::emptyArray();
- LLSD parcel = LLSD::emptyMap();
- LLSD parcels = LLSD::emptyArray();
-
- resource["urls"] = FAKE_NUMBER_OF_URLS;
- resource["memory"] = FAKE_AMOUNT_OF_MEMORY;
-
- location["x"] = 128.0f;
- location["y"] = 128.0f;
- location["z"] = 0.0f;
-
- object["id"] = LLUUID("d574a375-0c6c-fe3d-5733-da669465afc7");
- object["name"] = "Gabs fake Object!";
- object["owner_id"] = LLUUID("8dbf2d41-69a0-4e5e-9787-0c9d297bc570");
- object["owner_name"] = "Gabs Linden";
- object["location"] = location;
- object["resources"] = resource;
-
- objects.append(object);
-
- parcel["id"] = LLUUID("da05fb28-0d20-e593-2728-bddb42dd0160");
- parcel["local_id"] = 42;
- parcel["name"] = "Gabriel Linden\'s Sub Plot";
- parcel["objects"] = objects;
- parcels.append(parcel);
-
- fake_content["parcels"] = parcels;
- const LLSD& content = fake_content;
-
-#else
-
- const LLSD& content = content_ref;
-
-#endif
-
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
-
-#ifdef DUMP_REPLIES_TO_LLINFOS
-
- LLSDNotationStreamer notation_streamer(content);
- std::ostringstream nice_llsd;
- nice_llsd << notation_streamer;
-
- OSMessageBox(nice_llsd.str(), "details response:", 0);
-
- LL_INFOS() << "details response:" << content << LL_ENDL;
-
-#endif
-
- LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
-
- if(!instance)
- {
- LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
- }
- else
- {
- LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
- if(tab)
- {
- LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
- if(panel_memory)
- {
- panel_memory->setRegionDetails(content);
- }
- else
- {
- LL_WARNS() << "Failed to get scriptlimits memory panel" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL;
- }
- }
-}
-
-void fetchScriptLimitsRegionDetailsResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-}
-
-void fetchScriptLimitsAttachmentInfoResponder::httpSuccess()
-{
- const LLSD& content_ref = getContent();
-
-#ifdef USE_FAKE_RESPONSES
-
- // just add the summary, as that's all I'm testing currently!
- LLSD fake_content = LLSD::emptyMap();
- LLSD summary = LLSD::emptyMap();
- LLSD available = LLSD::emptyArray();
- LLSD available_urls = LLSD::emptyMap();
- LLSD available_memory = LLSD::emptyMap();
- LLSD used = LLSD::emptyArray();
- LLSD used_urls = LLSD::emptyMap();
- LLSD used_memory = LLSD::emptyMap();
-
- used_urls["type"] = "urls";
- used_urls["amount"] = FAKE_NUMBER_OF_URLS;
- available_urls["type"] = "urls";
- available_urls["amount"] = FAKE_AVAILABLE_URLS;
- used_memory["type"] = "memory";
- used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY;
- available_memory["type"] = "memory";
- available_memory["amount"] = FAKE_AVAILABLE_MEMORY;
-
- used.append(used_urls);
- used.append(used_memory);
- available.append(available_urls);
- available.append(available_memory);
-
- summary["available"] = available;
- summary["used"] = used;
-
- fake_content["summary"] = summary;
- fake_content["attachments"] = content_ref["attachments"];
-
- const LLSD& content = fake_content;
-
-#else
-
- const LLSD& content = content_ref;
-
-#endif
-
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
-
-#ifdef DUMP_REPLIES_TO_LLINFOS
-
- LLSDNotationStreamer notation_streamer(content);
- std::ostringstream nice_llsd;
- nice_llsd << notation_streamer;
-
- OSMessageBox(nice_llsd.str(), "attachment response:", 0);
-
- LL_INFOS() << "attachment response:" << content << LL_ENDL;
-
-#endif
-
- LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
-
- if(!instance)
- {
- LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
- }
- else
- {
- LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
- if(tab)
- {
- LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel");
- if(panel)
- {
- panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
-
- LLButton* btn = panel->getChild<LLButton>("refresh_list_btn");
- if(btn)
- {
- btn->setEnabled(true);
- }
-
- panel->setAttachmentDetails(content);
- }
- else
- {
- LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL;
- }
- }
-}
-
-void fetchScriptLimitsAttachmentInfoResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-}
-
-///----------------------------------------------------------------------------
// Memory Panel
///----------------------------------------------------------------------------
@@ -564,12 +199,8 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources()
std::string url = gAgent.getRegion()->getCapability("LandResources");
if (!url.empty())
{
- body["parcel_id"] = mParcelId;
-
- LLSD info;
- info["parcel_id"] = mParcelId;
- LLHTTPClient::post(url, body, new fetchScriptLimitsRegionInfoResponder(info));
-
+ LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro",
+ boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro, this, url));
return TRUE;
}
else
@@ -578,6 +209,147 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources()
}
}
+void LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptResourcesCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD postData;
+
+ postData["parcel_id"] = mParcelId;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Failed to get script resource info" << LL_ENDL;
+ return;
+ }
+
+ // We could retrieve these sequentially inline from this coroutine. But
+ // since the original code retrieved them in parallel I'll spawn two
+ // coroutines to do the retrieval.
+
+ // The summary service:
+ if (result.has("ScriptResourceSummary"))
+ {
+ std::string urlResourceSummary = result["ScriptResourceSummary"].asString();
+ LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro",
+ boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro, this, urlResourceSummary));
+ }
+
+ if (result.has("ScriptResourceDetails"))
+ {
+ std::string urlResourceDetails = result["ScriptResourceDetails"].asString();
+ LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro",
+ boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro, this, urlResourceDetails));
+ }
+
+
+}
+
+void LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptSummaryCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Unable to retrieve script summary." << LL_ENDL;
+ return;
+ }
+
+ LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
+ if (!instance)
+ {
+ LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
+ return;
+ }
+
+ LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
+ if (!tab)
+ {
+ LL_WARNS() << "Unable to access script limits tab" << LL_ENDL;
+ return;
+ }
+
+ LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
+ if (!panelMemory)
+ {
+ LL_WARNS() << "Unable to get memory panel." << LL_ENDL;
+ return;
+ }
+
+ panelMemory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
+
+ LLButton* btn = panelMemory->getChild<LLButton>("refresh_list_btn");
+ if (btn)
+ {
+ btn->setEnabled(true);
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ panelMemory->setRegionSummary(result);
+
+}
+
+void LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptDetailsCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Unable to retrieve script details." << LL_ENDL;
+ return;
+ }
+
+ LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
+
+ if (!instance)
+ {
+ LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
+ return;
+ }
+
+ LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
+ if (!tab)
+ {
+ LL_WARNS() << "Unable to access script limits tab" << LL_ENDL;
+ return;
+ }
+
+ LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel");
+
+ if (!panelMemory)
+ {
+ LL_WARNS() << "Unable to get memory panel." << LL_ENDL;
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ panelMemory->setRegionDetails(result);
+}
+
void LLPanelScriptLimitsRegionMemory::processParcelInfo(const LLParcelData& parcel_data)
{
if(!getLandScriptResources())
@@ -935,17 +707,8 @@ BOOL LLPanelScriptLimitsRegionMemory::StartRequestChain()
std::string url = region->getCapability("RemoteParcelRequest");
if (!url.empty())
{
- body["location"] = ll_sd_from_vector3(parcel_center);
- if (!region_id.isNull())
- {
- body["region_id"] = region_id;
- }
- if (!pos_global.isExactlyZero())
- {
- U64 region_handle = to_region_handle(pos_global);
- body["region_handle"] = ll_sd_from_U64(region_handle);
- }
- LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
+ LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url,
+ region_id, parcel_center, pos_global, getObserverHandle());
}
else
{
@@ -1183,7 +946,8 @@ BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails()
std::string url = gAgent.getRegion()->getCapability("AttachmentResources");
if (!url.empty())
{
- LLHTTPClient::get(url, body, new fetchScriptLimitsAttachmentInfoResponder());
+ LLCoros::instance().launch("LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro",
+ boost::bind(&LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro, this, url));
return TRUE;
}
else
@@ -1192,6 +956,59 @@ BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails()
}
}
+void LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL;
+ return;
+ }
+
+ LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits");
+
+ if (!instance)
+ {
+ LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL;
+ return;
+ }
+
+ LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels");
+ if (!tab)
+ {
+ LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL;
+ return;
+ }
+
+ LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel");
+ if (!panel)
+ {
+ LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL;
+ return;
+ }
+
+ panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string("")));
+
+ LLButton* btn = panel->getChild<LLButton>("refresh_list_btn");
+ if (btn)
+ {
+ btn->setEnabled(true);
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ panel->setAttachmentDetails(result);
+}
+
+
void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content)
{
LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list");
diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h
index 5ba0185d32..e3cbbd185f 100755
--- a/indra/newview/llfloaterscriptlimits.h
+++ b/indra/newview/llfloaterscriptlimits.h
@@ -33,6 +33,8 @@
#include "llhost.h"
#include "llpanel.h"
#include "llremoteparcelrequest.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLPanelScriptLimitsInfo;
class LLTabContainer;
@@ -80,57 +82,6 @@ protected:
};
/////////////////////////////////////////////////////////////////////////////
-// Responders
-/////////////////////////////////////////////////////////////////////////////
-
-class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(fetchScriptLimitsRegionInfoResponder);
-public:
- fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {};
-
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
- LLSD mInfo;
-};
-
-class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(fetchScriptLimitsRegionSummaryResponder);
-public:
- fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {};
-
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
- LLSD mInfo;
-};
-
-class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(fetchScriptLimitsRegionDetailsResponder);
-public:
- fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {};
-
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
- LLSD mInfo;
-};
-
-class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder);
-public:
- fetchScriptLimitsAttachmentInfoResponder() {};
-
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
-};
-
-/////////////////////////////////////////////////////////////////////////////
// Memory panel
/////////////////////////////////////////////////////////////////////////////
@@ -181,6 +132,10 @@ private:
std::vector<LLSD> mObjectListItems;
+ void getLandScriptResourcesCoro(std::string url);
+ void getLandScriptSummaryCoro(std::string url);
+ void getLandScriptDetailsCoro(std::string url);
+
protected:
// LLRemoteParcelInfoObserver interface:
@@ -225,6 +180,7 @@ public:
void clearList();
private:
+ void getAttachmentLimitsCoro(std::string url);
bool mGotAttachmentMemoryUsed;
S32 mAttachmentMemoryMax;
diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp
index c1c21c593e..f6cfaf5522 100755
--- a/indra/newview/llfloatertos.cpp
+++ b/indra/newview/llfloatertos.cpp
@@ -35,8 +35,6 @@
// linden library includes
#include "llbutton.h"
#include "llevents.h"
-#include "llhttpclient.h"
-#include "llhttpconstants.h"
#include "llnotificationsutil.h"
#include "llradiogroup.h"
#include "lltextbox.h"
@@ -45,7 +43,7 @@
#include "llvfile.h"
#include "message.h"
#include "llstartup.h" // login_alert_done
-
+#include "llcorehttputil.h"
LLFloaterTOS::LLFloaterTOS(const LLSD& data)
: LLModalDialog( data["message"].asString() ),
@@ -57,57 +55,6 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)
{
}
-// helper class that trys to download a URL from a web site and calls a method
-// on parent class indicating if the web server is working or not
-class LLIamHere : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLIamHere);
-private:
- LLIamHere( LLFloaterTOS* parent ) :
- mParent( parent )
- {}
-
- LLFloaterTOS* mParent;
-
-public:
- static LLIamHere* build( LLFloaterTOS* parent )
- {
- return new LLIamHere( parent );
- }
-
- virtual void setParent( LLFloaterTOS* parentIn )
- {
- mParent = parentIn;
- }
-
-protected:
- virtual void httpSuccess()
- {
- if ( mParent )
- {
- mParent->setSiteIsAlive( true );
- }
- }
-
- virtual void httpFailure()
- {
- LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL;
- 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 = (getStatus() == HTTP_FOUND);
- mParent->setSiteIsAlive( alive );
- }
- }
-};
-
-// this is global and not a class member to keep crud out of the header file
-namespace {
- LLPointer< LLIamHere > gResponsePtr = 0;
-};
-
BOOL LLFloaterTOS::postBuild()
{
childSetAction("Continue", onContinue, this);
@@ -180,9 +127,6 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )
LLFloaterTOS::~LLFloaterTOS()
{
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
}
// virtual
@@ -243,9 +187,10 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
if(!mLoadingScreenLoaded)
{
mLoadingScreenLoaded = true;
+ std::string url(getString("real_url"));
- gResponsePtr = LLIamHere::build( this );
- LLHTTPClient::get( getString( "real_url" ), gResponsePtr );
+ LLCoros::instance().launch("LLFloaterTOS::testSiteIsAliveCoro",
+ boost::bind(&LLFloaterTOS::testSiteIsAliveCoro, this, url));
}
else if(mRealNavigateBegun)
{
@@ -257,3 +202,26 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev
}
}
+void LLFloaterTOS::testSiteIsAliveCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+
+ LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ // double not.
+ // First ! returns a boolean error status, second ! is true if success result.
+ setSiteIsAlive(!!status);
+}
+
+
diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h
index 47126d06a6..2748b20513 100755
--- a/indra/newview/llfloatertos.h
+++ b/indra/newview/llfloatertos.h
@@ -31,6 +31,8 @@
#include "llassetstorage.h"
#include "llmediactrl.h"
#include <boost/function.hpp>
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLButton;
class LLRadioGroup;
@@ -60,12 +62,15 @@ public:
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
private:
+ void testSiteIsAliveCoro(std::string url);
std::string mMessage;
bool mLoadingScreenLoaded;
bool mSiteAlive;
bool mRealNavigateBegun;
std::string mReplyPumpName;
+
+
};
#endif // LL_LLFLOATERTOS_H
diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp
index 965d29b09c..b1316e386d 100755
--- a/indra/newview/llfloatertranslationsettings.cpp
+++ b/indra/newview/llfloatertranslationsettings.cpp
@@ -42,41 +42,6 @@
#include "llnotificationsutil.h"
#include "llradiogroup.h"
-class EnteredKeyVerifier : public LLTranslate::KeyVerificationReceiver
-{
-public:
- EnteredKeyVerifier(LLTranslate::EService service, bool alert)
- : LLTranslate::KeyVerificationReceiver(service)
- , mAlert(alert)
- {
- }
-
-private:
- /*virtual*/ void setVerificationStatus(bool ok)
- {
- LLFloaterTranslationSettings* floater =
- LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
-
- if (!floater)
- {
- LL_WARNS() << "Cannot find translation settings floater" << LL_ENDL;
- return;
- }
-
- switch (getService())
- {
- case LLTranslate::SERVICE_BING:
- floater->setBingVerified(ok, mAlert);
- break;
- case LLTranslate::SERVICE_GOOGLE:
- floater->setGoogleVerified(ok, mAlert);
- break;
- }
- }
-
- bool mAlert;
-};
-
LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key)
: LLFloater(key)
, mMachineTranslationCB(NULL)
@@ -231,11 +196,34 @@ void LLFloaterTranslationSettings::updateControlsEnabledState()
mOKBtn->setEnabled(!on || service_verified);
}
+/*static*/
+void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert)
+{
+ LLFloaterTranslationSettings* floater =
+ LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
+
+ if (!floater)
+ {
+ LL_WARNS() << "Cannot find translation settings floater" << LL_ENDL;
+ return;
+ }
+
+ switch (service)
+ {
+ case LLTranslate::SERVICE_BING:
+ floater->setBingVerified(ok, alert);
+ break;
+ case LLTranslate::SERVICE_GOOGLE:
+ floater->setGoogleVerified(ok, alert);
+ break;
+ }
+}
+
+
void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert)
{
- LLTranslate::KeyVerificationReceiverPtr receiver =
- new EnteredKeyVerifier((LLTranslate::EService) service, alert);
- LLTranslate::verifyKey(receiver, key);
+ LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key,
+ boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert));
}
void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control)
diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h
index b9bfd6265a..2a15eacded 100755
--- a/indra/newview/llfloatertranslationsettings.h
+++ b/indra/newview/llfloatertranslationsettings.h
@@ -61,6 +61,8 @@ private:
void onBtnGoogleVerify();
void onBtnOK();
+ static void setVerificationStatus(int service, bool alert, bool ok);
+
LLCheckBoxCtrl* mMachineTranslationCB;
LLComboBox* mLanguageCombo;
LLLineEditor* mBingAPIKeyEditor;
diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp
index e02e8eeb5a..f2efef0c33 100755
--- a/indra/newview/llfloaterurlentry.cpp
+++ b/indra/newview/llfloaterurlentry.cpp
@@ -26,8 +26,6 @@
#include "llviewerprecompiledheaders.h"
-#include "llhttpclient.h"
-
#include "llfloaterurlentry.h"
#include "llpanellandmedia.h"
@@ -40,40 +38,10 @@
#include "lluictrlfactory.h"
#include "llwindow.h"
#include "llviewerwindow.h"
+#include "llcorehttputil.h"
static LLFloaterURLEntry* sInstance = NULL;
-// Move this to its own file.
-// helper class that tries to download a URL from a web site and calls a method
-// 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;
-
-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 );
- }
- }
-};
-
//-----------------------------------------------------------------------------
// LLFloaterURLEntry()
//-----------------------------------------------------------------------------
@@ -225,8 +193,8 @@ void LLFloaterURLEntry::onBtnOK( void* userdata )
if(!media_url.empty() &&
(scheme == "http" || scheme == "https"))
{
- LLHTTPClient::getHeaderOnly( media_url,
- new LLMediaTypeResponder(self->getHandle()));
+ LLCoros::instance().launch("LLFloaterURLEntry::getMediaTypeCoro",
+ boost::bind(&LLFloaterURLEntry::getMediaTypeCoro, media_url, self->getHandle()));
}
else
{
@@ -240,6 +208,58 @@ void LLFloaterURLEntry::onBtnOK( void* userdata )
}
// static
+void LLFloaterURLEntry::getMediaTypeCoro(std::string url, LLHandle<LLFloater> parentHandle)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMediaTypeCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+ httpOpts->setHeadersOnly(true);
+
+ LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ LLFloaterURLEntry* floaterUrlEntry = (LLFloaterURLEntry*)parentHandle.get();
+ if (!floaterUrlEntry)
+ {
+ LL_WARNS() << "Could not get URL entry floater." << LL_ENDL;
+ return;
+ }
+
+ // Set empty type to none/none. Empty string is reserved for legacy parcels
+ // which have no mime type set.
+ std::string resolvedMimeType = LLMIMETypes::getDefaultMimeType();
+
+ if (!status)
+ {
+ floaterUrlEntry->headerFetchComplete(status.getType(), resolvedMimeType);
+ return;
+ }
+
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+
+ if (resultHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE))
+ {
+ const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE];
+ std::string::size_type idx1 = mediaType.find_first_of(";");
+ std::string mimeType = mediaType.substr(0, idx1);
+ if (!mimeType.empty())
+ {
+ resolvedMimeType = mimeType;
+ }
+ }
+
+ floaterUrlEntry->headerFetchComplete(status.getType(), resolvedMimeType);
+
+}
+
+// static
//-----------------------------------------------------------------------------
// onBtnCancel()
//-----------------------------------------------------------------------------
diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h
index bdd1ebe592..20f4604907 100755
--- a/indra/newview/llfloaterurlentry.h
+++ b/indra/newview/llfloaterurlentry.h
@@ -29,6 +29,8 @@
#include "llfloater.h"
#include "llpanellandmedia.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLLineEditor;
class LLComboBox;
@@ -56,7 +58,10 @@ private:
static void onBtnOK(void*);
static void onBtnCancel(void*);
static void onBtnClear(void*);
- bool callback_clear_url_list(const LLSD& notification, const LLSD& response);
+ bool callback_clear_url_list(const LLSD& notification, const LLSD& response);
+
+ static void getMediaTypeCoro(std::string url, LLHandle<LLFloater> parentHandle);
+
};
#endif // LL_LLFLOATERURLENTRY_H
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 86f9da6318..4559132aeb 100755
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -41,7 +41,6 @@
#include "llui.h"
#include "message.h"
#include "roles_constants.h"
-#include "llhttpclient.h"
#include "lltransactiontypes.h"
#include "llstatusbar.h"
#include "lleconomy.h"
@@ -53,6 +52,7 @@
#include "lltrans.h"
#include "llviewerregion.h"
#include <boost/regex.hpp>
+#include "llcorehttputil.h"
#if LL_MSVC
#pragma warning(push)
@@ -768,9 +768,9 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)
// LLGroupMgr
//
-LLGroupMgr::LLGroupMgr()
+LLGroupMgr::LLGroupMgr():
+ mMemberRequestInFlight(false)
{
- mLastGroupMembersRequestFrame = 0;
}
LLGroupMgr::~LLGroupMgr()
@@ -1861,49 +1861,94 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
group_datap->mMemberVersion.generate();
}
-
-// Responder class for capability group management
-class GroupBanDataResponder : public LLHTTPClient::Responder
+void LLGroupMgr::getGroupBanRequestCoro(std::string url, LLUUID groupId)
{
-public:
- GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false);
- virtual ~GroupBanDataResponder() {}
- virtual void httpSuccess();
- virtual void httpFailure();
-private:
- LLUUID mGroupID;
- BOOL mForceRefresh;
-};
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
-GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) :
- mGroupID(gropup_id),
- mForceRefresh(force_refresh)
-{}
+ std::string finalUrl = url + "?group_id=" + groupId.asString();
-void GroupBanDataResponder::httpFailure()
-{
- LL_WARNS("GrpMgr") << "Error receiving group member data [status:"
- << mStatus << "]: " << mContent << LL_ENDL;
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL;
+ return;
+ }
+
+ if (result.has("ban_list"))
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ // group ban data received
+ processGroupBanRequest(result);
+ }
}
-void GroupBanDataResponder::httpSuccess()
+void LLGroupMgr::postGroupBanRequestCoro(std::string url, LLUUID groupId,
+ U32 action, uuid_vec_t banList, bool update)
{
- if (mContent.has("ban_list"))
- {
- // group ban data received
- LLGroupMgr::processGroupBanRequest(mContent);
- }
- else if (mForceRefresh)
- {
- // no ban data received, refreshing data after successful operation
- LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID);
- }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
+
+ httpOptions->setFollowRedirects(false);
+
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
+
+
+ std::string finalUrl = url + "?group_id=" + groupId.asString();
+
+ LLSD postData = LLSD::emptyMap();
+ postData["ban_action"] = (LLSD::Integer)action;
+ // Add our list of potential banned residents to the list
+ postData["ban_ids"] = LLSD::emptyArray();
+ LLSD banEntry;
+
+ uuid_vec_t::const_iterator it = banList.begin();
+ for (; it != banList.end(); ++it)
+ {
+ banEntry = (*it);
+ postData["ban_ids"].append(banEntry);
+ }
+
+ LL_WARNS() << "post: " << ll_pretty_print_sd(postData) << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, finalUrl, postData, httpOptions, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("GrpMgr") << "Error posting group member data " << LL_ENDL;
+ return;
+ }
+
+ if (result.has("ban_list"))
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ // group ban data received
+ processGroupBanRequest(result);
+ }
+
+ if (update)
+ {
+ getGroupBanRequestCoro(url, groupId);
+ }
}
void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type,
const LLUUID& group_id,
U32 ban_action, /* = BAN_NO_ACTION */
- const std::vector<LLUUID> ban_list) /* = std::vector<LLUUID>() */
+ const std::vector<LLUUID> &ban_list) /* = std::vector<LLUUID>() */
{
LLViewerRegion* currentRegion = gAgent.getRegion();
if(!currentRegion)
@@ -1925,37 +1970,27 @@ void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type,
{
return;
}
- cap_url += "?group_id=" + group_id.asString();
-
- LLSD body = LLSD::emptyMap();
- body["ban_action"] = (LLSD::Integer)(ban_action & ~BAN_UPDATE);
- // Add our list of potential banned residents to the list
- body["ban_ids"] = LLSD::emptyArray();
- LLSD ban_entry;
- uuid_vec_t::const_iterator iter = ban_list.begin();
- for(;iter != ban_list.end(); ++iter)
- {
- ban_entry = (*iter);
- body["ban_ids"].append(ban_entry);
- }
+ U32 action = ban_action & ~BAN_UPDATE;
+ bool update = ((ban_action & BAN_UPDATE) == BAN_UPDATE);
- LLHTTPClient::ResponderPtr grp_ban_responder = new GroupBanDataResponder(group_id, ban_action & BAN_UPDATE);
- switch(request_type)
- {
- case REQUEST_GET:
- LLHTTPClient::get(cap_url, grp_ban_responder);
- break;
- case REQUEST_POST:
- LLHTTPClient::post(cap_url, body, grp_ban_responder);
- break;
- case REQUEST_PUT:
- case REQUEST_DEL:
- break;
- }
+ switch (request_type)
+ {
+ case REQUEST_GET:
+ LLCoros::instance().launch("LLGroupMgr::getGroupBanRequestCoro",
+ boost::bind(&LLGroupMgr::getGroupBanRequestCoro, this, cap_url, group_id));
+ break;
+ case REQUEST_POST:
+ LLCoros::instance().launch("LLGroupMgr::postGroupBanRequestCoro",
+ boost::bind(&LLGroupMgr::postGroupBanRequestCoro, this, cap_url, group_id,
+ action, ban_list, update));
+ break;
+ case REQUEST_PUT:
+ case REQUEST_DEL:
+ break;
+ }
}
-
void LLGroupMgr::processGroupBanRequest(const LLSD& content)
{
// Did we get anything in content?
@@ -1993,45 +2028,42 @@ void LLGroupMgr::processGroupBanRequest(const LLSD& content)
LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);
}
+void LLGroupMgr::groupMembersRequestCoro(std::string url, LLUUID groupId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+ mMemberRequestInFlight = true;
-// Responder class for capability group management
-class GroupMemberDataResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(GroupMemberDataResponder);
-public:
- GroupMemberDataResponder() {}
- virtual ~GroupMemberDataResponder() {}
+ LLSD postData = LLSD::emptyMap();
+ postData["group_id"] = groupId;
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
- LLSD mMemberData;
-};
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
-void GroupMemberDataResponder::httpFailure()
-{
- LL_WARNS("GrpMgr") << "Error receiving group member data "
- << dumpResponse() << LL_ENDL;
-}
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-void GroupMemberDataResponder::httpSuccess()
-{
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- LLGroupMgr::processCapGroupMembersRequest(content);
-}
+ if (!status)
+ {
+ LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL;
+ mMemberRequestInFlight = false;
+ return;
+ }
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ LLGroupMgr::processCapGroupMembersRequest(result);
+ mMemberRequestInFlight = false;
+}
-// static
void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id)
{
+ static U32 lastGroupMemberRequestFrame = 0;
+
// Have we requested the information already this frame?
- if(mLastGroupMembersRequestFrame == gFrameCount)
+ if ((lastGroupMemberRequestFrame == gFrameCount) || (mMemberRequestInFlight))
return;
LLViewerRegion* currentRegion = gAgent.getRegion();
@@ -2060,20 +2092,13 @@ void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id)
return;
}
- // Post to our service. Add a body containing the group_id.
- LLSD body = LLSD::emptyMap();
- body["group_id"] = group_id;
+ lastGroupMemberRequestFrame = gFrameCount;
- LLHTTPClient::ResponderPtr grp_data_responder = new GroupMemberDataResponder();
-
- // This could take a while to finish, timeout after 5 minutes.
- LLHTTPClient::post(cap_url, body, grp_data_responder, LLSD(), 300);
-
- mLastGroupMembersRequestFrame = gFrameCount;
+ LLCoros::instance().launch("LLGroupMgr::groupMembersRequestCoro",
+ boost::bind(&LLGroupMgr::groupMembersRequestCoro, this, cap_url, group_id));
}
-// static
void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
{
// Did we get anything in content?
@@ -2090,7 +2115,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
LLUUID group_id = content["group_id"].asUUID();
- LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id);
+ LLGroupMgrGroupData* group_datap = getGroupData(group_id);
if(!group_datap)
{
LL_WARNS("GrpMgr") << "Received incorrect, possibly stale, group or request id" << LL_ENDL;
@@ -2184,7 +2209,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
// TODO:
// Refactor to reduce multiple calls for data we already have.
if(group_datap->mTitles.size() < 1)
- LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id);
+ sendGroupTitlesRequest(group_id);
group_datap->mMemberDataComplete = true;
@@ -2193,11 +2218,11 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete)
{
group_datap->mPendingRoleMemberRequest = false;
- LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id);
+ sendGroupRoleMembersRequest(group_id);
}
group_datap->mChanged = TRUE;
- LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+ notifyObservers(GC_MEMBER_DATA);
}
diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h
index 2e94e8d9a0..fd0c2de854 100755
--- a/indra/newview/llgroupmgr.h
+++ b/indra/newview/llgroupmgr.h
@@ -32,6 +32,8 @@
#include <vector>
#include <string>
#include <map>
+#include "lleventcoro.h"
+#include "llcoros.h"
// Forward Declarations
class LLMessageSystem;
@@ -362,6 +364,7 @@ public:
BAN_UPDATE = 4
};
+
public:
LLGroupMgr();
~LLGroupMgr();
@@ -396,15 +399,13 @@ public:
static void sendGroupMemberEjects(const LLUUID& group_id,
uuid_vec_t& member_ids);
- static void sendGroupBanRequest(EBanRequestType request_type,
+ void sendGroupBanRequest(EBanRequestType request_type,
const LLUUID& group_id,
U32 ban_action = BAN_NO_ACTION,
- const uuid_vec_t ban_list = uuid_vec_t());
+ const uuid_vec_t &ban_list = uuid_vec_t());
- static void processGroupBanRequest(const LLSD& content);
void sendCapGroupMembersRequest(const LLUUID& group_id);
- static void processCapGroupMembersRequest(const LLSD& content);
void cancelGroupRoleChanges(const LLUUID& group_id);
@@ -427,6 +428,14 @@ public:
void clearGroupData(const LLUUID& group_id);
private:
+ void groupMembersRequestCoro(std::string url, LLUUID groupId);
+ void processCapGroupMembersRequest(const LLSD& content);
+
+ void getGroupBanRequestCoro(std::string url, LLUUID groupId);
+ void postGroupBanRequestCoro(std::string url, LLUUID groupId, U32 action, uuid_vec_t banList, bool update);
+
+ static void processGroupBanRequest(const LLSD& content);
+
void notifyObservers(LLGroupChange gc);
void notifyObserver(const LLUUID& group_id, LLGroupChange gc);
void addGroup(LLGroupMgrGroupData* group_datap);
@@ -442,7 +451,7 @@ private:
typedef std::map<LLUUID,observer_set_t> observer_map_t;
observer_map_t mParticularObservers;
- S32 mLastGroupMembersRequestFrame;
+ bool mMemberRequestInFlight;
};
diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp
deleted file mode 100755
index d0492bcdb4..0000000000
--- a/indra/newview/llhomelocationresponder.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * @file llhomelocationresponder.cpp
- * @author Meadhbh Hamrick
- * @brief Processes responses to the HomeLocation CapReq
- *
- * $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$
- */
-
-/* File Inclusions */
-#include "llviewerprecompiledheaders.h"
-
-#include "llhomelocationresponder.h"
-#include "llsdutil.h"
-#include "llagent.h"
-#include "llviewerregion.h"
-
-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 )
- {
- failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content);
- }
- else
- {
- LL_INFOS() << "setting home position" << LL_ENDL;
-
- LLViewerRegion *viewer_region = gAgent.getRegion();
- gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos );
- }
-}
-
-void LLHomeLocationResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-}
diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h
deleted file mode 100755
index adc6c8cb58..0000000000
--- a/indra/newview/llhomelocationresponder.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * @file llhomelocationresponder.h
- * @author Meadhbh Hamrick
- * @brief Processes responses to the HomeLocation CapReq
- *
- * $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_LLHOMELOCATIONRESPONDER_H
-#define LL_LLHOMELOCATIONRESPONDER_H
-
-/* File Inclusions */
-#include "llhttpclient.h"
-
-/* Typedef, Enum, Class, Struct, etc. */
-class LLHomeLocationResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLHomeLocationResponder);
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
-};
-
-#endif
diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp
index 2d4ce6c883..6a2daeeb90 100755
--- a/indra/newview/llhttpretrypolicy.cpp
+++ b/indra/newview/llhttpretrypolicy.cpp
@@ -25,9 +25,23 @@
*/
#include "llviewerprecompiledheaders.h"
-
#include "llhttpretrypolicy.h"
+namespace
+{
+ // Moved from httpconstants.h... only used in this file.
+ 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));
+ }
+}
+
LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx):
mMinDelay(min_delay),
mMaxDelay(max_delay),
@@ -56,7 +70,7 @@ bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header
&& getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time));
}
-bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time)
+bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders::ptr_t &headers, F32& retry_header_time)
{
if (headers)
{
@@ -85,9 +99,9 @@ void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers)
void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response)
{
F32 retry_header_time;
- const LLCore::HttpHeaders *headers = response->getHeaders();
+ const LLCore::HttpHeaders::ptr_t headers = response->getHeaders();
bool has_retry_header_time = getRetryAfter(headers,retry_header_time);
- onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time);
+ onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time);
}
void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time)
@@ -140,3 +154,34 @@ bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const
seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX;
return mShouldRetry;
}
+
+// Moved from httpconstants. Only used by this file.
+// Parses 'Retry-After' header contents and returns seconds until retry should occur.
+/*static*/
+bool LLAdaptiveRetryPolicy::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/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h
index cf79e0b401..af07b4afec 100755
--- a/indra/newview/llhttpretrypolicy.h
+++ b/indra/newview/llhttpretrypolicy.h
@@ -76,10 +76,12 @@ public:
// virtual
bool shouldRetry(F32& seconds_to_wait) const;
+ static bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait);
+
protected:
void init();
bool getRetryAfter(const LLSD& headers, F32& retry_header_time);
- bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time);
+ bool getRetryAfter(const LLCore::HttpHeaders::ptr_t &headers, F32& retry_header_time);
void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time);
private:
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index b8b6bdaa11..53b97a58c5 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -37,7 +37,6 @@
#include "llrect.h"
#include "llerror.h"
#include "llbutton.h"
-#include "llhttpclient.h"
#include "llsdutil_math.h"
#include "llstring.h"
#include "lltextutil.h"
@@ -69,6 +68,7 @@
#include "llconversationlog.h"
#include "message.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
const static std::string ADHOC_NAME_SUFFIX(" Conference");
@@ -79,6 +79,10 @@ const static std::string NEARBY_P2P_BY_AGENT("nearby_P2P_by_agent");
/** Timeout of outgoing session initialization (in seconds) */
const static U32 SESSION_INITIALIZATION_TIMEOUT = 30;
+void startConfrenceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents);
+void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType);
+void start_deprecated_conference_chat(const LLUUID& temp_session_id, const LLUUID& creator_id, const LLUUID& other_participant_id, const LLSD& agents_to_invite);
+
std::string LLCallDialogManager::sPreviousSessionlName = "";
LLIMModel::LLIMSession::SType LLCallDialogManager::sPreviousSessionType = LLIMModel::LLIMSession::P2P_SESSION;
std::string LLCallDialogManager::sCurrentSessionlName = "";
@@ -110,7 +114,7 @@ void process_dnd_im(const LLSD& notification)
{
LLSD data = notification["substitutions"];
LLUUID sessionID = data["SESSION_ID"].asUUID();
- LLUUID fromID = data["FROM_ID"].asUUID();
+ LLUUID fromID = data["FROM_ID"].asUUID();
//re-create the IM session if needed
//(when coming out of DND mode upon app restart)
@@ -131,12 +135,10 @@ void process_dnd_im(const LLSD& notification)
fromID,
false,
false); //will need slight refactor to retrieve whether offline message or not (assume online for now)
- }
-
- notify_of_message(data, true);
}
-
+ notify_of_message(data, true);
+}
static void on_avatar_name_cache_toast(const LLUUID& agent_id,
@@ -387,6 +389,130 @@ void on_new_message(const LLSD& msg)
notify_of_message(msg, false);
}
+void startConfrenceCoro(std::string url,
+ LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD postData;
+ postData["method"] = "start conference";
+ postData["session-id"] = tempSessionId;
+ postData["params"] = agents;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("LLIMModel") << "Failed to start conference" << LL_ENDL;
+ //try an "old school" way.
+ // *TODO: What about other error status codes? 4xx 5xx?
+ if (status == LLCore::HttpStatus(HTTP_BAD_REQUEST))
+ {
+ start_deprecated_conference_chat(
+ tempSessionId,
+ creatorId,
+ otherParticipantId,
+ agents);
+ }
+
+ //else throw an error back to the client?
+ //in theory we should have just have these error strings
+ //etc. set up in this file as opposed to the IMMgr,
+ //but the error string were unneeded here previously
+ //and it is not worth the effort switching over all
+ //the possible different language translations
+ }
+}
+
+void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD postData;
+ postData["method"] = "accept invitation";
+ postData["session-id"] = sessionId;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!gIMMgr)
+ {
+ LL_WARNS("") << "Global IM Manager is NULL" << LL_ENDL;
+ return;
+ }
+
+ if (!status)
+ {
+ LL_WARNS("LLIMModel") << "Bad HTTP response in chatterBoxInvitationCoro" << LL_ENDL;
+ //throw something back to the viewer here?
+
+ gIMMgr->clearPendingAgentListUpdates(sessionId);
+ gIMMgr->clearPendingInvitation(sessionId);
+
+ if (status == LLCore::HttpStatus(HTTP_NOT_FOUND))
+ {
+ static const std::string error_string("session_does_not_exist_error");
+ gIMMgr->showSessionStartError(error_string, sessionId);
+ }
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+
+ LLIMSpeakerMgr* speakerMgr = LLIMModel::getInstance()->getSpeakerManager(sessionId);
+ if (speakerMgr)
+ {
+ //we've accepted our invitation
+ //and received a list of agents that were
+ //currently in the session when the reply was sent
+ //to us. Now, it is possible that there were some agents
+ //to slip in/out between when that message was sent to us
+ //and now.
+
+ //the agent list updates we've received have been
+ //accurate from the time we were added to the session
+ //but unfortunately, our base that we are receiving here
+ //may not be the most up to date. It was accurate at
+ //some point in time though.
+ speakerMgr->setSpeakers(result);
+
+ //we now have our base of users in the session
+ //that was accurate at some point, but maybe not now
+ //so now we apply all of the updates we've received
+ //in case of race conditions
+ speakerMgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(sessionId));
+ }
+
+ if (LLIMMgr::INVITATION_TYPE_VOICE == invitationType)
+ {
+ gIMMgr->startCall(sessionId, LLVoiceChannel::INCOMING_CALL);
+ }
+
+ if ((invitationType == LLIMMgr::INVITATION_TYPE_VOICE
+ || invitationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE)
+ && LLIMModel::getInstance()->findIMSession(sessionId))
+ {
+ // TODO remove in 2010, for voice calls we do not open an IM window
+ //LLFloaterIMSession::show(mSessionID);
+ }
+
+ gIMMgr->clearPendingAgentListUpdates(sessionId);
+ gIMMgr->clearPendingInvitation(sessionId);
+
+}
+
+
LLIMModel::LLIMModel()
{
addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1));
@@ -1465,54 +1591,6 @@ void start_deprecated_conference_chat(
delete[] bucket;
}
-class LLStartConferenceChatResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLStartConferenceChatResponder);
-public:
- LLStartConferenceChatResponder(
- const LLUUID& temp_session_id,
- const LLUUID& creator_id,
- const LLUUID& other_participant_id,
- const LLSD& agents_to_invite)
- {
- mTempSessionID = temp_session_id;
- mCreatorID = creator_id;
- mOtherParticipantID = other_participant_id;
- mAgents = agents_to_invite;
- }
-
-protected:
- virtual void httpFailure()
- {
- //try an "old school" way.
- // *TODO: What about other error status codes? 4xx 5xx?
- if ( getStatus() == HTTP_BAD_REQUEST )
- {
- start_deprecated_conference_chat(
- mTempSessionID,
- mCreatorID,
- mOtherParticipantID,
- mAgents);
- }
-
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- //else throw an error back to the client?
- //in theory we should have just have these error strings
- //etc. set up in this file as opposed to the IMMgr,
- //but the error string were unneeded here previously
- //and it is not worth the effort switching over all
- //the possible different language translations
- }
-
-private:
- LLUUID mTempSessionID;
- LLUUID mCreatorID;
- LLUUID mOtherParticipantID;
-
- LLSD mAgents;
-};
-
// Returns true if any messages were sent, false otherwise.
// Is sort of equivalent to "does the server need to do anything?"
bool LLIMModel::sendStartSession(
@@ -1549,20 +1627,10 @@ bool LLIMModel::sendStartSession(
{
std::string url = region->getCapability(
"ChatSessionRequest");
- LLSD data;
- data["method"] = "start conference";
- data["session-id"] = temp_session_id;
-
- data["params"] = agents;
- LLHTTPClient::post(
- url,
- data,
- new LLStartConferenceChatResponder(
- temp_session_id,
- gAgent.getID(),
- other_participant_id,
- data["params"]));
+ LLCoros::instance().launch("startConfrenceCoro",
+ boost::bind(&startConfrenceCoro, url,
+ temp_session_id, gAgent.getID(), other_participant_id, agents));
}
else
{
@@ -1580,97 +1648,6 @@ bool LLIMModel::sendStartSession(
return false;
}
-//
-// Helper Functions
-//
-
-class LLViewerChatterBoxInvitationAcceptResponder :
- public LLHTTPClient::Responder
-{
- LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder);
-public:
- LLViewerChatterBoxInvitationAcceptResponder(
- const LLUUID& session_id,
- LLIMMgr::EInvitationType invitation_type)
- {
- mSessionID = session_id;
- mInvitiationType = invitation_type;
- }
-
-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);
- if (speaker_mgr)
- {
- //we've accepted our invitation
- //and received a list of agents that were
- //currently in the session when the reply was sent
- //to us. Now, it is possible that there were some agents
- //to slip in/out between when that message was sent to us
- //and now.
-
- //the agent list updates we've received have been
- //accurate from the time we were added to the session
- //but unfortunately, our base that we are receiving here
- //may not be the most up to date. It was accurate at
- //some point in time though.
- speaker_mgr->setSpeakers(content);
-
- //we now have our base of users in the session
- //that was accurate at some point, but maybe not now
- //so now we apply all of the udpates we've received
- //in case of race conditions
- speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID));
- }
-
- if (LLIMMgr::INVITATION_TYPE_VOICE == mInvitiationType)
- {
- gIMMgr->startCall(mSessionID, LLVoiceChannel::INCOMING_CALL);
- }
-
- if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE
- || mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE)
- && LLIMModel::getInstance()->findIMSession(mSessionID))
- {
- // TODO remove in 2010, for voice calls we do not open an IM window
- //LLFloaterIMSession::show(mSessionID);
- }
-
- gIMMgr->clearPendingAgentListUpdates(mSessionID);
- gIMMgr->clearPendingInvitation(mSessionID);
- }
- }
-
- void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- //throw something back to the viewer here?
- if ( gIMMgr )
- {
- gIMMgr->clearPendingAgentListUpdates(mSessionID);
- gIMMgr->clearPendingInvitation(mSessionID);
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- static const std::string error_string("session_does_not_exist_error");
- gIMMgr->showSessionStartError(error_string, mSessionID);
- }
- }
- }
-
-private:
- LLUUID mSessionID;
- LLIMMgr::EInvitationType mInvitiationType;
-};
-
// the other_participant_id is either an agent_id, a group_id, or an inventory
// folder item_id (collection of calling cards)
@@ -2496,15 +2473,9 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload
if (voice)
{
- LLSD data;
- data["method"] = "accept invitation";
- data["session-id"] = session_id;
- LLHTTPClient::post(
- url,
- data,
- new LLViewerChatterBoxInvitationAcceptResponder(
- session_id,
- inv_type));
+ LLCoros::instance().launch("chatterBoxInvitationCoro",
+ boost::bind(&chatterBoxInvitationCoro, url,
+ session_id, inv_type));
// send notification message to the corresponding chat
if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc")
@@ -2539,10 +2510,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload
LLSD data;
data["method"] = "decline invitation";
data["session-id"] = session_id;
- LLHTTPClient::post(
- url,
- data,
- NULL);
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data,
+ "Invitation declined",
+ "Invitation decline failed.");
}
}
@@ -2589,15 +2560,9 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)
std::string url = gAgent.getRegion()->getCapability(
"ChatSessionRequest");
- LLSD data;
- data["method"] = "accept invitation";
- data["session-id"] = session_id;
- LLHTTPClient::post(
- url,
- data,
- new LLViewerChatterBoxInvitationAcceptResponder(
- session_id,
- inv_type));
+ LLCoros::instance().launch("chatterBoxInvitationCoro",
+ boost::bind(&chatterBoxInvitationCoro, url,
+ session_id, inv_type));
}
}
break;
@@ -2627,10 +2592,9 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)
LLSD data;
data["method"] = "decline invitation";
data["session-id"] = session_id;
- LLHTTPClient::post(
- url,
- data,
- NULL);
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data,
+ "Invitation declined.",
+ "Invitation decline failed.");
}
}
@@ -3687,15 +3651,9 @@ public:
if ( url != "" )
{
- LLSD data;
- data["method"] = "accept invitation";
- data["session-id"] = session_id;
- LLHTTPClient::post(
- url,
- data,
- new LLViewerChatterBoxInvitationAcceptResponder(
- session_id,
- LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE));
+ LLCoros::instance().launch("chatterBoxInvitationCoro",
+ boost::bind(&chatterBoxInvitationCoro, url,
+ session_id, LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE));
}
} //end if invitation has instant message
else if ( input["body"].has("voice") )
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index f92eff4845..41a8813acb 100755
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -34,6 +34,9 @@
#include "lllogchat.h"
#include "llvoicechannel.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+
class LLAvatarName;
class LLFriendObserver;
class LLCallDialogManager;
@@ -292,6 +295,7 @@ private:
* Add message to a list of message associated with session specified by session_id
*/
bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
+
};
class LLIMSessionObserver
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 605f71f412..0c70b074bf 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -124,11 +124,6 @@ bool isRemoveAction(const std::string& action)
return ("take_off" == action || "detach" == action || "deactivate" == action);
}
-bool isMarketplaceCopyAction(const std::string& action)
-{
- return (("copy_to_outbox" == action) || ("move_to_outbox" == action));
-}
-
bool isMarketplaceSendAction(const std::string& action)
{
return ("send_to_marketplace" == action);
@@ -777,14 +772,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
{
items.push_back(std::string("Marketplace Separator"));
- if (gMenuHolder->getChild<LLView>("MerchantOutbox")->getVisible())
- {
- items.push_back(std::string("Merchant Copy"));
- if (!canListOnOutboxNow())
- {
- disabled_items.push_back(std::string("Merchant Copy"));
- }
- }
if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible())
{
items.push_back(std::string("Marketplace Copy"));
@@ -799,8 +786,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
}
- // Don't allow items to be pasted directly into the COF or the inbox/outbox
- if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder())
+ // Don't allow items to be pasted directly into the COF or the inbox
+ if (!isCOFFolder() && !isInboxFolder())
{
items.push_back(std::string("Paste"));
}
@@ -838,10 +825,6 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else
{
items.push_back(std::string("Share"));
@@ -942,19 +925,6 @@ void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items)
items.push_back(std::string("Open"));
}
-void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags,
- menuentry_vec_t &items,
- menuentry_vec_t &disabled_items)
-{
- items.push_back(std::string("Rename"));
- items.push_back(std::string("Delete"));
-
- if ((flags & FIRST_SELECTED_ITEM) == 0)
- {
- disabled_items.push_back(std::string("Rename"));
- }
-}
-
void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags,
menuentry_vec_t &items,
menuentry_vec_t &disabled_items)
@@ -1204,41 +1174,6 @@ BOOL LLInvFVBridge::isMarketplaceListingsFolder() const
return gInventory.isObjectDescendentOf(mUUID, folder_id);
}
-BOOL LLInvFVBridge::isOutboxFolder() const
-{
- const LLUUID outbox_id = getOutboxFolder();
-
- if (outbox_id.isNull())
- {
- return FALSE;
- }
-
- return gInventory.isObjectDescendentOf(mUUID, outbox_id);
-}
-
-BOOL LLInvFVBridge::isOutboxFolderDirectParent() const
-{
- BOOL outbox_is_parent = FALSE;
-
- const LLInventoryCategory *cat = gInventory.getCategory(mUUID);
-
- if (cat)
- {
- const LLUUID outbox_id = getOutboxFolder();
-
- outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID()));
- }
-
- return outbox_is_parent;
-}
-
-const LLUUID LLInvFVBridge::getOutboxFolder() const
-{
- const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
-
- return outbox_id;
-}
-
BOOL LLInvFVBridge::isItemPermissive() const
{
return FALSE;
@@ -1495,56 +1430,6 @@ bool LLInvFVBridge::canListOnMarketplace() const
return true;
}
-// *TODO : Suppress canListOnOutboxNow() once we deprecate Merchant Outbox completely
-bool LLInvFVBridge::canListOnOutboxNow() const
-{
- bool can_list = true;
-
- // Do not allow listing while import is in progress
- if (LLMarketplaceInventoryImporter::instanceExists())
- {
- can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress();
- }
-
- const LLInventoryObject* obj = getInventoryObject();
- can_list &= (obj != NULL);
-
- if (can_list)
- {
- const LLUUID& object_id = obj->getLinkedUUID();
- can_list = object_id.notNull();
-
- if (can_list)
- {
- LLFolderViewFolder * object_folderp = mInventoryPanel.get() ? mInventoryPanel.get()->getFolderByID(object_id) : NULL;
- if (object_folderp)
- {
- can_list = !static_cast<LLFolderBridge*>(object_folderp->getViewModelItem())->isLoading();
- }
- }
-
- if (can_list)
- {
- // Get outbox id
- const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- LLFolderViewItem * outbox_itemp = mInventoryPanel.get() ? mInventoryPanel.get()->getItemByID(outbox_id) : NULL;
-
- if (outbox_itemp)
- {
- MASK mask = 0x0;
- BOOL drop = FALSE;
- EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType());
- void * cargo_data = (void *) obj;
- std::string tooltip_msg;
-
- can_list = outbox_itemp->getViewModelItem()->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg);
- }
- }
- }
-
- return can_list;
-}
-
bool LLInvFVBridge::canListOnMarketplaceNow() const
{
bool can_list = true;
@@ -1714,16 +1599,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
folder_view_itemp->getViewModelItem()->pasteLinkFromClipboard();
return;
}
- else if (isMarketplaceCopyAction(action))
- {
- LL_INFOS() << "Copy item to marketplace action!" << LL_ENDL;
-
- LLInventoryItem* itemp = model->getItem(mUUID);
- if (!itemp) return;
-
- const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId());
- }
else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
{
LLInventoryItem* itemp = model->getItem(mUUID);
@@ -2455,13 +2330,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
const LLUUID &cat_id = inv_cat->getUUID();
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID from_folder_uuid = inv_cat->getParentUUID();
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
- const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id);
@@ -2602,9 +2474,9 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
- if (is_movable && (move_is_into_outbox || move_is_into_marketplacelistings))
+ if (is_movable && move_is_into_marketplacelistings)
{
- const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID));
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
LLViewerInventoryCategory * dest_folder = getCategory();
S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount());
is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size);
@@ -2713,10 +2585,6 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL append = true;
LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append);
}
- else if (move_is_into_outbox && !move_is_from_outbox)
- {
- copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId());
- }
else if (move_is_into_marketplacelistings)
{
move_folder_to_marketplacelistings(inv_cat, mUUID);
@@ -2767,7 +2635,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
else if (LLToolDragAndDrop::SOURCE_WORLD == source)
{
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -2779,7 +2647,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
else if (LLToolDragAndDrop::SOURCE_LIBRARY == source)
{
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -3296,16 +3164,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
removeSystemFolder();
}
#endif
- else if (isMarketplaceCopyAction(action))
- {
- LL_INFOS() << "Copy folder to marketplace action!" << LL_ENDL;
-
- LLInventoryCategory * cat = gInventory.getCategory(mUUID);
- if (!cat) return;
-
- const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId());
- }
else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action))
{
LLInventoryCategory * cat = gInventory.getCategory(mUUID);
@@ -3546,7 +3404,6 @@ void LLFolderBridge::perform_pasteFromClipboard()
if (model && isClipboardPasteable())
{
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
@@ -3554,7 +3411,6 @@ void LLFolderBridge::perform_pasteFromClipboard()
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
const BOOL move_is_into_favorites = (mUUID == favorites_id);
@@ -3562,10 +3418,10 @@ void LLFolderBridge::perform_pasteFromClipboard()
LLClipboard::instance().pasteFromClipboard(objects);
LLViewerInventoryCategory * dest_folder = getCategory();
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
std::string error_msg;
- const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID));
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
int index = 0;
for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
{
@@ -3744,17 +3600,15 @@ void LLFolderBridge::pasteLinkFromClipboard()
if(model)
{
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
// Notify user of failure somehow -- play error sound? modal dialog?
return;
@@ -3875,10 +3729,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.clear(); // clear any items that used to exist
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else if(isAgentInventory()) // do not allow creating in library
{
LLViewerInventoryCategory *cat = getCategory();
@@ -3886,7 +3736,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
// Not sure what the right thing is to do here.
if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT))
{
- if (!isInboxFolder() && !isOutboxFolder()) // don't allow creation in inbox or outbox
+ if (!isInboxFolder()) // don't allow creation in inbox
{
// Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.
if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))
@@ -3948,7 +3798,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
disabled_items.push_back(std::string("Delete System Folder"));
}
- if (!isOutboxFolder() && !isMarketplaceListingsFolder())
+ if (!isMarketplaceListingsFolder())
{
items.push_back(std::string("Share"));
if (!canShare())
@@ -3994,7 +3844,6 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
if (trash_id == mUUID) return;
if (isItemInTrash()) return;
if (!isAgentInventory()) return;
- if (isOutboxFolder()) return;
if (!isItemRemovable())
{
@@ -4588,7 +4437,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false);
const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false);
- const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false);
const LLUUID from_folder_uuid = inv_item->getParentUUID();
@@ -4598,8 +4446,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id);
const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id);
- const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id);
- const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_item->getUUID(), outbox_id);
const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id);
const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id);
@@ -4675,9 +4521,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = can_move_to_landmarks(inv_item);
}
- else if (user_confirm && (move_is_into_outbox || move_is_into_marketplacelistings))
+ else if (user_confirm && move_is_into_marketplacelistings)
{
- const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID));
+ const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID);
LLViewerInventoryCategory * dest_folder = getCategory();
accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex());
}
@@ -4762,19 +4608,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
dropToOutfit(inv_item, move_is_into_current_outfit);
}
- // MERCHANT OUTBOX folder
- // Move the item
- else if (move_is_into_outbox)
- {
- if (move_is_from_outbox)
- {
- move_item_within_outbox(inv_item, mUUID, LLToolDragAndDrop::getOperationId());
- }
- else
- {
- copy_item_to_outbox(inv_item, mUUID, LLUUID::null, LLToolDragAndDrop::getOperationId());
- }
- }
// MARKETPLACE LISTINGS folder
// Move the item
else if (move_is_into_marketplacelistings)
@@ -4861,7 +4694,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = FALSE;
}
- else if (move_is_into_outbox || move_is_into_marketplacelistings)
+ else if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -4899,7 +4732,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
}
else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
{
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -4933,7 +4766,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
{
accept = TRUE;
- if (move_is_into_outbox || move_is_into_marketplacelistings)
+ if (move_is_into_marketplacelistings)
{
tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory");
accept = FALSE;
@@ -5102,10 +4935,6 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -5175,11 +5004,7 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t items;
menuentry_vec_t disabled_items;
- if (isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
- else if (isMarketplaceListingsFolder())
+ if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
items.push_back(std::string("Properties"));
@@ -5256,11 +5081,7 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t disabled_items;
LL_DEBUGS() << "LLLandmarkBridge::buildContextMenu()" << LL_ENDL;
- if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
- else if (isMarketplaceListingsFolder())
+ if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
items.push_back(std::string("Properties"));
@@ -5554,10 +5375,6 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -5846,10 +5663,6 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -5906,11 +5719,7 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t disabled_items;
LL_DEBUGS() << "LLAnimationBridge::buildContextMenu()" << LL_ENDL;
- if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
- else if (isMarketplaceListingsFolder())
+ if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
items.push_back(std::string("Properties"));
@@ -6171,10 +5980,6 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -6399,10 +6204,6 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
{
addTrashContextMenuOptions(items, disabled_items);
}
- else if(isOutboxFolder())
- {
- items.push_back(std::string("Delete"));
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
@@ -6705,10 +6506,6 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
items.push_back(std::string("Restore Item"));
}
- else if(isOutboxFolder())
- {
- addOutboxContextMenuOptions(flags, items, disabled_items);
- }
else if (isMarketplaceListingsFolder())
{
addMarketplaceContextMenuOptions(flags, items, disabled_items);
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 7e7cf9c7dd..30419ae930 100755
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -77,7 +77,6 @@ public:
bool canShare() const;
bool canListOnMarketplace() const;
- bool canListOnOutboxNow() const;
bool canListOnMarketplaceNow() const;
//--------------------------------------------------------------------
@@ -145,9 +144,6 @@ protected:
virtual void addDeleteContextMenuOptions(menuentry_vec_t &items,
menuentry_vec_t &disabled_items);
virtual void addOpenRightClickMenuOption(menuentry_vec_t &items);
- virtual void addOutboxContextMenuOptions(U32 flags,
- menuentry_vec_t &items,
- menuentry_vec_t &disabled_items);
virtual void addMarketplaceContextMenuOptions(U32 flags,
menuentry_vec_t &items,
menuentry_vec_t &disabled_items);
@@ -164,9 +160,7 @@ protected:
BOOL isCOFFolder() const; // true if COF or descendant of
BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox
- BOOL isOutboxFolderDirectParent() const;
BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder
- const LLUUID getOutboxFolder() const;
virtual BOOL isItemPermissive() const;
static void changeItemParent(LLInventoryModel* model,
@@ -182,10 +176,6 @@ protected:
BOOL callback_cutToClipboard(const LLSD& notification, const LLSD& response);
BOOL perform_cutToClipboard();
-public:
- BOOL isOutboxFolder() const; // true if COF or descendant of marketplace outbox
-
-protected:
LLHandle<LLInventoryPanel> mInventoryPanel;
LLFolderView* mRoot;
const LLUUID mUUID; // item id
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 990343c205..973bf59125 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -782,11 +782,6 @@ void reset_inventory_filter()
}
}
-void open_outbox()
-{
- LLFloaterReg::showInstance("outbox");
-}
-
void open_marketplace_listings()
{
LLFloaterReg::showInstance("marketplace_listings");
@@ -808,157 +803,6 @@ LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId)
return created_folder_id;
}
-void move_to_outbox_cb_action(const LLSD& payload)
-{
- LLViewerInventoryItem * viitem = gInventory.getItem(payload["item_id"].asUUID());
- LLUUID dest_folder_id = payload["dest_folder_id"].asUUID();
-
- if (viitem)
- {
- // when moving item directly into outbox create folder with that name
- if (dest_folder_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
- {
- dest_folder_id = create_folder_for_item(viitem, dest_folder_id);
- }
-
- LLUUID parent = viitem->getParentUUID();
-
- gInventory.changeItemParent(
- viitem,
- dest_folder_id,
- false);
-
- LLUUID top_level_folder = payload["top_level_folder"].asUUID();
-
- if (top_level_folder != LLUUID::null)
- {
- LLViewerInventoryCategory* category;
-
- while (parent.notNull())
- {
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(parent,cat_array,item_array);
-
- LLUUID next_parent;
-
- category = gInventory.getCategory(parent);
-
- if (!category) break;
-
- next_parent = category->getParentUUID();
-
- if (cat_array->empty() && item_array->empty())
- {
- gInventory.removeCategory(parent);
- }
-
- if (parent == top_level_folder)
- {
- break;
- }
-
- parent = next_parent;
- }
- }
-
- open_outbox();
- }
-}
-
-void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id)
-{
- // Collapse links directly to items/folders
- LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
- LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory();
- if (linked_category != NULL)
- {
- copy_folder_to_outbox(linked_category, dest_folder, top_level_folder, operation_id);
- }
- else
- {
- LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem();
- if (linked_item != NULL)
- {
- inv_item = (LLInventoryItem *) linked_item;
- }
-
- // Check for copy permissions
- if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()))
- {
- // when moving item directly into outbox create folder with that name
- if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
- {
- dest_folder = create_folder_for_item(inv_item, dest_folder);
- }
-
- copy_inventory_item(gAgent.getID(),
- inv_item->getPermissions().getOwner(),
- inv_item->getUUID(),
- dest_folder,
- inv_item->getName(),
- LLPointer<LLInventoryCallback>(NULL));
-
- open_outbox();
- }
- else
- {
- LLSD payload;
- payload["item_id"] = inv_item->getUUID();
- payload["dest_folder_id"] = dest_folder;
- payload["top_level_folder"] = top_level_folder;
- payload["operation_id"] = operation_id;
-
- LLMarketplaceInventoryNotifications::addNoCopyNotification(payload, move_to_outbox_cb_action);
- }
- }
-}
-
-void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id)
-{
- // when moving item directly into outbox create folder with that name
- if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false))
- {
- dest_folder = create_folder_for_item(inv_item, dest_folder);
- }
-
- LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item;
-
- gInventory.changeItemParent(
- viewer_inv_item,
- dest_folder,
- false);
-}
-
-void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id)
-{
- LLUUID new_folder_id = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_cat->getName());
- gInventory.notifyObservers();
-
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(inv_cat->getUUID(),cat_array,item_array);
-
- // copy the vector because otherwise the iterator won't be happy if we delete from it
- LLInventoryModel::item_array_t item_array_copy = *item_array;
-
- for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++)
- {
- LLInventoryItem* item = *iter;
- copy_item_to_outbox(item, new_folder_id, top_level_folder, operation_id);
- }
-
- LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
-
- for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
- {
- LLViewerInventoryCategory* category = *iter;
- copy_folder_to_outbox(category, new_folder_id, top_level_folder, operation_id);
- }
-
- open_outbox();
-}
-
///----------------------------------------------------------------------------
// Marketplace functions
//
@@ -975,7 +819,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid)
{
return -1;
}
- // If not a descendent of the marketplace listings root, then the nesting depth is -1 by definition
+ // If not a descendant of the marketplace listings root, then the nesting depth is -1 by definition
if (!gInventory.isObjectDescendentOf(cur_uuid, marketplace_listings_uuid))
{
return -1;
@@ -1605,7 +1449,7 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa
void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level)
{
- llinfos << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << llendl;
+ LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL;
}
// Make all relevant business logic checks on the marketplace listings starting with the folder as argument.
diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h
index 6ae8fd0f13..8aa8370f91 100755
--- a/indra/newview/llinventoryfunctions.h
+++ b/indra/newview/llinventoryfunctions.h
@@ -75,10 +75,6 @@ void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory*
// Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path);
-void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id);
-void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id);
-void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id);
-
typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 0bad4702e0..53a58aff4c 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -149,8 +149,8 @@ LLInventoryModel::LLInventoryModel()
mObservers(),
mHttpRequestFG(NULL),
mHttpRequestBG(NULL),
- mHttpOptions(NULL),
- mHttpHeaders(NULL),
+ mHttpOptions(),
+ mHttpHeaders(),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpPriorityFG(0),
mHttpPriorityBG(0),
@@ -179,16 +179,9 @@ void LLInventoryModel::cleanupInventory()
mObservers.clear();
// Run down HTTP transport
- if (mHttpHeaders)
- {
- mHttpHeaders->release();
- mHttpHeaders = NULL;
- }
- if (mHttpOptions)
- {
- mHttpOptions->release();
- mHttpOptions = NULL;
- }
+ mHttpHeaders.reset();
+ mHttpOptions.reset();
+
delete mHttpRequestFG;
mHttpRequestFG = NULL;
delete mHttpRequestBG;
@@ -525,59 +518,6 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp
return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());
}
-class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLCreateInventoryCategoryResponder);
-public:
- LLCreateInventoryCategoryResponder(LLInventoryModel* model,
- boost::optional<inventory_func_type> callback):
- mModel(model),
- mCallback(callback)
- {
- }
-
-protected:
- virtual void httpFailure()
- {
- LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL;
- }
-
- 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(LOG_INV) << ll_pretty_print_sd(content) << LL_ENDL;
- // Add the category to the internal representation
- LLPointer<LLViewerInventoryCategory> cat =
- new LLViewerInventoryCategory( category_id,
- content["parent_id"].asUUID(),
- (LLFolderType::EType)content["type"].asInteger(),
- content["name"].asString(),
- gAgent.getID() );
- cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL);
- cat->setDescendentCount(0);
- LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
- mModel->accountForUpdate(update);
- mModel->updateCategory(cat);
-
- if (mCallback)
- {
- mCallback.get()(category_id);
- }
- }
-
-private:
- boost::optional<inventory_func_type> mCallback;
- LLInventoryModel* mModel;
-};
-
// Convenience function to create a new category. You could call
// updateCategory() with a newly generated UUID category, but this
// version will take care of details like what the name should be
@@ -585,7 +525,7 @@ private:
LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& pname,
- boost::optional<inventory_func_type> callback)
+ inventory_func_type callback)
{
LLUUID id;
@@ -617,7 +557,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
if ( viewer_region )
url = viewer_region->getCapability("CreateInventoryCategory");
- if (!url.empty() && callback.get_ptr())
+ if (!url.empty() && callback)
{
//Let's use the new capability.
@@ -631,11 +571,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
request["payload"] = body;
LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL;
- // viewer_region->getCapAPI().post(request);
- LLHTTPClient::post(
- url,
- body,
- new LLCreateInventoryCategoryResponder(this, callback) );
+ LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro",
+ boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback));
return LLUUID::null;
}
@@ -664,6 +601,57 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
return id;
}
+void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("createNewCategoryCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+
+ httpOpts->setWantHeaders(true);
+
+ LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL;
+ return;
+ }
+
+ if (!result.has("folder_id"))
+ {
+ LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL;
+ return;
+ }
+
+ LLUUID categoryId = result["folder_id"].asUUID();
+
+ // Add the category to the internal representation
+ LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(categoryId,
+ result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(),
+ result["name"].asString(), gAgent.getID());
+
+ cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL);
+ cat->setDescendentCount(0);
+ LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
+
+ accountForUpdate(update);
+ updateCategory(cat);
+
+ if (callback)
+ {
+ callback(categoryId);
+ }
+
+}
+
// 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.
@@ -2442,11 +2430,11 @@ void LLInventoryModel::initHttpRequest()
mHttpRequestFG = new LLCore::HttpRequest;
mHttpRequestBG = new LLCore::HttpRequest;
- mHttpOptions = new LLCore::HttpOptions;
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
mHttpOptions->setTransferTimeout(300);
mHttpOptions->setUseRetryAfter(true);
// mHttpOptions->setTrace(2); // Do tracing of requests
- mHttpHeaders = new LLCore::HttpHeaders;
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);
mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY);
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index ac336e347c..a74e3b69f4 100755
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -35,7 +35,6 @@
#include "llassettype.h"
#include "llfoldertype.h"
#include "llframetimer.h"
-#include "llcurl.h"
#include "lluuid.h"
#include "llpermissionsflags.h"
#include "llviewerinventory.h"
@@ -46,6 +45,8 @@
#include "httpoptions.h"
#include "httpheaders.h"
#include "httphandler.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLInventoryObserver;
class LLInventoryObject;
@@ -207,14 +208,14 @@ private:
**/
//--------------------------------------------------------------------
- // Descendents
+ // Descendants
//--------------------------------------------------------------------
public:
- // Make sure we have the descendents in the structure. Returns true
+ // Make sure we have the descendants in the structure. Returns true
// if a fetch was performed.
bool fetchDescendentsOf(const LLUUID& folder_id) const;
- // Return the direct descendents of the id provided.Set passed
+ // Return the direct descendants of the id provided.Set passed
// in values to NULL if the call fails.
// NOTE: The array provided points straight into the guts of
// this object, and should only be used for read operations, since
@@ -223,10 +224,10 @@ public:
cat_array_t*& categories,
item_array_t*& items) const;
- // Compute a hash of direct descendent names (for detecting child name changes)
+ // Compute a hash of direct descendant names (for detecting child name changes)
LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const;
- // Starting with the object specified, add its descendents to the
+ // Starting with the object specified, add its descendants to the
// array provided, but do not add the inventory object specified
// by id. There is no guaranteed order.
// NOTE: Neither array will be erased before adding objects to it.
@@ -340,7 +341,7 @@ public:
U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0);
// Change an existing item with the matching id or add
- // the category. No notifcation will be sent to observers. This
+ // the category. No notification will be sent to observers. This
// method will only generate network traffic if the item had to be
// reparented.
// NOTE: In usage, you will want to perform cache accounting
@@ -378,7 +379,7 @@ public:
bool update_parent_version = true,
bool do_notify_observers = true);
- // Update model after all descendents removed from server.
+ // Update model after all descendants removed from server.
void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);
// Update model after an existing item gets updated on server.
@@ -409,7 +410,7 @@ public:
// Changes items order by insertion of the item identified by src_item_id
// before (or after) the item identified by dest_item_id. Both items must exist in items array.
// Sorting is stored after method is finished. Only src_item_id is moved before (or after) dest_item_id.
- // The parameter "insert_before" controls on which side of dest_item_id src_item_id gets rensinserted.
+ // The parameter "insert_before" controls on which side of dest_item_id src_item_id gets reinserted.
static void updateItemsOrder(LLInventoryModel::item_array_t& items,
const LLUUID& src_item_id,
const LLUUID& dest_item_id,
@@ -433,7 +434,7 @@ public:
LLUUID createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& name,
- boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>());
+ inventory_func_type callback = NULL);
protected:
// Internal methods that add inventory and make sure that all of
// the internal data structures are consistent. These methods
@@ -441,6 +442,8 @@ protected:
// instance will take over the memory management from there.
void addCategory(LLViewerInventoryCategory* category);
void addItem(LLViewerInventoryItem* item);
+
+ void createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback);
/** Mutators
** **
@@ -567,8 +570,8 @@ private:
// Usual plumbing for LLCore:: HTTP operations.
LLCore::HttpRequest * mHttpRequestFG;
LLCore::HttpRequest * mHttpRequestBG;
- LLCore::HttpOptions * mHttpOptions;
- LLCore::HttpHeaders * mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
LLCore::HttpRequest::policy_t mHttpPolicyClass;
LLCore::HttpRequest::priority_t mHttpPriorityFG;
LLCore::HttpRequest::priority_t mHttpPriorityBG;
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 5194cba891..02d378bc51 100755
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1437,16 +1437,20 @@ BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask )
// Open selected items if enter key hit on the inventory panel
if (mask == MASK_NONE)
{
- //Don't allow attaching or opening items from Merchant Outbox
- LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
- if(folder_item)
- {
- LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
- if(bridge && bridge->isOutboxFolder() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
- {
- return handled;
- }
- }
+
+// @TODO$: Rider: This code is dead with Outbox, however should something similar be
+// done for VMM?
+//
+// //Don't allow attaching or opening items from Merchant Outbox
+// LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
+// if(folder_item)
+// {
+// LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+// if(bridge && bridge->is() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
+// {
+// return handled;
+// }
+// }
LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "open");
handled = TRUE;
diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp
index d5bfe1df4a..e8e56ef0cd 100755
--- a/indra/newview/llmarketplacefunctions.cpp
+++ b/indra/newview/llmarketplacefunctions.cpp
@@ -30,7 +30,6 @@
#include "llagent.h"
#include "llbufferstream.h"
-#include "llhttpclient.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "llnotificationsutil.h"
@@ -42,609 +41,112 @@
#include "llviewermedia.h"
#include "llviewernetwork.h"
#include "llviewerregion.h"
-
#include "reader.h" // JSON
#include "writer.h" // JSON
+#include "lleventcoro.h"
+#include "llcoros.h"
+#include "llcorehttputil.h"
+#include "llsdutil.h"
//
// Helpers
//
-static std::string getMarketplaceDomain()
-{
- std::string domain = "secondlife.com";
-
- if (!LLGridManager::getInstance()->isInProductionGrid())
- {
- const std::string& grid_id = LLGridManager::getInstance()->getGridId();
- const std::string& grid_id_lower = utf8str_tolower(grid_id);
-
- if (grid_id_lower == "damballah")
- {
- domain = "secondlife-staging.com";
- }
- else
- {
- domain = llformat("%s.lindenlab.com", grid_id_lower.c_str());
- }
- }
-
- return domain;
-}
-
-static std::string getMarketplaceURL(const std::string& urlStringName)
-{
- LLStringUtil::format_map_t domain_arg;
- domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain();
-
- std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg);
-
- return marketplace_url;
-}
-
-LLSD getMarketplaceStringSubstitutions()
-{
- std::string marketplace_url = getMarketplaceURL("MarketplaceURL");
- std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore");
- std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard");
- std::string marketplace_url_imports = getMarketplaceURL("MarketplaceURL_Imports");
- std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore");
-
- LLSD marketplace_sub_map;
-
- marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url;
- marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create;
- marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info;
- marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard;
- marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports;
-
- return marketplace_sub_map;
-}
-
-// Get the version folder: if there is only one subfolder, we will use it as a version folder
-LLUUID getVersionFolderIfUnique(const LLUUID& folder_id)
-{
- LLUUID version_id = LLUUID::null;
- LLInventoryModel::cat_array_t* categories;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(folder_id, categories, items);
- if (categories->size() == 1)
- {
- version_id = categories->begin()->get()->getUUID();
- }
- else
- {
- LLNotificationsUtil::add("AlertMerchantListingActivateRequired");
- }
- return version_id;
-}
+namespace {
-///////////////////////////////////////////////////////////////////////////////
-// SLM Responders
-void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
-{
- LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL;
- if ((status == 422) && (description == "[\"You must have an English description to list the product\", \"You must choose a category for your product before it can be listed\", \"Listing could not change state.\", \"Price can't be blank\"]"))
- {
- // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing
- LLNotificationsUtil::add("MerchantUnprocessableEntity");
- }
- else
+ static std::string getMarketplaceDomain()
{
- // Prompt the user with the warning (so they know why things are failing)
- LLSD subs;
- subs["[ERROR_REASON]"] = reason;
- // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though.
- subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : "");
- LLNotificationsUtil::add("MerchantTransactionFailed", subs);
- }
-}
-void log_SLM_infos(const std::string& request, U32 status, const std::string& body)
-{
- if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
- {
- LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL;
- }
-}
-void log_SLM_infos(const std::string& request, const std::string& url, const std::string& body)
-{
- if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
- {
- LL_INFOS("SLM") << "SLM API : Sending " << request << ". url : " << url << ", body : " << body << LL_ENDL;
- }
-}
+ std::string domain = "secondlife.com";
-class LLSLMGetMerchantResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMGetMerchantResponder);
-public:
-
- LLSLMGetMerchantResponder() {}
-
-protected:
- virtual void httpFailure()
- {
- if (HTTP_NOT_FOUND == getStatus())
- {
- log_SLM_infos("Get /merchant", getStatus(), "User is not a merchant");
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
- }
- else if (HTTP_SERVICE_UNAVAILABLE == getStatus())
+ if (!LLGridManager::getInstance()->isInProductionGrid())
{
- log_SLM_infos("Get /merchant", getStatus(), "Merchant is not migrated");
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT);
- }
- else
- {
- log_SLM_warning("Get /merchant", getStatus(), getReason(), getContent().get("error_code"), getContent().get("error_description"));
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE);
- }
- }
-
- virtual void httpSuccess()
- {
- log_SLM_infos("Get /merchant", getStatus(), "User is a merchant");
- LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT);
- }
-
-};
+ const std::string& grid_id = LLGridManager::getInstance()->getGridId();
+ const std::string& grid_id_lower = utf8str_tolower(grid_id);
-class LLSLMGetListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMGetListingsResponder);
-public:
-
- LLSLMGetListingsResponder(const LLUUID& folder_id)
- {
- mExpectedFolderId = folder_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Get /listings", getStatus(), getReason(), "", body);
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Get /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- log_SLM_infos("Get /listings", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
- {
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
- if (folder_id.notNull())
+ if (grid_id_lower == "damballah")
{
- LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
+ domain = "secondlife-staging.com";
+ }
+ else
+ {
+ domain = llformat("%s.lindenlab.com", grid_id_lower.c_str());
}
- it++;
}
-
- // Update all folders under the root
- LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- }
-private:
- LLUUID mExpectedFolderId;
-};
-class LLSLMCreateListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMCreateListingsResponder);
-public:
-
- LLSLMCreateListingsResponder(const LLUUID& folder_id)
- {
- mExpectedFolderId = folder_id;
+ return domain;
}
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+
+ static std::string getMarketplaceURL(const std::string& urlStringName)
{
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Post /listings", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Post /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
+ LLStringUtil::format_map_t domain_arg;
+ domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain();
- log_SLM_infos("Post /listings", getStatus(), body);
+ std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg);
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
- {
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
- LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
- it++;
- }
+ return marketplace_url;
}
-private:
- LLUUID mExpectedFolderId;
-};
-class LLSLMGetListingResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMGetListingResponder);
-public:
-
- LLSLMGetListingResponder(const LLUUID& folder_id)
- {
- mExpectedFolderId = folder_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+ // Get the version folder: if there is only one subfolder, we will use it as a version folder
+ LLUUID getVersionFolderIfUnique(const LLUUID& folder_id)
{
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- if (getStatus() == 404)
- {
- // That listing does not exist -> delete its record from the local SLM data store
- LLMarketplaceData::instance().deleteListing(mExpectedFolderId, false);
- }
- else
- {
- log_SLM_warning("Get /listing", getStatus(), getReason(), "", body);
- }
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
+ LLUUID version_id = LLUUID::null;
+ LLInventoryModel::cat_array_t* categories;
+ LLInventoryModel::item_array_t* items;
+ gInventory.getDirectDescendentsOf(folder_id, categories, items);
+ if (categories->size() == 1)
{
- log_SLM_warning("Get /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
+ version_id = categories->begin()->get()->getUUID();
}
-
- log_SLM_infos("Get /listing", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
+ else
{
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
-
- // Update that listing
- LLMarketplaceData::instance().setListingID(folder_id, listing_id, false);
- LLMarketplaceData::instance().setVersionFolderID(folder_id, version_id, false);
- LLMarketplaceData::instance().setActivationState(folder_id, is_listed, false);
- LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
- LLMarketplaceData::instance().setCountOnHand(folder_id,count,false);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
-
- it++;
+ LLNotificationsUtil::add("AlertMerchantListingActivateRequired");
}
+ return version_id;
}
-private:
- LLUUID mExpectedFolderId;
-};
-class LLSLMUpdateListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMUpdateListingsResponder);
-public:
-
- LLSLMUpdateListingsResponder(const LLUUID& folder_id, bool expected_listed_state, const LLUUID& expected_version_id)
+ ///////////////////////////////////////////////////////////////////////////////
+ // SLM Reporters
+ void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description)
{
- mExpectedFolderId = folder_id;
- mExpectedListedState = expected_listed_state;
- mExpectedVersionUUID = expected_version_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Put /listing", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
+ LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL;
+ if ((status == 422) && (description == "[\"You must have an English description to list the product\", \"You must choose a category for your product before it can be listed\", \"Listing could not change state.\", \"Price can't be blank\"]"))
{
- log_SLM_warning("Put /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
+ // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing
+ LLNotificationsUtil::add("MerchantUnprocessableEntity");
}
-
- log_SLM_infos("Put /listing", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
+ else
{
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
-
- // Update that listing
- LLMarketplaceData::instance().setListingID(folder_id, listing_id, false);
- LLMarketplaceData::instance().setVersionFolderID(folder_id, version_id, false);
- LLMarketplaceData::instance().setActivationState(folder_id, is_listed, false);
- LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false);
- LLMarketplaceData::instance().setCountOnHand(folder_id,count,false);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
-
- // Show a notification alert if what we got is not what we expected
- // (this actually doesn't result in an error status from the SLM API protocol)
- if ((mExpectedListedState != is_listed) || (mExpectedVersionUUID != version_id))
- {
- LLSD subs;
- subs["[URL]"] = edit_url;
- LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs);
- }
-
- it++;
+ // Prompt the user with the warning (so they know why things are failing)
+ LLSD subs;
+ subs["[ERROR_REASON]"] = reason;
+ // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though.
+ subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : "");
+ LLNotificationsUtil::add("MerchantTransactionFailed", subs);
}
}
-private:
- LLUUID mExpectedFolderId;
- bool mExpectedListedState;
- LLUUID mExpectedVersionUUID;
-};
-class LLSLMAssociateListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMAssociateListingsResponder);
-public:
-
- LLSLMAssociateListingsResponder(const LLUUID& folder_id, const LLUUID& source_folder_id)
+ void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const LLSD& description)
{
- mExpectedFolderId = folder_id;
- mSourceFolderId = source_folder_id;
+ log_SLM_warning(request, status, reason, code, std::string(ll_pretty_print_sd(description)));
}
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+
+ void log_SLM_infos(const std::string& request, U32 status, const std::string& body)
{
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
- LLMarketplaceData::instance().setUpdating(mSourceFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- update_marketplace_category(mSourceFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Put /associate_inventory", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- update_marketplace_category(mSourceFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- log_SLM_infos("Put /associate_inventory", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
+ if (gSavedSettings.getBOOL("MarketplaceListingsLogging"))
{
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- bool is_listed = listing["is_listed"].asBool();
- std::string edit_url = listing["edit_url"].asString();
- std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString();
- std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString();
- int count = listing["inventory_info"]["count_on_hand"].asInt();
-
- LLUUID folder_id(folder_uuid_string);
- LLUUID version_id(version_uuid_string);
-
- // Check that the listing ID is not already associated to some other record
- LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id);
- if (old_listing.notNull())
- {
- // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID)
- LLMarketplaceData::instance().deleteListing(old_listing);
- }
-
- // Add the new association
- LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count);
- update_marketplace_category(folder_id, false);
- gInventory.notifyObservers();
-
- // The stock count needs to be updated with the new local count now
- LLMarketplaceData::instance().updateCountOnHand(folder_id,1);
-
- it++;
+ LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL;
}
-
- // Always update the source folder so its widget updates
- update_marketplace_category(mSourceFolderId, false);
}
-private:
- LLUUID mExpectedFolderId; // This is the folder now associated with the id.
- LLUUID mSourceFolderId; // This is the folder initially associated with the id. Can be LLUUI::null
-};
-class LLSLMDeleteListingsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSLMDeleteListingsResponder);
-public:
-
- LLSLMDeleteListingsResponder(const LLUUID& folder_id)
+ void log_SLM_infos(const std::string& request, U32 status, const LLSD& body)
{
- mExpectedFolderId = folder_id;
- }
-
- virtual void completedRaw(const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false);
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (!isGoodStatus())
- {
- log_SLM_warning("Delete /listing", getStatus(), getReason(), "", body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body,root))
- {
- log_SLM_warning("Delete /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body);
- update_marketplace_category(mExpectedFolderId, false);
- gInventory.notifyObservers();
- return;
- }
-
- log_SLM_infos("Delete /listing", getStatus(), body);
-
- // Extract the info from the Json string
- Json::ValueIterator it = root["listings"].begin();
-
- while (it != root["listings"].end())
- {
- Json::Value listing = *it;
-
- int listing_id = listing["id"].asInt();
- LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
- LLMarketplaceData::instance().deleteListing(folder_id);
-
- it++;
- }
+ log_SLM_infos(request, status, std::string(ll_pretty_print_sd(body)));
}
-private:
- LLUUID mExpectedFolderId;
-};
-// SLM Responders End
-///////////////////////////////////////////////////////////////////////////////
+}
+
+#if 1
namespace LLMarketplaceImport
{
// Basic interface for this namespace
@@ -669,105 +171,133 @@ namespace LLMarketplaceImport
static S32 sImportResultStatus = 0;
static LLSD sImportResults = LLSD::emptyMap();
- static LLTimer slmGetTimer;
- static LLTimer slmPostTimer;
-
// Responders
-
- class LLImportPostResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLImportPostResponder);
- public:
- LLImportPostResponder() : LLCurl::Responder() {}
- protected:
- /* virtual */ void httpCompleted()
- {
- slmPostTimer.stop();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] "
- << dumpResponse() << LL_ENDL;
- }
-
- S32 status = getStatus();
- if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) ||
- (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||
- // MAINT-2301 : we determined we can safely ignore that error in that context
- (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))
- {
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL;
- }
- status = MarketplaceErrorCodes::IMPORT_DONE;
- }
-
- if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
- {
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM POST : Clearing marketplace cookie due to client or server error" << LL_ENDL;
- }
- sMarketplaceCookie.clear();
- }
-
- sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE);
- sImportPostPending = false;
- sImportResultStatus = status;
- sImportId = getContent();
- }
- };
-
- class LLImportGetResponder : public LLHTTPClient::Responder
- {
- LOG_CLASS(LLImportGetResponder);
- public:
- LLImportGetResponder() : LLCurl::Responder() {}
-
- protected:
- /* virtual */ void httpCompleted()
- {
- const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE);
-
- if (!set_cookie_string.empty())
- {
- sMarketplaceCookie = set_cookie_string;
- }
-
- slmGetTimer.stop();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] "
- << dumpResponse() << LL_ENDL;
- }
-
- // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions
- // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initally empty
- S32 status = getStatus();
- if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&
- (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) &&
- (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND))
- {
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL;
- }
- sMarketplaceCookie.clear();
- }
- else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST))
+ void marketplacePostCoro(std::string url)
+ {
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("marketplacePostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(true);
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
+ httpHeaders->append(HTTP_OUT_HEADER_CONNECTION, "Keep-Alive");
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie);
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent());
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ S32 httpCode = status.getType();
+ if ((httpCode == MarketplaceErrorCodes::IMPORT_REDIRECT) ||
+ (httpCode == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||
+ // MAINT-2301 : we determined we can safely ignore that error in that context
+ (httpCode == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))
+ {
+ if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
{
- LL_INFOS() << " SLM GET : Got error status = " << status << ", but marketplace cookie not cleared." << LL_ENDL;
+ LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL;
}
+ httpCode = MarketplaceErrorCodes::IMPORT_DONE;
+ }
- sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);
- sImportGetPending = false;
- sImportResultStatus = status;
- sImportResults = getContent();
- }
- };
+ if (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
+ {
+ if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
+ {
+ LL_INFOS() << " SLM POST clearing marketplace cookie due to client or server error" << LL_ENDL;
+ }
+ sMarketplaceCookie.clear();
+ }
+
+ sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_DONE);
+ sImportPostPending = false;
+ sImportResultStatus = httpCode;
+
+ {
+ std::stringstream str;
+ LLSDSerialize::toPrettyXML(result, str);
+
+ LL_INFOS() << "Full results:\n" << str.str() << "\n" << LL_ENDL;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ sImportId = result;
+
+ }
+
+ void marketplaceGetCoro(std::string url, bool buildHeaders)
+ {
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("marketplaceGetCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders;
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(!sMarketplaceCookie.empty());
+
+ if (buildHeaders)
+ {
+ httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie);
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent());
+ }
+ else
+ {
+ httpHeaders = LLViewerMedia::getHttpHeaders();
+ }
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+
+ if (sMarketplaceCookie.empty() && resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE))
+ {
+ sMarketplaceCookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asString();
+ }
+
+ // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions
+ // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty
+ S32 httpCode = status.getType();
+ if ((httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&
+ (httpCode != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) &&
+ (httpCode != MarketplaceErrorCodes::IMPORT_NOT_FOUND))
+ {
+ if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
+ {
+ LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL;
+ }
+ sMarketplaceCookie.clear();
+ }
+ else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST))
+ {
+ LL_INFOS() << " SLM GET : Got error status = " << httpCode << ", but marketplace cookie not cleared." << LL_ENDL;
+ }
+
+ sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_PROCESSING);
+ sImportGetPending = false;
+ sImportResultStatus = httpCode;
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ sImportResults = result;
+
+
+ }
// Basic API
@@ -818,20 +348,10 @@ namespace LLMarketplaceImport
sImportGetPending = true;
std::string url = getInventoryImportURL();
-
- if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
- {
- LL_INFOS() << " SLM GET: establishMarketplaceSessionCookie, LLHTTPClient::get, url = " << url << LL_ENDL;
- LLSD headers = LLViewerMedia::getHeaders();
- std::stringstream str;
- LLSDSerialize::toPrettyXML(headers, str);
- LL_INFOS() << " SLM GET: headers " << LL_ENDL;
- LL_INFOS() << str.str() << LL_ENDL;
- }
- slmGetTimer.start();
- LLHTTPClient::get(url, new LLImportGetResponder(), LLViewerMedia::getHeaders());
-
+ LLCoros::instance().launch("marketplaceGetCoro",
+ boost::bind(&marketplaceGetCoro, url, false));
+
return true;
}
@@ -848,26 +368,9 @@ namespace LLMarketplaceImport
url += sImportId.asString();
- // Make the headers for the post
- LLSD headers = LLSD::emptyMap();
- 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"))
- {
- LL_INFOS() << " SLM GET: pollStatus, LLHTTPClient::get, url = " << url << LL_ENDL;
- std::stringstream str;
- LLSDSerialize::toPrettyXML(headers, str);
- LL_INFOS() << " SLM GET: headers " << LL_ENDL;
- LL_INFOS() << str.str() << LL_ENDL;
- }
-
- slmGetTimer.start();
- LLHTTPClient::get(url, new LLImportGetResponder(), headers);
-
+ LLCoros::instance().launch("marketplaceGetCoro",
+ boost::bind(&marketplaceGetCoro, url, true));
+
return true;
}
@@ -886,35 +389,17 @@ namespace LLMarketplaceImport
std::string url = getInventoryImportURL();
- // Make the headers for the post
- LLSD headers = LLSD::emptyMap();
- 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"))
- {
- LL_INFOS() << " SLM POST: triggerImport, LLHTTPClient::post, url = " << url << LL_ENDL;
- std::stringstream str;
- LLSDSerialize::toPrettyXML(headers, str);
- LL_INFOS() << " SLM POST: headers " << LL_ENDL;
- LL_INFOS() << str.str() << LL_ENDL;
- }
+ LLCoros::instance().launch("marketplacePostCoro",
+ boost::bind(&marketplacePostCoro, url));
- slmPostTimer.start();
- LLHTTPClient::post(url, LLSD(), new LLImportPostResponder(), headers);
-
return true;
}
}
-
+#endif
//
// Interface class
//
-
static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 1.0f;
//static
@@ -1212,6 +697,26 @@ LLMarketplaceData::~LLMarketplaceData()
gInventory.removeObserver(mInventoryObserver);
}
+
+LLSD LLMarketplaceData::getMarketplaceStringSubstitutions()
+{
+ std::string marketplace_url = getMarketplaceURL("MarketplaceURL");
+ std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore");
+ std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard");
+ std::string marketplace_url_imports = getMarketplaceURL("MarketplaceURL_Imports");
+ std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore");
+
+ LLSD marketplace_sub_map;
+
+ marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url;
+ marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create;
+ marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info;
+ marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard;
+ marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports;
+
+ return marketplace_sub_map;
+}
+
void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type& cb)
{
if (mStatusUpdatedSignal == NULL)
@@ -1227,15 +732,60 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type&
}
else
{
- // Initiate SLM connection and set responder
- std::string url = getSLMConnectURL("/merchant");
- if (url != "")
+ mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING;
+
+ LLCoros::instance().launch("getMerchantStatus",
+ boost::bind(&LLMarketplaceData::getMerchantStatusCoro, this));
+ }
+}
+
+void LLMarketplaceData::getMerchantStatusCoro()
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setFollowRedirects(true);
+
+ std::string url = getSLMConnectURL("/merchant");
+ if (url.empty())
+ {
+ LL_INFOS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL;
+ }
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ S32 httpCode = status.getType();
+
+ if (httpCode == HTTP_NOT_FOUND)
+ {
+ log_SLM_infos("Get /merchant", httpCode, std::string("User is not a merchant"));
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT);
+ }
+ else if (httpCode == HTTP_SERVICE_UNAVAILABLE)
+ {
+ log_SLM_infos("Get /merchant", httpCode, std::string("Merchant is not migrated"));
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT);
+ }
+ else
{
- mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING;
- log_SLM_infos("LLHTTPClient::get", url, "");
- LLHTTPClient::get(url, new LLSLMGetMerchantResponder(), LLSD());
+ std::string err_code = result["error_code"].asString();
+ std::string err_description = result["error_description"].asString();
+ log_SLM_warning("Get /merchant", httpCode, status.toString(), err_code, err_description);
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE);
}
+ return;
}
+
+ log_SLM_infos("Get /merchant", status.getType(), std::string("User is a merchant"));
+ setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT);
}
void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb)
@@ -1250,151 +800,434 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot
// Get/Post/Put requests to the SLM Server using the SLM API
void LLMarketplaceData::getSLMListings()
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Send request
+ const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
+ setUpdating(marketplaceFolderId, true);
+
+ LLCoros::instance().launch("getSLMListings",
+ boost::bind(&LLMarketplaceData::getSLMListingsCoro, this, marketplaceFolderId));
+}
+
+void LLMarketplaceData::getSLMListingsCoro(LLUUID folderId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
std::string url = getSLMConnectURL("/listings");
- log_SLM_infos("LLHTTPClient::get", url, "");
- const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
- setUpdating(marketplacelistings_id,true);
- LLHTTPClient::get(url, new LLSLMGetListingsResponder(marketplacelistings_id), headers);
+
+ LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, url, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Get /listings", status.getType(), status.toString(), "", result);
+ setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Get /listings", static_cast<U32>(status.getType()), result);
+
+ // Extract the info from the results
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listingId = listing["id"].asInteger();
+ bool isListed = listing["is_listed"].asBoolean();
+ std::string editUrl = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ if (folderUuid.notNull())
+ {
+ addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count);
+ }
+ }
+
+ // Update all folders under the root
+ setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
}
-void LLMarketplaceData::getSLMListing(S32 listing_id)
+void LLMarketplaceData::getSLMListing(S32 listingId)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Send request
- std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::get", url, "");
- LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
- setUpdating(folder_id,true);
- LLHTTPClient::get(url, new LLSLMGetListingResponder(folder_id), headers);
+ LLUUID folderId = getListingFolder(listingId);
+ setUpdating(folderId, true);
+
+ LLCoros::instance().launch("getSingleListingCoro",
+ boost::bind(&LLMarketplaceData::getSingleListingCoro, this, listingId, folderId));
+}
+
+void LLMarketplaceData::getSingleListingCoro(S32 listingId, LLUUID folderId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
+ std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId);
+
+ LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, url, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (status.getType() == HTTP_NOT_FOUND)
+ {
+ // That listing does not exist -> delete its record from the local SLM data store
+ deleteListing(folderId, false);
+ }
+ else
+ {
+ log_SLM_warning("Get /listing", status.getType(), status.toString(), "", result);
+ }
+
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Get /listings", static_cast<U32>(status.getType()), result);
+
+
+ // Extract the info from the results
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int resListingId = listing["id"].asInteger();
+ bool isListed = listing["is_listed"].asBoolean();
+ std::string editUrl = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ // Update that listing
+ setListingID(folderUuid, resListingId, false);
+ setVersionFolderID(folderUuid, versionUuid, false);
+ setActivationState(folderUuid, isListed, false);
+ setListingURL(folderUuid, editUrl, false);
+ setCountOnHand(folderUuid, count, false);
+ update_marketplace_category(folderUuid, false);
+ gInventory.notifyObservers();
+ }
}
void LLMarketplaceData::createSLMListing(const LLUUID& folder_id, const LLUUID& version_id, S32 count)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Build the json message
- Json::Value root;
- Json::FastWriter writer;
-
- LLViewerInventoryCategory* category = gInventory.getCategory(folder_id);
- root["listing"]["name"] = category->getName();
- root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
- root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
- root["listing"]["inventory_info"]["count_on_hand"] = count;
-
- std::string json_str = writer.write(root);
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = json_str.size();
- U8 *data = new U8[size];
- memcpy(data, (U8*)(json_str.c_str()), size);
-
- // Send request
- std::string url = getSLMConnectURL("/listings");
- log_SLM_infos("LLHTTPClient::postRaw", url, json_str);
- setUpdating(folder_id,true);
- LLHTTPClient::postRaw(url, data, size, new LLSLMCreateListingsResponder(folder_id), headers);
+ setUpdating(folder_id, true);
+ LLCoros::instance().launch("createSLMListingCoro",
+ boost::bind(&LLMarketplaceData::createSLMListingCoro, this, folder_id, version_id, count));
}
-void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count)
+void LLMarketplaceData::createSLMListingCoro(LLUUID folderId, LLUUID versionId, S32 count)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
- Json::Value root;
- Json::FastWriter writer;
+ LLViewerInventoryCategory* category = gInventory.getCategory(folderId);
+ LLSD invInfo;
+ invInfo["listing_folder_id"] = folderId;
+ invInfo["version_folder_id"] = versionId;
+ invInfo["count_on_hand"] = count;
+ LLSD listing;
+ listing["name"] = category->getName();
+ listing["inventory_info"] = invInfo;
+ LLSD postData;
+ postData["listing"] = listing;
- // Note : auto unlist if the count is 0 (out of stock)
- if (is_listed && (count == 0))
+ std::string url = getSLMConnectURL("/listings");
+
+ LLSD result = httpAdapter->postJsonAndSuspend(httpRequest, url, postData, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
{
- is_listed = false;
- LLNotificationsUtil::add("AlertMerchantStockFolderEmpty");
+ log_SLM_warning("Post /listings", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
}
- // Note : we're assuming that sending unchanged info won't break anything server side...
- root["listing"]["id"] = listing_id;
- root["listing"]["is_listed"] = is_listed;
- root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
- root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
- root["listing"]["inventory_info"]["count_on_hand"] = count;
-
- std::string json_str = writer.write(root);
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = json_str.size();
- U8 *data = new U8[size];
- memcpy(data, (U8*)(json_str.c_str()), size);
+ log_SLM_infos("Post /listings", status.getType(), result);
+
+ // Extract the info from the results
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listingId = listing["id"].asInteger();
+ bool isListed = listing["is_listed"].asBoolean();
+ std::string editUrl = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count);
+ update_marketplace_category(folderUuid, false);
+ gInventory.notifyObservers();
+ }
+
+}
+
+void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count)
+{
+ setUpdating(folder_id, true);
+ LLCoros::instance().launch("updateSLMListingCoro",
+ boost::bind(&LLMarketplaceData::updateSLMListingCoro, this, folder_id, listing_id, version_id, is_listed, count));
+}
+
+void LLMarketplaceData::updateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, bool isListed, S32 count)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
- // Send request
- std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::putRaw", url, json_str);
- setUpdating(folder_id,true);
- LLHTTPClient::putRaw(url, data, size, new LLSLMUpdateListingsResponder(folder_id, is_listed, version_id), headers);
+ LLSD invInfo;
+ invInfo["listing_folder_id"] = folderId;
+ invInfo["version_folder_id"] = versionId;
+ invInfo["count_on_hand"] = count;
+ LLSD listing;
+ listing["inventory_info"] = invInfo;
+ listing["id"] = listingId;
+ listing["is_listed"] = isListed;
+ LLSD postData;
+ postData["listing"] = listing;
+
+ std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId);
+ LLSD result = httpAdapter->putJsonAndSuspend(httpRequest, url, postData, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Put /listing", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Put /listing", status.getType(), result);
+
+ // Extract the info from the Json string
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listing_id = listing["id"].asInteger();
+ bool is_listed = listing["is_listed"].asBoolean();
+ std::string edit_url = listing["edit_url"].asString();
+ LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int onHand = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ // Update that listing
+ setListingID(folderUuid, listing_id, false);
+ setVersionFolderID(folderUuid, versionUuid, false);
+ setActivationState(folderUuid, is_listed, false);
+ setListingURL(folderUuid, edit_url, false);
+ setCountOnHand(folderUuid, onHand, false);
+ update_marketplace_category(folderUuid, false);
+ gInventory.notifyObservers();
+
+ // Show a notification alert if what we got is not what we expected
+ // (this actually doesn't result in an error status from the SLM API protocol)
+ if ((isListed != is_listed) || (versionId != versionUuid))
+ {
+ LLSD subs;
+ subs["[URL]"] = edit_url;
+ LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs);
+ }
+ }
+
}
void LLMarketplaceData::associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, const LLUUID& source_folder_id)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- Json::Value root;
- Json::FastWriter writer;
-
- // Note : we're assuming that sending unchanged info won't break anything server side...
- root["listing"]["id"] = listing_id;
- root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString();
- root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString();
-
- std::string json_str = writer.write(root);
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = json_str.size();
- U8 *data = new U8[size];
- memcpy(data, (U8*)(json_str.c_str()), size);
-
- // Send request
- std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::putRaw", url, json_str);
- setUpdating(folder_id,true);
- setUpdating(source_folder_id,true);
- LLHTTPClient::putRaw(url, data, size, new LLSLMAssociateListingsResponder(folder_id,source_folder_id), headers);
+ setUpdating(folder_id, true);
+ setUpdating(source_folder_id, true);
+ LLCoros::instance().launch("associateSLMListingCoro",
+ boost::bind(&LLMarketplaceData::associateSLMListingCoro, this, folder_id, listing_id, version_id, source_folder_id));
}
-void LLMarketplaceData::deleteSLMListing(S32 listing_id)
+void LLMarketplaceData::associateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, LLUUID sourceFolderId)
{
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "application/json";
- headers["Content-Type"] = "application/json";
-
- // Send request
- std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id);
- log_SLM_infos("LLHTTPClient::del", url, "");
- LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
- setUpdating(folder_id,true);
- LLHTTPClient::del(url, new LLSLMDeleteListingsResponder(folder_id), headers);
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
+ LLSD invInfo;
+ invInfo["listing_folder_id"] = folderId;
+ invInfo["version_folder_id"] = versionId;
+ LLSD listing;
+ listing["id"] = listingId;
+ listing["inventory_info"] = invInfo;
+ LLSD postData;
+ postData["listing"] = listing;
+
+ // Send request
+ std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d", listingId);
+
+ LLSD result = httpAdapter->putJsonAndSuspend(httpRequest, url, postData, httpHeaders);
+
+ setUpdating(folderId, false);
+ setUpdating(sourceFolderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Put /associate_inventory", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ update_marketplace_category(sourceFolderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Put /associate_inventory", status.getType(), result);
+
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listing_id = listing["id"].asInteger();
+ bool is_listed = listing["is_listed"].asBoolean();
+ std::string edit_url = listing["edit_url"].asString();
+ LLUUID folder_uuid = listing["inventory_info"]["listing_folder_id"].asUUID();
+ LLUUID version_uuid = listing["inventory_info"]["version_folder_id"].asUUID();
+ int count = listing["inventory_info"]["count_on_hand"].asInteger();
+
+ // Check that the listing ID is not already associated to some other record
+ LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id);
+ if (old_listing.notNull())
+ {
+ // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID)
+ deleteListing(old_listing);
+ }
+
+ // Add the new association
+ addListing(folder_uuid, listing_id, version_uuid, is_listed, edit_url, count);
+ update_marketplace_category(folder_uuid, false);
+ gInventory.notifyObservers();
+
+ // The stock count needs to be updated with the new local count now
+ updateCountOnHand(folder_uuid, 1);
+ }
+
+ // Always update the source folder so its widget updates
+ update_marketplace_category(sourceFolderId, false);
+}
+
+void LLMarketplaceData::deleteSLMListing(S32 listingId)
+{
+ LLCoros::instance().launch("deleteSLMListingCoro",
+ boost::bind(&LLMarketplaceData::deleteSLMListingCoro, this, listingId));
+}
+
+void LLMarketplaceData::deleteSLMListingCoro(S32 listingId)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpHeaders->append("Accept", "application/json");
+ httpHeaders->append("Content-Type", "application/json");
+
+ std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId);
+ LLUUID folderId = getListingFolder(listingId);
+
+ setUpdating(folderId, true);
+
+ LLSD result = httpAdapter->deleteJsonAndSuspend(httpRequest, url, httpHeaders);
+
+ setUpdating(folderId, false);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ log_SLM_warning("Delete /listing", status.getType(), status.toString(), "", result);
+ update_marketplace_category(folderId, false);
+ gInventory.notifyObservers();
+ return;
+ }
+
+ log_SLM_infos("Delete /listing", status.getType(), result);
+
+ for (LLSD::array_iterator it = result["listings"].beginArray();
+ it != result["listings"].endArray(); ++it)
+ {
+ LLSD listing = *it;
+
+ int listing_id = listing["id"].asInteger();
+ LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id);
+ deleteListing(folder_id);
+ }
+
}
std::string LLMarketplaceData::getSLMConnectURL(const std::string& route)
{
- std::string url("");
+ std::string url;
LLViewerRegion *regionp = gAgent.getRegion();
if (regionp)
{
// Get DirectDelivery cap
url = regionp->getCapability("DirectDelivery");
- if (url != "")
+ if (!url.empty())
{
url += route;
}
@@ -1983,5 +1816,3 @@ bool LLMarketplaceData::setListingURL(const LLUUID& folder_id, const std::string
return true;
}
-
-
diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h
index f8e7ed4364..9d795c6ced 100755
--- a/indra/newview/llmarketplacefunctions.h
+++ b/indra/newview/llmarketplacefunctions.h
@@ -37,8 +37,6 @@
#include "llstring.h"
-LLSD getMarketplaceStringSubstitutions();
-
namespace MarketplaceErrorCodes
{
@@ -183,6 +181,8 @@ class LLSLMDeleteListingsResponder;
class LLMarketplaceData
: public LLSingleton<LLMarketplaceData>
{
+ friend class LLSingleton < LLMarketplaceData > ;
+
public:
friend class LLSLMGetMerchantResponder;
friend class LLSLMGetListingsResponder;
@@ -192,9 +192,8 @@ public:
friend class LLSLMAssociateListingsResponder;
friend class LLSLMDeleteListingsResponder;
- LLMarketplaceData();
- virtual ~LLMarketplaceData();
-
+ static LLSD getMarketplaceStringSubstitutions();
+
// Public SLM API : Initialization and status
typedef boost::signals2::signal<void ()> status_updated_signal_t;
void initializeSLM(const status_updated_signal_t::slot_type& cb);
@@ -241,8 +240,11 @@ public:
// Used to decide when to run a validation on listing folders
void setValidationWaiting(const LLUUID& folder_id, S32 count);
void decrementValidationWaiting(const LLUUID& folder_id, S32 count = 1);
-
+
private:
+ LLMarketplaceData();
+ virtual ~LLMarketplaceData();
+
// Modify Marketplace data set : each method returns true if the function succeeds, false if error
// Used internally only by SLM Responders when data are received from the SLM Server
bool addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count);
@@ -261,6 +263,14 @@ private:
void deleteSLMListing(S32 listing_id);
std::string getSLMConnectURL(const std::string& route);
+ void getMerchantStatusCoro();
+ void getSLMListingsCoro(LLUUID folderId);
+ void getSingleListingCoro(S32 listingId, LLUUID folderId);
+ void createSLMListingCoro(LLUUID folderId, LLUUID versionId, S32 count);
+ void updateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, bool isListed, S32 count);
+ void associateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, LLUUID sourceFolderId);
+ void deleteSLMListingCoro(S32 listingId);
+
// Handling Marketplace connection and inventory connection
U32 mMarketPlaceStatus;
status_updated_signal_t* mStatusUpdatedSignal;
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index a1f6a01aa0..1045def72e 100755
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -36,6 +36,9 @@
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llworld.h"
+#include "llhttpsdhandler.h"
+#include "httpcommon.h"
+#include "llcorehttputil.h"
/**
* Materials cap parameters
@@ -59,56 +62,51 @@
#define MATERIALS_PUT_THROTTLE_SECS 1.f
#define MATERIALS_PUT_MAX_ENTRIES 50
-/**
- * LLMaterialsResponder helper class
- */
-class LLMaterialsResponder : public LLHTTPClient::Responder
+
+class LLMaterialHttpHandler : public LLHttpSDHandler
{
-public:
- typedef boost::function<void (bool, const LLSD&)> CallbackFunction;
+public:
+ typedef boost::function<void(bool, const LLSD&)> CallbackFunction;
+ typedef boost::shared_ptr<LLMaterialHttpHandler> ptr_t;
+
+ LLMaterialHttpHandler(const std::string& method, CallbackFunction cback);
- LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback);
- virtual ~LLMaterialsResponder();
+ virtual ~LLMaterialHttpHandler();
- virtual void httpSuccess();
- virtual void httpFailure();
+protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
private:
std::string mMethod;
- std::string mCapabilityURL;
CallbackFunction mCallback;
};
-LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback)
- : LLHTTPClient::Responder()
- , mMethod(pMethod)
- , mCapabilityURL(pCapabilityURL)
- , mCallback(pCallback)
+LLMaterialHttpHandler::LLMaterialHttpHandler(const std::string& method, CallbackFunction cback):
+ LLHttpSDHandler(),
+ mMethod(method),
+ mCallback(cback)
{
+
}
-LLMaterialsResponder::~LLMaterialsResponder()
+LLMaterialHttpHandler::~LLMaterialHttpHandler()
{
}
-void LLMaterialsResponder::httpSuccess()
+void LLMaterialHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
{
- const LLSD& pContent = getContent();
-
LL_DEBUGS("Materials") << LL_ENDL;
- mCallback(true, pContent);
+ mCallback(true, content);
}
-void LLMaterialsResponder::httpFailure()
+void LLMaterialHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
{
- U32 pStatus = (U32) getStatus();
- const std::string& pReason = getReason();
-
LL_WARNS("Materials")
<< "\n--------------------------------------------------------------------------\n"
- << mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME
- << "'\n with url '" << mCapabilityURL << "' because " << pReason
+ << mMethod << " Error[" << status.toULong() << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME
+ << "'\n with url '" << response->getRequestURL() << "' because " << status.toString()
<< "\n--------------------------------------------------------------------------"
<< LL_ENDL;
@@ -116,12 +114,35 @@ void LLMaterialsResponder::httpFailure()
mCallback(false, emptyResult);
}
+
+
/**
* LLMaterialMgr class
*/
-
-LLMaterialMgr::LLMaterialMgr()
+LLMaterialMgr::LLMaterialMgr():
+ mGetQueue(),
+ mGetPending(),
+ mGetCallbacks(),
+ mGetTECallbacks(),
+ mGetAllQueue(),
+ mGetAllRequested(),
+ mGetAllPending(),
+ mGetAllCallbacks(),
+ mPutQueue(),
+ mMaterials(),
+ mHttpRequest(),
+ mHttpHeaders(),
+ mHttpOptions(),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mHttpPriority(0)
{
+ LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
+
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
+ mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_MATERIALS);
+
mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL)));
gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL);
LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1));
@@ -554,6 +575,8 @@ void LLMaterialMgr::onIdle(void*)
{
instancep->processPutQueue();
}
+
+ instancep->mHttpRequest->update(0L);
}
void LLMaterialMgr::processGetQueue()
@@ -629,10 +652,26 @@ void LLMaterialMgr::processGetQueue()
LLSD postData = LLSD::emptyMap();
postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
- LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id));
- LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials."
+ LLMaterialHttpHandler * handler =
+ new LLMaterialHttpHandler("POST",
+ boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id)
+ );
+
+ LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '" << capURL << " for " << materialsData.size() << " materials."
<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
- LLHTTPClient::post(capURL, postData, materialsResponder);
+
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
+ mHttpPolicy, mHttpPriority, capURL,
+ postData, mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material POST. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
regionp->resetMaterialsCapThrottle();
}
}
@@ -667,8 +706,22 @@ void LLMaterialMgr::processGetAllQueue()
}
LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL;
- LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion));
- LLHTTPClient::get(capURL, materialsResponder);
+ LLMaterialHttpHandler *handler =
+ new LLMaterialHttpHandler("GET",
+ boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)
+ );
+
+ LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority, capURL,
+ mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material GET. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
regionp->resetMaterialsCapThrottle();
mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
mGetAllQueue.erase(itRegion); // Invalidates region_id
@@ -755,8 +808,24 @@ void LLMaterialMgr::processPutQueue()
putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
- LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
- LLHTTPClient::put(capURL, putData, materialsResponder);
+
+ LLMaterialHttpHandler * handler =
+ new LLMaterialHttpHandler("PUT",
+ boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)
+ );
+
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD(
+ mHttpRequest, mHttpPolicy, mHttpPriority, capURL,
+ putData, mHttpOptions, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_ERRS("Meterials") << "Failed to execute material PUT. Status = " <<
+ status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL;
+ }
+
regionp->resetMaterialsCapThrottle();
}
else
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
index e83f1f4e01..ef202d24ba 100644
--- a/indra/newview/llmaterialmgr.h
+++ b/indra/newview/llmaterialmgr.h
@@ -30,6 +30,9 @@
#include "llmaterial.h"
#include "llmaterialid.h"
#include "llsingleton.h"
+#include "httprequest.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
class LLViewerRegion;
@@ -56,7 +59,7 @@ public:
void put(const LLUUID& object_id, const U8 te, const LLMaterial& material);
void remove(const LLUUID& object_id, const U8 te);
-protected:
+private:
void clearGetQueues(const LLUUID& region_id);
bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const;
bool isGetAllPending(const LLUUID& region_id) const;
@@ -72,16 +75,7 @@ protected:
void onPutResponse(bool success, const LLSD& content);
void onRegionRemoved(LLViewerRegion* regionp);
-protected:
- typedef std::set<LLMaterialID> material_queue_t;
- typedef std::map<LLUUID, material_queue_t> get_queue_t;
- get_queue_t mGetQueue;
- typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
- typedef std::map<const pending_material_t, F64> get_pending_map_t;
- get_pending_map_t mGetPending;
- typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t;
- get_callback_map_t mGetCallbacks;
-
+private:
// struct for TE-specific material ID query
class TEMaterialPair
{
@@ -108,22 +102,37 @@ protected:
bool operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; }
};
- typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;
- get_callback_te_map_t mGetTECallbacks;
+ typedef std::set<LLMaterialID> material_queue_t;
+ typedef std::map<LLUUID, material_queue_t> get_queue_t;
+ typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
+ typedef std::map<const pending_material_t, F64> get_pending_map_t;
+ typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t;
+
+ typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;
typedef std::set<LLUUID> getall_queue_t;
- getall_queue_t mGetAllQueue;
- getall_queue_t mGetAllRequested;
typedef std::map<LLUUID, F64> getall_pending_map_t;
- getall_pending_map_t mGetAllPending;
typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t;
- getall_callback_map_t mGetAllCallbacks;
-
typedef std::map<U8, LLMaterial> facematerial_map_t;
typedef std::map<LLUUID, facematerial_map_t> put_queue_t;
- put_queue_t mPutQueue;
- material_map_t mMaterials;
+ get_queue_t mGetQueue;
+ get_pending_map_t mGetPending;
+ get_callback_map_t mGetCallbacks;
+
+ get_callback_te_map_t mGetTECallbacks;
+ getall_queue_t mGetAllQueue;
+ getall_queue_t mGetAllRequested;
+ getall_pending_map_t mGetAllPending;
+ getall_callback_map_t mGetAllCallbacks;
+ put_queue_t mPutQueue;
+ material_map_t mMaterials;
+
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
+ LLCore::HttpRequest::priority_t mHttpPriority;
U32 getMaxEntries(const LLViewerRegion* regionp);
};
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index 2fb9e60b29..bfd0700a2f 100755
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -33,6 +33,7 @@
#pragma warning (disable:4702)
#endif
+#include <algorithm>
#include <boost/lexical_cast.hpp>
#include "llhttpconstants.h"
@@ -40,6 +41,7 @@
#include "llmediaentry.h"
#include "lltextureentry.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
//
// When making a request
@@ -91,52 +93,74 @@ const U32 LLMediaDataClient::MAX_ROUND_ROBIN_QUEUE_SIZE = 10000;
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q);
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q);
-template <typename T>
-typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type)
+
+//=========================================================================
+/// Uniary Predicate for matching requests in collections by either the request
+/// or by UUID
+///
+class PredicateMatchRequest
{
- for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter)
- {
- if(request->isMatch(*iter, match_type))
- {
- return iter;
- }
- }
-
- return c.end();
+public:
+ PredicateMatchRequest(const LLMediaDataClient::Request::ptr_t &request, LLMediaDataClient::Request::Type matchType = LLMediaDataClient::Request::ANY);
+ PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType = LLMediaDataClient::Request::ANY);
+
+ PredicateMatchRequest(const PredicateMatchRequest &other);
+
+ bool operator()(const LLMediaDataClient::Request::ptr_t &test) const;
+
+private:
+ LLMediaDataClient::Request::ptr_t mRequest;
+ LLMediaDataClient::Request::Type mMatchType;
+ LLUUID mId;
+};
+
+
+PredicateMatchRequest::PredicateMatchRequest(const LLMediaDataClient::Request::ptr_t &request, LLMediaDataClient::Request::Type matchType) :
+ mRequest(request),
+ mMatchType(matchType),
+ mId()
+{}
+
+PredicateMatchRequest::PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType) :
+ mRequest(),
+ mMatchType(matchType),
+ mId(id)
+{}
+
+PredicateMatchRequest::PredicateMatchRequest(const PredicateMatchRequest &other)
+{
+ mRequest = other.mRequest;
+ mMatchType = other.mMatchType;
+ mId = other.mId;
}
-template <typename T>
-typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type)
+bool PredicateMatchRequest::operator()(const LLMediaDataClient::Request::ptr_t &test) const
{
- for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter)
- {
- if(((*iter)->getID() == id) && ((match_type == LLMediaDataClient::Request::ANY) || (match_type == (*iter)->getType())))
- {
- return iter;
- }
- }
-
- return c.end();
+ if (mRequest)
+ return (mRequest->isMatch(test, mMatchType));
+ else if (!mId.isNull())
+ return ((test->getID() == mId) && ((mMatchType == LLMediaDataClient::Request::ANY) || (mMatchType == test->getType())));
+ return false;
}
-// NOTE: remove_matching_requests will not work correctly for containers where deleting an element may invalidate iterators
-// to other elements in the container (such as std::vector).
-// If the implementation is changed to use a container with this property, this will need to be revisited.
+//=========================================================================
+///
template <typename T>
-void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type)
+void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred)
{
- for(typename T::iterator iter = c.begin(); iter != c.end();)
- {
- typename T::value_type i = *iter;
- typename T::iterator next = iter;
- next++;
- if((i->getID() == id) && ((match_type == LLMediaDataClient::Request::ANY) || (match_type == i->getType())))
- {
- i->markDead();
- c.erase(iter);
- }
- iter = next;
- }
+ for (typename T::iterator it = c.begin(); it != c.end();)
+ {
+ if (matchPred(*it))
+ {
+ (*it)->markDead();
+ // *TDOO: When C++11 is in change the following line to: it = c.erase(it);
+ c.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -145,18 +169,20 @@ void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request
//
//////////////////////////////////////////////////////////////////////////////////////
-LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay,
- F32 retry_timer_delay,
- U32 max_retries,
- U32 max_sorted_queue_size,
- U32 max_round_robin_queue_size)
- : mQueueTimerDelay(queue_timer_delay),
- mRetryTimerDelay(retry_timer_delay),
- mMaxNumRetries(max_retries),
- mMaxSortedQueueSize(max_sorted_queue_size),
- mMaxRoundRobinQueueSize(max_round_robin_queue_size),
- mQueueTimerIsRunning(false)
+LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay,
+ U32 max_retries, U32 max_sorted_queue_size, U32 max_round_robin_queue_size):
+ mQueueTimerDelay(queue_timer_delay),
+ mRetryTimerDelay(retry_timer_delay),
+ mMaxNumRetries(max_retries),
+ mMaxSortedQueueSize(max_sorted_queue_size),
+ mMaxRoundRobinQueueSize(max_round_robin_queue_size),
+ mQueueTimerIsRunning(false),
+ mHttpRequest(new LLCore::HttpRequest()),
+ mHttpHeaders(new LLCore::HttpHeaders()),
+ mHttpOpts(new LLCore::HttpOptions()),
+ mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID)
{
+ // *TODO: Look up real Policy ID
}
LLMediaDataClient::~LLMediaDataClient()
@@ -171,20 +197,23 @@ bool LLMediaDataClient::isEmpty() const
bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object)
{
- if(find_matching_request(mQueue, object->getID(), LLMediaDataClient::Request::ANY) != mQueue.end())
- return true;
-
- if(find_matching_request(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY) != mUnQueuedRequests.end())
- return true;
-
+ PredicateMatchRequest upred(object->getID());
+
+ if (std::find_if(mQueue.begin(), mQueue.end(), upred) != mQueue.end())
+ return true;
+ if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end())
+ return true;
+
return false;
}
void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object)
{
LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL;
- remove_matching_requests(mQueue, object->getID(), LLMediaDataClient::Request::ANY);
- remove_matching_requests(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY);
+ PredicateMatchRequest upred(object->getID());
+
+ mark_dead_and_remove_if(mQueue, upred);
+ mark_dead_and_remove_if(mUnQueuedRequests, upred);
}
void LLMediaDataClient::startQueueTimer()
@@ -207,23 +236,24 @@ void LLMediaDataClient::stopQueueTimer()
bool LLMediaDataClient::processQueueTimer()
{
- if(isEmpty())
+ if (isDoneProcessing())
return true;
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is: " << mQueue.size() << LL_ENDL;
LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mQueue << LL_ENDL;
serviceQueue();
-
+ serviceHttp();
+
LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is: " << mQueue.size() << LL_ENDL;
LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mQueue << LL_ENDL;
- return isEmpty();
+ return isDoneProcessing();
}
-LLMediaDataClient::request_ptr_t LLMediaDataClient::dequeue()
+LLMediaDataClient::Request::ptr_t LLMediaDataClient::dequeue()
{
- request_ptr_t request;
+ Request::ptr_t request;
request_queue_t *queue_p = getQueue();
if (queue_p->empty())
@@ -242,20 +272,20 @@ LLMediaDataClient::request_ptr_t LLMediaDataClient::dequeue()
else
{
// Don't return this request -- it's not ready to be serviced.
- request = NULL;
+ request.reset();
}
}
return request;
}
-void LLMediaDataClient::pushBack(request_ptr_t request)
+void LLMediaDataClient::pushBack(Request::ptr_t request)
{
request_queue_t *queue_p = getQueue();
queue_p->push_front(request);
}
-void LLMediaDataClient::trackRequest(request_ptr_t request)
+void LLMediaDataClient::trackRequest(Request::ptr_t request)
{
request_set_t::iterator iter = mUnQueuedRequests.find(request);
@@ -269,7 +299,7 @@ void LLMediaDataClient::trackRequest(request_ptr_t request)
}
}
-void LLMediaDataClient::stopTrackingRequest(request_ptr_t request)
+void LLMediaDataClient::stopTrackingRequest(Request::ptr_t request)
{
request_set_t::iterator iter = mUnQueuedRequests.find(request);
@@ -283,16 +313,22 @@ void LLMediaDataClient::stopTrackingRequest(request_ptr_t request)
}
}
+bool LLMediaDataClient::isDoneProcessing() const
+{
+ return (isEmpty() && mUnQueuedRequests.empty());
+}
+
+
void LLMediaDataClient::serviceQueue()
{
// Peel one off of the items from the queue and execute it
- request_ptr_t request;
+ Request::ptr_t request;
do
{
request = dequeue();
- if(request.isNull())
+ if(!request)
{
// Queue is empty.
return;
@@ -317,7 +353,18 @@ void LLMediaDataClient::serviceQueue()
trackRequest(request);
// and make the post
- LLHTTPClient::post(url, sd_payload, request->createResponder());
+ LLHttpSDHandler *handler = request->createHandler();
+ LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, mHttpPolicy, 0,
+ url, sd_payload, mHttpOpts, mHttpHeaders, handler);
+
+ if (handle == LLCORE_HTTP_HANDLE_INVALID)
+ {
+ // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers. Requires change in LLCore::HTTP
+ delete handler;
+ LLCore::HttpStatus status = mHttpRequest->getStatus();
+ LL_WARNS("LLMediaDataClient") << "'" << url << "' request POST failed. Reason "
+ << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL;
+ }
}
else
{
@@ -332,13 +379,17 @@ void LLMediaDataClient::serviceQueue()
}
else
{
- // This request has exceeded its maxumim retry count. It will be dropped.
+ // This request has exceeded its maximum retry count. It will be dropped.
LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL;
}
}
}
+void LLMediaDataClient::serviceHttp()
+{
+ mHttpRequest->update(0);
+}
// dump the queue
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q)
@@ -395,7 +446,7 @@ BOOL LLMediaDataClient::QueueTimer::tick()
//
//////////////////////////////////////////////////////////////////////////////////////
-LLMediaDataClient::RetryTimer::RetryTimer(F32 time, request_ptr_t request)
+LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request)
: LLEventTimer(time), mRequest(request)
{
mRequest->startTracking();
@@ -417,7 +468,7 @@ BOOL LLMediaDataClient::RetryTimer::tick()
}
// Release the ref to the request.
- mRequest = NULL;
+ mRequest.reset();
// Don't fire again
return TRUE;
@@ -490,7 +541,7 @@ void LLMediaDataClient::Request::reEnqueue()
{
if(mMDC)
{
- mMDC->enqueue(this);
+ mMDC->enqueue(shared_from_this());
}
}
@@ -533,13 +584,13 @@ bool LLMediaDataClient::Request::isDead()
void LLMediaDataClient::Request::startTracking()
{
if(mMDC)
- mMDC->trackRequest(this);
+ mMDC->trackRequest(shared_from_this());
}
void LLMediaDataClient::Request::stopTracking()
{
if(mMDC)
- mMDC->stopTrackingRequest(this);
+ mMDC->stopTrackingRequest(shared_from_this());
}
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
@@ -551,79 +602,61 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
<< " #retries=" << r.getRetryCount();
return s;
}
-
-//////////////////////////////////////////////////////////////////////////////////////
-//
-// LLMediaDataClient::Responder
-//
-//////////////////////////////////////////////////////////////////////////////////////
-LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
-: mRequest(request)
+//========================================================================
+
+LLMediaDataClient::Handler::Handler(const Request::ptr_t &request):
+ mRequest(request)
{
}
-/*virtual*/
-void LLMediaDataClient::Responder::httpFailure()
+
+void LLMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
{
- mRequest->stopTracking();
+ mRequest->stopTracking();
- if(mRequest->isDead())
- {
- LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL;
- return;
- }
-
- if (getStatus() == HTTP_SERVICE_UNAVAILABLE)
- {
- 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();
-
- if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())
- {
- LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
-
- // Start timer (instances are automagically tracked by
- // InstanceTracker<> and LLEventTimer)
- new RetryTimer(F32(retry_timeout/*secs*/), mRequest);
- }
- else
- {
- LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count "
- << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
- }
- }
- // *TODO: Redirect on 3xx status codes.
- else
- {
- LL_WARNS("LLMediaDataClient") << *mRequest << " http failure "
- << dumpResponse() << LL_ENDL;
- }
+ if (mRequest->isDead())
+ {
+ LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL;
+ return;
+ }
+
+ LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << LL_ENDL;
}
-/*virtual*/
-void LLMediaDataClient::Responder::httpSuccess()
+void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
{
- mRequest->stopTracking();
+ mRequest->stopTracking();
- if(mRequest->isDead())
- {
- LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL;
- return;
- }
+ if (status == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE))
+ {
+ F32 retry_timeout;
+
+ retry_timeout = mRequest->getRetryTimerDelay();
+
+ mRequest->incRetryCount();
+
+ if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())
+ {
+ LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
- LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL;
+ // Start timer (instances are automagically tracked by
+ // InstanceTracker<> and LLEventTimer)
+ new RetryTimer(F32(retry_timeout/*secs*/), mRequest);
+ }
+ else
+ {
+ LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count "
+ << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("LLMediaDataClient") << *mRequest << " HTTP failure " << LL_ENDL;
+ }
}
+
//////////////////////////////////////////////////////////////////////////////////////
//
// LLObjectMediaDataClient
@@ -634,7 +667,7 @@ void LLMediaDataClient::Responder::httpSuccess()
void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object)
{
// Create a get request and put it in the queue.
- enqueue(new RequestGet(object, this));
+ enqueue(Request::ptr_t(new RequestGet(object, this)));
}
const char *LLObjectMediaDataClient::getCapabilityName() const
@@ -678,14 +711,14 @@ void LLObjectMediaDataClient::sortQueue()
}
// static
-bool LLObjectMediaDataClient::compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2)
+bool LLObjectMediaDataClient::compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2)
{
- if (o2.isNull()) return true;
- if (o1.isNull()) return false;
+ if (!o2) return true;
+ if (!o1) return false;
return ( o1->getScore() > o2->getScore() );
}
-void LLObjectMediaDataClient::enqueue(Request *request)
+void LLObjectMediaDataClient::enqueue(Request::ptr_t request)
{
if(request->isDead())
{
@@ -703,9 +736,10 @@ void LLObjectMediaDataClient::enqueue(Request *request)
{
// For GET requests that are not new, if a matching request is already in the round robin queue,
// in flight, or being retried, leave it at its current position.
- request_queue_t::iterator iter = find_matching_request(mRoundRobinQueue, request->getID(), Request::GET);
- request_set_t::iterator iter2 = find_matching_request(mUnQueuedRequests, request->getID(), Request::GET);
-
+ PredicateMatchRequest upred(request->getID(), Request::GET);
+ request_queue_t::iterator iter = std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), upred);
+ request_set_t::iterator iter2 = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred);
+
if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) )
{
LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL;
@@ -718,9 +752,11 @@ void LLObjectMediaDataClient::enqueue(Request *request)
// IF the update will cause an object update message to be sent out at some point in the future, it probably should.
// Remove any existing requests of this type for this object
- remove_matching_requests(mQueue, request->getID(), request->getType());
- remove_matching_requests(mRoundRobinQueue, request->getID(), request->getType());
- remove_matching_requests(mUnQueuedRequests, request->getID(), request->getType());
+ PredicateMatchRequest upred(request->getID(), request->getType());
+
+ mark_dead_and_remove_if(mQueue, upred);
+ mark_dead_and_remove_if(mRoundRobinQueue, upred);
+ mark_dead_and_remove_if(mUnQueuedRequests, upred);
if (is_new)
{
@@ -749,7 +785,7 @@ void LLObjectMediaDataClient::enqueue(Request *request)
startQueueTimer();
}
-bool LLObjectMediaDataClient::canServiceRequest(request_ptr_t request)
+bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request)
{
if(mCurrentQueueIsTheSortedQueue)
{
@@ -785,9 +821,9 @@ bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &ob
if(LLMediaDataClient::isInQueue(object))
return true;
- if(find_matching_request(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY) != mRoundRobinQueue.end())
- return true;
-
+ if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end())
+ return true;
+
return false;
}
@@ -796,12 +832,12 @@ void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr
// First, call parent impl.
LLMediaDataClient::removeFromQueue(object);
- remove_matching_requests(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY);
+ mark_dead_and_remove_if(mRoundRobinQueue, PredicateMatchRequest(object->getID()));
}
bool LLObjectMediaDataClient::processQueueTimer()
{
- if(isEmpty())
+ if (isDoneProcessing())
return true;
LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is: " << mQueue.size()
@@ -816,6 +852,7 @@ bool LLObjectMediaDataClient::processQueueTimer()
LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is: " << mQueue << LL_ENDL;
serviceQueue();
+ serviceHttp();
swapCurrentQueue();
@@ -824,7 +861,7 @@ bool LLObjectMediaDataClient::processQueueTimer()
LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL;
LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL;
- return isEmpty();
+ return isDoneProcessing();
}
LLObjectMediaDataClient::RequestGet::RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc):
@@ -841,16 +878,16 @@ LLSD LLObjectMediaDataClient::RequestGet::getPayload() const
return result;
}
-LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestGet::createResponder()
+LLHttpSDHandler *LLObjectMediaDataClient::RequestGet::createHandler()
{
- return new LLObjectMediaDataClient::Responder(this);
+ return new LLObjectMediaDataClient::Handler(shared_from_this());
}
void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object)
{
// Create an update request and put it in the queue.
- enqueue(new RequestUpdate(object, this));
+ enqueue(Request::ptr_t(new RequestUpdate(object, this)));
}
LLObjectMediaDataClient::RequestUpdate::RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc):
@@ -877,60 +914,58 @@ LLSD LLObjectMediaDataClient::RequestUpdate::getPayload() const
return result;
}
-LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResponder()
+LLHttpSDHandler *LLObjectMediaDataClient::RequestUpdate::createHandler()
{
// This just uses the base class's responder.
- return new LLMediaDataClient::Responder(this);
+ return new LLMediaDataClient::Handler(shared_from_this());
}
-
-/*virtual*/
-void LLObjectMediaDataClient::Responder::httpSuccess()
+void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
{
- getRequest()->stopTracking();
+ LLMediaDataClient::Handler::onSuccess(response, content);
+
+ if (getRequest()->isDead())
+ { // warning emitted from base method.
+ return;
+ }
+
+ if (!content.isMap())
+ {
+ onFailure(response, LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents"));
+ return;
+ }
+
+ // This responder is only used for GET requests, not UPDATE.
+ LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << LL_ENDL;
+
+ // Look for an error
+ if (content.has("error"))
+ {
+ const LLSD &error = content["error"];
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" <<
+ error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
+
+ // XXX Warn user?
+ }
+ else
+ {
+ // Check the data
+ const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY];
+ if (object_id != getRequest()->getObject()->getID())
+ {
+ // NOT good, wrong object id!!
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL;
+ return;
+ }
+
+ // Otherwise, update with object media data
+ getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
+ content[LLTextureEntry::MEDIA_VERSION_KEY]);
+ }
- if(getRequest()->isDead())
- {
- LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL;
- 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;
-
- // Look for an error
- if (content.has("error"))
- {
- const LLSD &error = content["error"];
- LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" <<
- error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
-
- // XXX Warn user?
- }
- else
- {
- // Check the data
- const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY];
- if (object_id != getRequest()->getObject()->getID())
- {
- // NOT good, wrong object id!!
- LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL;
- return;
- }
-
- // Otherwise, update with object media data
- getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
- content[LLTextureEntry::MEDIA_VERSION_KEY]);
- }
}
+
//////////////////////////////////////////////////////////////////////////////////////
//
// LLObjectMediaNavigateClient
@@ -943,16 +978,18 @@ const char *LLObjectMediaNavigateClient::getCapabilityName() const
return "ObjectMediaNavigate";
}
-void LLObjectMediaNavigateClient::enqueue(Request *request)
+void LLObjectMediaNavigateClient::enqueue(Request::ptr_t request)
{
if(request->isDead())
{
- LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL;
+ LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL;
return;
}
+ PredicateMatchRequest upred(request);
+
// If there's already a matching request in the queue, remove it.
- request_queue_t::iterator iter = find_matching_request(mQueue, request, LLMediaDataClient::Request::ANY);
+ request_queue_t::iterator iter = std::find_if(mQueue.begin(), mQueue.end(), upred);
if(iter != mQueue.end())
{
LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL;
@@ -960,7 +997,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request)
}
else
{
- request_set_t::iterator set_iter = find_matching_request(mUnQueuedRequests, request, LLMediaDataClient::Request::ANY);
+ request_set_t::iterator set_iter = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred);
if(set_iter != mUnQueuedRequests.end())
{
LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL;
@@ -979,7 +1016,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request)
else
#endif
{
- LL_DEBUGS("LLMediaDataClient") << "queueing new request " << (*request) << LL_ENDL;
+ LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL;
mQueue.push_back(request);
// Start the timer if not already running
@@ -993,7 +1030,7 @@ void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 t
// LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL;
// Create a get request and put it in the queue.
- enqueue(new RequestNavigate(object, this, texture_index, url));
+ enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url)));
}
LLObjectMediaNavigateClient::RequestNavigate::RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url):
@@ -1012,75 +1049,67 @@ LLSD LLObjectMediaNavigateClient::RequestNavigate::getPayload() const
return result;
}
-LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::createResponder()
+LLHttpSDHandler *LLObjectMediaNavigateClient::RequestNavigate::createHandler()
{
- return new LLObjectMediaNavigateClient::Responder(this);
+ return new LLObjectMediaNavigateClient::Handler(shared_from_this());
}
-/*virtual*/
-void LLObjectMediaNavigateClient::Responder::httpFailure()
+void LLObjectMediaNavigateClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)
{
- getRequest()->stopTracking();
+ LLMediaDataClient::Handler::onSuccess(response, content);
- if(getRequest()->isDead())
- {
- LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL;
- return;
- }
+ if (getRequest()->isDead())
+ { // already warned.
+ return;
+ }
+
+ LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned" << LL_ENDL;
+
+ if (content.has("error"))
+ {
+ const LLSD &error = content["error"];
+ int error_code = error["code"];
+
+ if (ERROR_PERMISSION_DENIED_CODE == error_code)
+ {
+ mediaNavigateBounceBack();
+ }
+ else
+ {
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" <<
+ error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
+ }
+
+ // XXX Warn user?
+ }
+ else
+ {
+ // No action required.
+ LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << LL_ENDL;
+ }
- // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base
- // class
- if (getStatus() == HTTP_SERVICE_UNAVAILABLE)
- {
- LLMediaDataClient::Responder::httpFailure();
- }
- else
- {
- // bounce the face back
- 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]);
- }
}
-/*virtual*/
-void LLObjectMediaNavigateClient::Responder::httpSuccess()
+void LLObjectMediaNavigateClient::Handler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)
{
- getRequest()->stopTracking();
+ LLMediaDataClient::Handler::onFailure(response, status);
- if(getRequest()->isDead())
- {
- LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL;
- return;
- }
+ if (getRequest()->isDead())
+ { // already warned.
+ return;
+ }
- LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL;
-
- const LLSD& content = getContent();
- if (content.has("error"))
- {
- const LLSD &error = content["error"];
- int error_code = error["code"];
-
- if (ERROR_PERMISSION_DENIED_CODE == error_code)
- {
- LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL;
- const LLSD &payload = getRequest()->getPayload();
- // bounce the face back
- getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
- }
- else
- {
- LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" <<
- error["code"].asString() << ": " << error["message"].asString() << LL_ENDL;
- }
+ if (status != LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE))
+ {
+ mediaNavigateBounceBack();
+ }
+}
- // XXX Warn user?
- }
- else
- {
- // No action required.
- LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL;
- }
+void LLObjectMediaNavigateClient::Handler::mediaNavigateBounceBack()
+{
+ LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating or denied." << LL_ENDL;
+ const LLSD &payload = getRequest()->getPayload();
+
+ // bounce the face back
+ getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);
}
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 80dd519812..9907897613 100755
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -27,12 +27,15 @@
#ifndef LL_LLMEDIADATACLIENT_H
#define LL_LLMEDIADATACLIENT_H
-#include "llhttpclient.h"
#include <set>
#include "llrefcount.h"
#include "llpointer.h"
#include "lleventtimer.h"
-
+#include "llhttpsdhandler.h"
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+#include "httpheaders.h"
// Link seam for LLVOVolume
class LLMediaDataClientObject : public LLRefCount
@@ -74,6 +77,8 @@ public:
// Abstracts the Cap URL, the request, and the responder
class LLMediaDataClient : public LLRefCount
{
+ friend class PredicateMatchRequest;
+
protected:
LOG_CLASS(LLMediaDataClient);
public:
@@ -109,26 +114,30 @@ protected:
// Destructor
virtual ~LLMediaDataClient(); // use unref
- class Responder;
-
// Request (pure virtual base class for requests in the queue)
- class Request : public LLRefCount
- {
- public:
- // Subclasses must implement this to build a payload for their request type.
- virtual LLSD getPayload() const = 0;
- // and must create the correct type of responder.
- virtual Responder *createResponder() = 0;
+ class Request:
+ public boost::enable_shared_from_this<Request>
+ {
+ public:
+ typedef boost::shared_ptr<Request> ptr_t;
- virtual std::string getURL() { return ""; }
+ // Subclasses must implement this to build a payload for their request type.
+ virtual LLSD getPayload() const = 0;
+ // and must create the correct type of responder.
+ virtual LLHttpSDHandler *createHandler() = 0;
+
+ virtual std::string getURL() { return ""; }
enum Type {
GET,
UPDATE,
NAVIGATE,
- ANY
+ ANY
};
-
+
+ virtual ~Request()
+ { }
+
protected:
// The only way to create one of these is through a subclass.
Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1);
@@ -166,7 +175,7 @@ protected:
const LLUUID &getID() const { return mObjectID; }
S32 getFace() const { return mFace; }
- bool isMatch (const Request* other, Type match_type = ANY) const
+ bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const
{
return ((match_type == ANY) || (mType == other->mType)) &&
(mFace == other->mFace) &&
@@ -188,61 +197,62 @@ protected:
// Back pointer to the MDC...not a ref!
LLMediaDataClient *mMDC;
};
- typedef LLPointer<Request> request_ptr_t;
+ //typedef LLPointer<Request> request_ptr_t;
- // Responder
- class Responder : public LLHTTPClient::Responder
- {
- LOG_CLASS(Responder);
- public:
- Responder(const request_ptr_t &request);
- request_ptr_t &getRequest() { return mRequest; }
+ class Handler : public LLHttpSDHandler
+ {
+ LOG_CLASS(Handler);
+ public:
+ Handler(const Request::ptr_t &request);
+ Request::ptr_t getRequest() const { return mRequest; }
- protected:
- //If we get back an error (not found, etc...), handle it here
- virtual void httpFailure();
- //If we get back a normal response, handle it here. Default just logs it.
- virtual void httpSuccess();
+ protected:
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
+
+ private:
+ Request::ptr_t mRequest;
+ };
- private:
- request_ptr_t mRequest;
- };
class RetryTimer : public LLEventTimer
{
public:
- RetryTimer(F32 time, request_ptr_t);
+ RetryTimer(F32 time, Request::ptr_t);
virtual BOOL tick();
private:
// back-pointer
- request_ptr_t mRequest;
+ Request::ptr_t mRequest;
};
protected:
- typedef std::list<request_ptr_t> request_queue_t;
- typedef std::set<request_ptr_t> request_set_t;
+ typedef std::list<Request::ptr_t> request_queue_t;
+ typedef std::set<Request::ptr_t> request_set_t;
// Subclasses must override to return a cap name
virtual const char *getCapabilityName() const = 0;
// Puts the request into a queue, appropriately handling duplicates, etc.
- virtual void enqueue(Request*) = 0;
+ virtual void enqueue(Request::ptr_t) = 0;
virtual void serviceQueue();
+ virtual void serviceHttp();
virtual request_queue_t *getQueue() { return &mQueue; };
// Gets the next request, removing it from the queue
- virtual request_ptr_t dequeue();
+ virtual Request::ptr_t dequeue();
- virtual bool canServiceRequest(request_ptr_t request) { return true; };
+ virtual bool canServiceRequest(Request::ptr_t request) { return true; };
// Returns a request to the head of the queue (should only be used for requests that came from dequeue
- virtual void pushBack(request_ptr_t request);
+ virtual void pushBack(Request::ptr_t request);
- void trackRequest(request_ptr_t request);
- void stopTrackingRequest(request_ptr_t request);
+ void trackRequest(Request::ptr_t request);
+ void stopTrackingRequest(Request::ptr_t request);
+
+ bool isDoneProcessing() const;
request_queue_t mQueue;
@@ -260,6 +270,11 @@ protected:
void startQueueTimer();
void stopQueueTimer();
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOpts;
+ LLCore::HttpRequest::policy_t mHttpPolicy;
+
private:
static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj);
@@ -281,9 +296,9 @@ private:
bool mQueueTimerIsRunning;
- template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type);
- template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);
- template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);
+// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type);
+// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);
+// template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);
};
// MediaDataClient specific for the ObjectMedia cap
@@ -309,7 +324,7 @@ public:
public:
RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
/*virtual*/ LLSD getPayload() const;
- /*virtual*/ Responder *createResponder();
+ /*virtual*/ LLHttpSDHandler *createHandler();
};
class RequestUpdate: public Request
@@ -317,7 +332,7 @@ public:
public:
RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
/*virtual*/ LLSD getPayload() const;
- /*virtual*/ Responder *createResponder();
+ /*virtual*/ LLHttpSDHandler *createHandler();
};
// Returns true iff the queue is empty
@@ -331,7 +346,7 @@ public:
virtual bool processQueueTimer();
- virtual bool canServiceRequest(request_ptr_t request);
+ virtual bool canServiceRequest(Request::ptr_t request);
protected:
// Subclasses must override to return a cap name
@@ -340,17 +355,20 @@ protected:
virtual request_queue_t *getQueue();
// Puts the request into the appropriate queue
- virtual void enqueue(Request*);
+ virtual void enqueue(Request::ptr_t);
- class Responder : public LLMediaDataClient::Responder
+ class Handler: public LLMediaDataClient::Handler
{
- LOG_CLASS(Responder);
+ LOG_CLASS(Handler);
public:
- Responder(const request_ptr_t &request)
- : LLMediaDataClient::Responder(request) {}
+ Handler(const Request::ptr_t &request):
+ LLMediaDataClient::Handler(request)
+ {}
+
protected:
- virtual void httpSuccess();
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
};
+
private:
// The Get/Update data client needs a second queue to avoid object updates starving load-ins.
void swapCurrentQueue();
@@ -359,7 +377,7 @@ private:
bool mCurrentQueueIsTheSortedQueue;
// Comparator for sorting
- static bool compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2);
+ static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2);
void sortQueue();
};
@@ -384,14 +402,14 @@ public:
void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);
// Puts the request into the appropriate queue
- virtual void enqueue(Request*);
+ virtual void enqueue(Request::ptr_t);
class RequestNavigate: public Request
{
public:
RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url);
/*virtual*/ LLSD getPayload() const;
- /*virtual*/ Responder *createResponder();
+ /*virtual*/ LLHttpSDHandler *createHandler();
/*virtual*/ std::string getURL() { return mURL; }
private:
std::string mURL;
@@ -401,15 +419,18 @@ protected:
// Subclasses must override to return a cap name
virtual const char *getCapabilityName() const;
- class Responder : public LLMediaDataClient::Responder
+ class Handler : public LLMediaDataClient::Handler
{
- LOG_CLASS(Responder);
+ LOG_CLASS(Handler);
public:
- Responder(const request_ptr_t &request)
- : LLMediaDataClient::Responder(request) {}
+ Handler(const Request::ptr_t &request):
+ LLMediaDataClient::Handler(request)
+ {}
+
protected:
- virtual void httpFailure();
- virtual void httpSuccess();
+ virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);
+ virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);
+
private:
void mediaNavigateBounceBack();
};
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 55b94aa141..457053f713 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -36,7 +36,6 @@
#include "llappviewer.h"
#include "llbufferstream.h"
#include "llcallbacklist.h"
-#include "llcurl.h"
#include "lldatapacker.h"
#include "lldeadmantimer.h"
#include "llfloatermodelpreview.h"
@@ -73,6 +72,10 @@
#include "llfasttimer.h"
#include "llcorehttputil.h"
#include "lltrans.h"
+#include "llstatusbar.h"
+#include "llinventorypanel.h"
+#include "lluploaddialog.h"
+#include "llfloaterreg.h"
#include "boost/lexical_cast.hpp"
@@ -413,6 +416,17 @@ static unsigned int metrics_teleport_start_count = 0;
boost::signals2::connection metrics_teleport_started_signal;
static void teleport_started();
+void on_new_single_inventory_upload_complete(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ const std::string inventory_type_string,
+ const LLUUID& item_folder_id,
+ const std::string& item_name,
+ const std::string& item_description,
+ const LLSD& server_response,
+ S32 upload_price);
+
+
//get the number of bytes resident in memory for given volume
U32 get_volume_memory_size(const LLVolume* volume)
{
@@ -774,9 +788,9 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
LLMeshRepoThread::LLMeshRepoThread()
: LLThread("mesh repo"),
mHttpRequest(NULL),
- mHttpOptions(NULL),
- mHttpLargeOptions(NULL),
- mHttpHeaders(NULL),
+ mHttpOptions(),
+ mHttpLargeOptions(),
+ mHttpHeaders(),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
@@ -789,13 +803,13 @@ LLMeshRepoThread::LLMeshRepoThread()
mHeaderMutex = new LLMutex(NULL);
mSignal = new LLCondition(NULL);
mHttpRequest = new LLCore::HttpRequest;
- mHttpOptions = new LLCore::HttpOptions;
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
mHttpOptions->setTransferTimeout(SMALL_MESH_XFER_TIMEOUT);
mHttpOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter"));
- mHttpLargeOptions = new LLCore::HttpOptions;
+ mHttpLargeOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
mHttpLargeOptions->setTransferTimeout(LARGE_MESH_XFER_TIMEOUT);
mHttpLargeOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter"));
- mHttpHeaders = new LLCore::HttpHeaders;
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_VND_LL_MESH);
mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH2);
mHttpLegacyPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH1);
@@ -817,22 +831,9 @@ LLMeshRepoThread::~LLMeshRepoThread()
delete *iter;
}
mHttpRequestSet.clear();
- if (mHttpHeaders)
- {
- mHttpHeaders->release();
- mHttpHeaders = NULL;
- }
- if (mHttpOptions)
- {
- mHttpOptions->release();
- mHttpOptions = NULL;
- }
- if (mHttpLargeOptions)
- {
- mHttpLargeOptions->release();
- mHttpLargeOptions = NULL;
- }
- delete mHttpRequest;
+ mHttpHeaders.reset();
+
+ delete mHttpRequest;
mHttpRequest = NULL;
delete mMutex;
mMutex = NULL;
@@ -1918,11 +1919,11 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut");
mHttpRequest = new LLCore::HttpRequest;
- mHttpOptions = new LLCore::HttpOptions;
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
mHttpOptions->setTransferTimeout(mMeshUploadTimeOut);
mHttpOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter"));
mHttpOptions->setRetries(UPLOAD_RETRY_LIMIT);
- mHttpHeaders = new LLCore::HttpHeaders;
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_UPLOADS);
mHttpPriority = 0;
@@ -1930,16 +1931,6 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
LLMeshUploadThread::~LLMeshUploadThread()
{
- if (mHttpHeaders)
- {
- mHttpHeaders->release();
- mHttpHeaders = NULL;
- }
- if (mHttpOptions)
- {
- mHttpOptions->release();
- mHttpOptions = NULL;
- }
delete mHttpRequest;
mHttpRequest = NULL;
}
@@ -4723,3 +4714,122 @@ void teleport_started()
LLMeshRepository::metricsStart();
}
+
+void on_new_single_inventory_upload_complete(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType inventory_type,
+ const std::string inventory_type_string,
+ const LLUUID& item_folder_id,
+ const std::string& item_name,
+ const std::string& item_description,
+ const LLSD& server_response,
+ S32 upload_price)
+{
+ bool success = false;
+
+ if (upload_price > 0)
+ {
+ // this upload costed us L$, update our balance
+ // and display something saying that it cost L$
+ LLStatusBar::sendMoneyBalanceRequest();
+
+ LLSD args;
+ args["AMOUNT"] = llformat("%d", upload_price);
+ LLNotificationsUtil::add("UploadPayment", args);
+ }
+
+ if (item_folder_id.notNull())
+ {
+ U32 everyone_perms = PERM_NONE;
+ U32 group_perms = PERM_NONE;
+ U32 next_owner_perms = PERM_ALL;
+ if (server_response.has("new_next_owner_mask"))
+ {
+ // The server provided creation perms so use them.
+ // Do not assume we got the perms we asked for in
+ // since the server may not have granted them all.
+ everyone_perms = server_response["new_everyone_mask"].asInteger();
+ group_perms = server_response["new_group_mask"].asInteger();
+ next_owner_perms = server_response["new_next_owner_mask"].asInteger();
+ }
+ else
+ {
+ // The server doesn't provide creation perms
+ // so use old assumption-based perms.
+ if (inventory_type_string != "snapshot")
+ {
+ next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+ }
+ }
+
+ LLPermissions new_perms;
+ new_perms.init(
+ gAgent.getID(),
+ gAgent.getID(),
+ LLUUID::null,
+ LLUUID::null);
+
+ new_perms.initMasks(
+ PERM_ALL,
+ PERM_ALL,
+ everyone_perms,
+ group_perms,
+ next_owner_perms);
+
+ U32 inventory_item_flags = 0;
+ if (server_response.has("inventory_flags"))
+ {
+ inventory_item_flags = (U32)server_response["inventory_flags"].asInteger();
+ if (inventory_item_flags != 0)
+ {
+ LL_INFOS() << "inventory_item_flags " << inventory_item_flags << LL_ENDL;
+ }
+ }
+ S32 creation_date_now = time_corrected();
+ LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+ server_response["new_inventory_item"].asUUID(),
+ item_folder_id,
+ new_perms,
+ server_response["new_asset"].asUUID(),
+ asset_type,
+ inventory_type,
+ item_name,
+ item_description,
+ LLSaleInfo::DEFAULT,
+ inventory_item_flags,
+ creation_date_now);
+
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+ success = true;
+
+ // Show the preview panel for textures and sounds to let
+ // user know that the image (or snapshot) arrived intact.
+ LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel();
+ if (panel)
+ {
+ LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+
+ panel->setSelection(
+ server_response["new_inventory_item"].asUUID(),
+ TAKE_FOCUS_NO);
+
+ // restore keyboard focus
+ gFocusMgr.setKeyboardFocus(focus);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL;
+ }
+
+ // remove the "Uploading..." message
+ LLUploadDialog::modalUploadFinished();
+
+ // Let the Snapshot floater know we have finished uploading a snapshot to inventory.
+ LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
+ if (asset_type == LLAssetType::AT_TEXTURE && floater_snapshot)
+ {
+ floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory")));
+ }
+}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 688cd01a87..b33497730e 100755
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -38,6 +38,7 @@
#include "httpoptions.h"
#include "httpheaders.h"
#include "httphandler.h"
+#include "llthread.h"
#define LLCONVEXDECOMPINTER_STATIC 1
@@ -274,9 +275,9 @@ public:
// llcorehttp library interface objects.
LLCore::HttpStatus mHttpStatus;
LLCore::HttpRequest * mHttpRequest;
- LLCore::HttpOptions * mHttpOptions;
- LLCore::HttpOptions * mHttpLargeOptions;
- LLCore::HttpHeaders * mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpOptions::ptr_t mHttpLargeOptions;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
LLCore::HttpRequest::policy_t mHttpPolicyClass;
LLCore::HttpRequest::policy_t mHttpLegacyPolicyClass;
LLCore::HttpRequest::policy_t mHttpLargePolicyClass;
@@ -447,8 +448,8 @@ private:
// llcorehttp library interface objects.
LLCore::HttpStatus mHttpStatus;
LLCore::HttpRequest * mHttpRequest;
- LLCore::HttpOptions * mHttpOptions;
- LLCore::HttpHeaders * mHttpHeaders;
+ LLCore::HttpOptions::ptr_t mHttpOptions;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
LLCore::HttpRequest::policy_t mHttpPolicyClass;
LLCore::HttpRequest::priority_t mHttpPriority;
};
diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h
index 3e7f05b5e1..7a183cb298 100755
--- a/indra/newview/llnotificationhandler.h
+++ b/indra/newview/llnotificationhandler.h
@@ -277,22 +277,6 @@ protected:
virtual void initChannel() {};
};
-/**
- * Handler for outbox notifications
- */
-class LLOutboxNotification : public LLSystemNotificationHandler
-{
-public:
- LLOutboxNotification();
- virtual ~LLOutboxNotification() {};
- virtual void onChange(LLNotificationPtr p) { }
- virtual void onDelete(LLNotificationPtr p);
- virtual bool processNotification(const LLNotificationPtr& p);
-
-protected:
- virtual void initChannel() {};
-};
-
class LLHandlerUtil
{
public:
diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp
index 152581c5a0..a6f20a9f27 100755
--- a/indra/newview/llnotificationmanager.cpp
+++ b/indra/newview/llnotificationmanager.cpp
@@ -61,7 +61,6 @@ void LLNotificationManager::init()
mChannels.push_back(new LLOfferHandler());
mChannels.push_back(new LLHintHandler());
mChannels.push_back(new LLBrowserNotification());
- mChannels.push_back(new LLOutboxNotification());
mChannels.push_back(new LLIMHandler());
mChatHandler = boost::shared_ptr<LLFloaterIMNearbyChatHandler>(new LLFloaterIMNearbyChatHandler());
@@ -70,7 +69,7 @@ void LLNotificationManager::init()
//--------------------------------------------------------------------------
void LLNotificationManager::onChat(const LLChat& msg, const LLSD &args)
{
- if(mChatHandler)
- mChatHandler->processChat(msg, args);
- }
+ if(mChatHandler)
+ mChatHandler->processChat(msg, args);
+}
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index 878f1af9ef..5d1ae4ff10 100755
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -34,14 +34,12 @@
#include "lldispatcher.h"
#include "llfloaterreg.h"
-#include "llhttpclient.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llparcel.h"
#include "llagent.h"
#include "llclassifiedflags.h"
-#include "llclassifiedstatsresponder.h"
#include "llcommandhandler.h" // for classified HTML detail page click tracking
#include "lliconctrl.h"
#include "lllineeditor.h"
@@ -57,6 +55,7 @@
#include "llscrollcontainer.h"
#include "llstatusbar.h"
#include "llviewertexture.h"
+#include "llcorehttputil.h"
const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$
@@ -91,19 +90,6 @@ public:
};
static LLDispatchClassifiedClickThrough sClassifiedClickThrough;
-// Just to debug errors. Can be thrown away later.
-class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLClassifiedClickMessageResponder);
-
-protected:
- // If we get back an error (not found, etc...), handle it here
- virtual void httpFailure()
- {
- LL_WARNS() << "Sending click message failed " << dumpResponse() << LL_ENDL;
- }
-};
-
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@@ -229,8 +215,10 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key)
{
LL_INFOS() << "Classified stat request via capability" << LL_ENDL;
LLSD body;
- body["classified_id"] = getClassifiedId();
- LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(getClassifiedId()));
+ LLUUID classifiedId = getClassifiedId();
+ body["classified_id"] = classifiedId;
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body,
+ boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1));
}
// Update classified click stats.
@@ -240,6 +228,23 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key)
setInfoLoaded(false);
}
+/*static*/
+void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result)
+{
+ S32 teleport = result["teleport_clicks"].asInteger();
+ S32 map = result["map_clicks"].asInteger();
+ S32 profile = result["profile_clicks"].asInteger();
+ S32 search_teleport = result["search_teleport_clicks"].asInteger();
+ S32 search_map = result["search_map_clicks"].asInteger();
+ S32 search_profile = result["search_profile_clicks"].asInteger();
+
+ LLPanelClassifiedInfo::setClickThrough(classifiedId,
+ teleport + search_teleport,
+ map + search_map,
+ profile + search_profile,
+ true);
+}
+
void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type)
{
if(APT_CLASSIFIED_INFO == type)
@@ -548,7 +553,8 @@ void LLPanelClassifiedInfo::sendClickMessage(
std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");
LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL;
LL_INFOS() << "body: [" << body << "]" << LL_ENDL;
- LLHTTPClient::post(url, body, new LLClassifiedClickMessageResponder());
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+ "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent.");
}
void LLPanelClassifiedInfo::sendClickMessage(const std::string& type)
diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h
index cedd65c405..b292782615 100755
--- a/indra/newview/llpanelclassified.h
+++ b/indra/newview/llpanelclassified.h
@@ -37,6 +37,8 @@
#include "llrect.h"
#include "lluuid.h"
#include "v3dmath.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLScrollContainer;
class LLTextureCtrl;
@@ -193,6 +195,9 @@ private:
S32 mMapClicksNew;
S32 mProfileClicksNew;
+ static void handleSearchStatResponse(LLUUID classifiedId, LLSD result);
+
+
typedef std::list<LLPanelClassifiedInfo*> panel_list_t;
static panel_list_t sAllPanels;
};
diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp
index fc4ee9862e..9d52a1906b 100644
--- a/indra/newview/llpanelexperiencelisteditor.cpp
+++ b/indra/newview/llpanelexperiencelisteditor.cpp
@@ -183,7 +183,7 @@ void LLPanelExperienceListEditor::onItems()
columns[0]["value"] = getString("loading");
mItems->addElement(item);
- LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
+ LLExperienceCache::instance().get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
getDerivedHandle<LLPanelExperienceListEditor>(), _1));
}
diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp
index df03ef7526..d5979b6e96 100644
--- a/indra/newview/llpanelexperiencelog.cpp
+++ b/indra/newview/llpanelexperiencelog.cpp
@@ -140,7 +140,7 @@ void LLPanelExperienceLog::refresh()
}
const LLSD event = dayArray[i];
LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
- const LLSD& experience = LLExperienceCache::get(id);
+ const LLSD& experience = LLExperienceCache::instance().get(id);
if(experience.isUndefined()){
waiting = true;
waiting_id = id;
@@ -168,7 +168,7 @@ void LLPanelExperienceLog::refresh()
{
mEventList->deleteAllItems();
mEventList->setCommentText(getString("loading"));
- LLExperienceCache::get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
+ LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
}
else
{
diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp
index 70d826a407..dcc5f4f234 100644
--- a/indra/newview/llpanelexperiencepicker.cpp
+++ b/indra/newview/llpanelexperiencepicker.cpp
@@ -58,41 +58,6 @@ const static std::string columnSpace = " ";
static LLPanelInjector<LLPanelExperiencePicker> t_panel_status("llpanelexperiencepicker");
-class LLExperienceSearchResponder : public LLHTTPClient::Responder
-{
-public:
- LLUUID mQueryID;
- LLHandle<LLPanelExperiencePicker> mParent;
-
- LLExperienceSearchResponder(const LLUUID& id, const LLHandle<LLPanelExperiencePicker>& parent) : mQueryID(id), mParent(parent) { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- if(mParent.isDead())
- return;
-
- LLPanelExperiencePicker* panel =mParent.get();
- if (panel)
- {
- panel->processResponse(mQueryID, getContent());
- }
- }
-
- /*virtual*/ void httpFailure()
- {
- if(mParent.isDead())
- return;
-
- LLPanelExperiencePicker* panel =mParent.get();
- if (panel)
- {
- panel->processResponse(mQueryID, LLSD());
- }
- LL_WARNS() << "experience picker failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-};
-
LLPanelExperiencePicker::LLPanelExperiencePicker()
:LLPanel()
{
@@ -163,17 +128,11 @@ void LLPanelExperiencePicker::find()
{
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
mQueryID.generate();
- std::ostringstream url;
- LLViewerRegion* region = gAgent.getRegion();
- std::string cap = region->getCapability("FindExperienceByName");
- if (!cap.empty())
- {
- url << cap << "?page=" << mCurrentPage << "&page_size=30&query=" << LLURI::escape(text);
- LLHTTPClient::get(url.str(), new LLExperienceSearchResponder(mQueryID, getDerivedHandle<LLPanelExperiencePicker>()));
+ LLExperienceCache::instance().findExperienceByName(text, mCurrentPage,
+ boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle<LLPanelExperiencePicker>(), mQueryID, _1));
- }
- getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
getChildView(BTN_OK)->setEnabled(FALSE);
@@ -183,6 +142,19 @@ void LLPanelExperiencePicker::find()
getChildView(BTN_LEFT)->setEnabled(FALSE);
}
+/*static*/
+void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult)
+{
+ if (hparent.isDead())
+ return;
+
+ LLPanelExperiencePicker* panel = hparent.get();
+ if (panel)
+ {
+ panel->processResponse(queryId, foundResult);
+ }
+}
+
bool LLPanelExperiencePicker::isSelectButtonEnabled()
{
@@ -233,13 +205,6 @@ void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLS
mResponse = content;
- const LLSD& experiences=mResponse["experience_keys"];
- LLSD::array_const_iterator it = experiences.beginArray();
- for ( ; it != experiences.endArray(); ++it)
- {
- LLExperienceCache::insert(*it);
- }
-
getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url"));
getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url"));
diff --git a/indra/newview/llpanelexperiencepicker.h b/indra/newview/llpanelexperiencepicker.h
index e39ffed70b..97aa04cf4c 100644
--- a/indra/newview/llpanelexperiencepicker.h
+++ b/indra/newview/llpanelexperiencepicker.h
@@ -74,8 +74,9 @@ private:
void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids );
void setAllowMultiple(bool allow_multiple);
-
void find();
+ static void findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult);
+
bool isSelectButtonEnabled();
void processResponse( const LLUUID& query_id, const LLSD& content );
diff --git a/indra/newview/llpanelgroupexperiences.cpp b/indra/newview/llpanelgroupexperiences.cpp
index 76b68122fb..a88a55ab22 100644
--- a/indra/newview/llpanelgroupexperiences.cpp
+++ b/indra/newview/llpanelgroupexperiences.cpp
@@ -31,45 +31,16 @@
#include "lluictrlfactory.h"
#include "roles_constants.h"
-#include "llhttpclient.h"
#include "llagent.h"
#include "llviewerregion.h"
#include "llflatlistview.h"
#include "llpanelexperiences.h"
#include "llsd.h"
-
+#include "llexperiencecache.h"
static LLPanelInjector<LLPanelGroupExperiences> t_panel_group_experiences("panel_group_experiences");
-class LLGroupExperienceResponder : public LLHTTPClient::Responder
-{
-public:
- LLHandle<LLPanelGroupExperiences> mHandle;
-
- LLGroupExperienceResponder(LLHandle<LLPanelGroupExperiences> handle) : mHandle(handle) { }
-
-protected:
- /*virtual*/ void httpSuccess()
- {
- if (mHandle.isDead())
- {
- return;
- }
-
- LLPanelGroupExperiences* panel = mHandle.get();
- if (panel)
- {
- panel->setExperienceList(getContent().get("experience_ids"));
- }
- }
-
- /*virtual*/ void httpFailure()
- {
- LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-};
-
LLPanelGroupExperiences::LLPanelGroupExperiences()
: LLPanelGroupTab(), mExperiencesList(NULL)
{
@@ -101,14 +72,8 @@ void LLPanelGroupExperiences::activate()
return;
}
- // search for experiences owned by the current group
- std::string url = gAgent.getRegion()->getCapability("GroupExperiences");
- if (!url.empty())
- {
- url += "?" + getGroupID().asString();
-
- LLHTTPClient::get(url, new LLGroupExperienceResponder(getDerivedHandle<LLPanelGroupExperiences>()));
- }
+ LLExperienceCache::instance().getGroupExperiences(getGroupID(),
+ boost::bind(&LLPanelGroupExperiences::groupExperiencesResults, getDerivedHandle<LLPanelGroupExperiences>(), _1));
}
void LLPanelGroupExperiences::setGroupID(const LLUUID& id)
@@ -141,3 +106,19 @@ void LLPanelGroupExperiences::setExperienceList(const LLSD& experiences)
mExperiencesList->addItem(item, public_key);
}
}
+
+/*static*/
+void LLPanelGroupExperiences::groupExperiencesResults(LLHandle<LLPanelGroupExperiences> handle, const LLSD &experiences)
+{
+ if (handle.isDead())
+ {
+ return;
+ }
+
+ LLPanelGroupExperiences* panel = handle.get();
+ if (panel)
+ {
+ panel->setExperienceList(experiences);
+ }
+
+}
diff --git a/indra/newview/llpanelgroupexperiences.h b/indra/newview/llpanelgroupexperiences.h
index ae1ecc1ac5..7c79f77332 100644
--- a/indra/newview/llpanelgroupexperiences.h
+++ b/indra/newview/llpanelgroupexperiences.h
@@ -48,6 +48,9 @@ public:
protected:
LLFlatListView* mExperiencesList;
+
+private:
+ static void groupExperiencesResults(LLHandle<LLPanelGroupExperiences>, const LLSD &);
};
#endif
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index 1d73d4bd6e..cd1dc0f070 100755
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -1352,17 +1352,8 @@ void LLLandmarksPanel::doCreatePick(LLLandmark* landmark)
std::string url = region->getCapability("RemoteParcelRequest");
if (!url.empty())
{
- body["location"] = ll_sd_from_vector3(region_pos);
- if (!region_id.isNull())
- {
- body["region_id"] = region_id;
- }
- if (!pos_global.isExactlyZero())
- {
- U64 region_handle = to_region_handle(pos_global);
- body["region_handle"] = ll_sd_from_U64(region_handle);
- }
- LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
+ LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url,
+ region_id, region_pos, pos_global, getObserverHandle());
}
else
{
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 953f234a53..3743aee00f 100755
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -40,7 +40,6 @@
#include "llcheckboxctrl.h"
#include "llcommandhandler.h" // for secondlife:///app/login/
#include "llcombobox.h"
-#include "llcurl.h"
#include "llviewercontrol.h"
#include "llfloaterpreference.h"
#include "llfocusmgr.h"
@@ -59,7 +58,6 @@
#include "llviewernetwork.h"
#include "llviewerwindow.h" // to link into child list
#include "lluictrlfactory.h"
-#include "llhttpclient.h"
#include "llweb.h"
#include "llmediactrl.h"
#include "llrootview.h"
@@ -436,6 +434,12 @@ void LLPanelLogin::show(const LLRect &rect,
void (*callback)(S32 option, void* user_data),
void* callback_data)
{
+#if 0
+ if (!LLPanelLogin::sInstance)
+ {
+ new LLPanelLogin(rect, callback, callback_data);
+ }
+#else
// instance management
if (LLPanelLogin::sInstance)
{
@@ -447,6 +451,7 @@ void LLPanelLogin::show(const LLRect &rect,
}
new LLPanelLogin(rect, callback, callback_data);
+#endif
if( !gFocusMgr.getKeyboardFocus() )
{
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index cedd3025fc..55e4ffff5e 100755
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -37,7 +37,6 @@
#include "llfloaterreg.h"
#include "llhints.h"
#include "llviewercontrol.h"
-#include "llviewerdisplayname.h"
// Linden libraries
#include "llavatarnamecache.h" // IDEVO
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index e62b5a4f1d..cec56a7ae7 100755
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -45,6 +45,7 @@
#include "llpanelpick.h"
#include "lltexturectrl.h"
#include "llviewerregion.h"
+#include "llhttpconstants.h"
LLPanelPlaceInfo::LLPanelPlaceInfo()
: LLPanel(),
@@ -150,17 +151,8 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id,
std::string url = region->getCapability("RemoteParcelRequest");
if (!url.empty())
{
- body["location"] = ll_sd_from_vector3(mPosRegion);
- if (!region_id.isNull())
- {
- body["region_id"] = region_id;
- }
- if (!pos_global.isExactlyZero())
- {
- U64 region_handle = to_region_handle(pos_global);
- body["region_handle"] = ll_sd_from_U64(region_handle);
- }
- LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
+ LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url,
+ region_id, mPosRegion, pos_global, getObserverHandle());
}
else
{
diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp
index 8e37b1418c..e4f39aac04 100644
--- a/indra/newview/llpanelsnapshotpostcard.cpp
+++ b/indra/newview/llpanelsnapshotpostcard.cpp
@@ -40,6 +40,7 @@
#include "llpostcard.h"
#include "llviewercontrol.h" // gSavedSettings
#include "llviewerwindow.h"
+#include "llviewerregion.h"
#include <boost/regex.hpp>
@@ -67,7 +68,8 @@ private:
/*virtual*/ void updateControls(const LLSD& info);
bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response);
- void sendPostcard();
+ static void sendPostcardFinished(LLSD result);
+ void sendPostcard();
void onMsgFormFocusRecieved();
void onFormatComboCommit(LLUICtrl* ctrl);
@@ -166,24 +168,44 @@ bool LLPanelSnapshotPostcard::missingSubjMsgAlertCallback(const LLSD& notificati
}
-void LLPanelSnapshotPostcard::sendPostcard()
+void LLPanelSnapshotPostcard::sendPostcardFinished(LLSD result)
{
- std::string to(getChild<LLUICtrl>("to_form")->getValue().asString());
- std::string subject(getChild<LLUICtrl>("subject_form")->getValue().asString());
+ LL_WARNS() << result << LL_ENDL;
- LLSD postcard = LLSD::emptyMap();
- postcard["pos-global"] = LLFloaterSnapshot::getPosTakenGlobal().getValue();
- postcard["to"] = to;
- postcard["from"] = mAgentEmail;
- postcard["name"] = getChild<LLUICtrl>("name_form")->getValue().asString();
- postcard["subject"] = subject;
- postcard["msg"] = getChild<LLUICtrl>("msg_form")->getValue().asString();
- LLPostCard::send(LLFloaterSnapshot::getImageData(), postcard);
+ std::string state = result["state"].asString();
- // Give user feedback of the event.
- gViewerWindow->playSnapshotAnimAndSound();
+ LLPostCard::reportPostResult((state == "complete"));
+}
- LLFloaterSnapshot::postSave();
+
+void LLPanelSnapshotPostcard::sendPostcard()
+{
+ // upload the image
+ std::string url = gAgent.getRegion()->getCapability("SendPostcard");
+ if (!url.empty())
+ {
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLPostcardUploadInfo(
+ mAgentEmail,
+ getChild<LLUICtrl>("name_form")->getValue().asString(),
+ getChild<LLUICtrl>("to_form")->getValue().asString(),
+ getChild<LLUICtrl>("subject_form")->getValue().asString(),
+ getChild<LLUICtrl>("msg_form")->getValue().asString(),
+ LLFloaterSnapshot::getPosTakenGlobal(),
+ LLFloaterSnapshot::getImageData(),
+ boost::bind(&LLPanelSnapshotPostcard::sendPostcardFinished, _4)));
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+ else
+ {
+ LL_WARNS() << "Postcards unavailable in this region." << LL_ENDL;
+ }
+
+
+ // Give user feedback of the event.
+ gViewerWindow->playSnapshotAnimAndSound();
+
+ LLFloaterSnapshot::postSave();
}
void LLPanelSnapshotPostcard::onMsgFormFocusRecieved()
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp
index 4977a72dc6..711a869e82 100755
--- a/indra/newview/llpathfindingmanager.cpp
+++ b/indra/newview/llpathfindingmanager.cpp
@@ -39,7 +39,6 @@
#include <boost/signals2.hpp>
#include "llagent.h"
-#include "llhttpclient.h"
#include "llhttpnode.h"
#include "llnotificationsutil.h"
#include "llpathfindingcharacterlist.h"
@@ -55,6 +54,8 @@
#include "lluuid.h"
#include "llviewerregion.h"
#include "llweb.h"
+#include "llcorehttputil.h"
+#include "llworld.h"
#define CAP_SERVICE_RETRIEVE_NAVMESH "RetrieveNavMeshSrc"
@@ -98,82 +99,6 @@ public:
LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode(SIM_MESSAGE_AGENT_STATE_UPDATE);
//---------------------------------------------------------------------------
-// NavMeshStatusResponder
-//---------------------------------------------------------------------------
-
-class NavMeshStatusResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(NavMeshStatusResponder);
-public:
- NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly);
- virtual ~NavMeshStatusResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-private:
- LLViewerRegion *mRegion;
- LLUUID mRegionUUID;
- bool mIsGetStatusOnly;
-};
-
-//---------------------------------------------------------------------------
-// NavMeshResponder
-//---------------------------------------------------------------------------
-
-class NavMeshResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(NavMeshResponder);
-public:
- NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr);
- virtual ~NavMeshResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-private:
- U32 mNavMeshVersion;
- LLPathfindingNavMeshPtr mNavMeshPtr;
-};
-
-//---------------------------------------------------------------------------
-// AgentStateResponder
-//---------------------------------------------------------------------------
-
-class AgentStateResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(AgentStateResponder);
-public:
- AgentStateResponder();
- virtual ~AgentStateResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-};
-
-
-//---------------------------------------------------------------------------
-// NavMeshRebakeResponder
-//---------------------------------------------------------------------------
-class NavMeshRebakeResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(NavMeshRebakeResponder);
-public:
- NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback);
- virtual ~NavMeshRebakeResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-private:
- LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback;
-};
-
-//---------------------------------------------------------------------------
// LinksetsResponder
//---------------------------------------------------------------------------
@@ -188,6 +113,8 @@ public:
void handleTerrainLinksetsResult(const LLSD &pContent);
void handleTerrainLinksetsError();
+ typedef boost::shared_ptr<LinksetsResponder> ptr_t;
+
protected:
private:
@@ -214,64 +141,6 @@ private:
typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;
//---------------------------------------------------------------------------
-// ObjectLinksetsResponder
-//---------------------------------------------------------------------------
-
-class ObjectLinksetsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(ObjectLinksetsResponder);
-public:
- ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);
- virtual ~ObjectLinksetsResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-private:
- LinksetsResponderPtr mLinksetsResponsderPtr;
-};
-
-//---------------------------------------------------------------------------
-// TerrainLinksetsResponder
-//---------------------------------------------------------------------------
-
-class TerrainLinksetsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(TerrainLinksetsResponder);
-public:
- TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr);
- virtual ~TerrainLinksetsResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-private:
- LinksetsResponderPtr mLinksetsResponsderPtr;
-};
-
-//---------------------------------------------------------------------------
-// CharactersResponder
-//---------------------------------------------------------------------------
-
-class CharactersResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(TerrainLinksetsResponder);
-public:
- CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback);
- virtual ~CharactersResponder();
-
-protected:
- virtual void httpSuccess();
- virtual void httpFailure();
-
-private:
- LLPathfindingManager::request_id_t mRequestId;
- LLPathfindingManager::object_request_callback_t mCharactersCallback;
-};
-
-//---------------------------------------------------------------------------
// LLPathfindingManager
//---------------------------------------------------------------------------
@@ -350,11 +219,13 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b
}
else
{
- std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion);
- llassert(!navMeshStatusURL.empty());
- navMeshPtr->handleNavMeshCheckVersion();
- LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly);
- LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder);
+ std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion);
+ llassert(!navMeshStatusURL.empty());
+ navMeshPtr->handleNavMeshCheckVersion();
+
+ U64 regionHandle = pRegion->getHandle();
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navMeshStatusRequestCoro",
+ boost::bind(&LLPathfindingManager::navMeshStatusRequestCoro, this, navMeshStatusURL, regionHandle, pIsGetStatusOnly));
}
}
@@ -385,15 +256,15 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re
pLinksetsCallback(pRequestId, kRequestStarted, emptyLinksetListPtr);
bool doRequestTerrain = isAllowViewTerrainProperties();
- LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain));
+ LinksetsResponder::ptr_t linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain));
- LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);
- LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder);
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetObjectsCoro",
+ boost::bind(&LLPathfindingManager::linksetObjectsCoro, this, objectLinksetsURL, linksetsResponderPtr, LLSD()));
- if (doRequestTerrain)
+ if (doRequestTerrain)
{
- LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);
- LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder);
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetTerrainCoro",
+ boost::bind(&LLPathfindingManager::linksetTerrainCoro, this, terrainLinksetsURL, linksetsResponderPtr, LLSD()));
}
}
}
@@ -432,18 +303,18 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP
{
pLinksetsCallback(pRequestId, kRequestStarted, emptyLinksetListPtr);
- LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined()));
+ LinksetsResponder::ptr_t linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined()));
if (!objectPostData.isUndefined())
{
- LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr);
- LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder);
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetObjectsCoro",
+ boost::bind(&LLPathfindingManager::linksetObjectsCoro, this, objectLinksetsURL, linksetsResponderPtr, objectPostData));
}
if (!terrainPostData.isUndefined())
{
- LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr);
- LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder);
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetTerrainCoro",
+ boost::bind(&LLPathfindingManager::linksetTerrainCoro, this, terrainLinksetsURL, linksetsResponderPtr, terrainPostData));
}
}
}
@@ -475,8 +346,8 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_
{
pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr);
- LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback);
- LLHTTPClient::get(charactersURL, charactersResponder);
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::charactersCoro",
+ boost::bind(&LLPathfindingManager::charactersCoro, this, charactersURL, pRequestId, pCharactersCallback));
}
}
}
@@ -508,8 +379,9 @@ void LLPathfindingManager::requestGetAgentState()
{
std::string agentStateURL = getAgentStateURLForRegion(currentRegion);
llassert(!agentStateURL.empty());
- LLHTTPClient::ResponderPtr responder = new AgentStateResponder();
- LLHTTPClient::get(agentStateURL, responder);
+
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navAgentStateRequestCoro",
+ boost::bind(&LLPathfindingManager::navAgentStateRequestCoro, this, agentStateURL));
}
}
}
@@ -530,35 +402,9 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak
{
std::string navMeshStatusURL = getNavMeshStatusURLForCurrentRegion();
llassert(!navMeshStatusURL.empty());
- LLSD postData;
- postData["command"] = "rebuild";
- LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback);
- LLHTTPClient::post(navMeshStatusURL, postData, responder);
- }
-}
-
-void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, const LLPathfindingNavMeshStatus &pNavMeshStatus)
-{
- if ((pRegion == NULL) || !pRegion->isAlive())
- {
- navMeshPtr->handleNavMeshNotEnabled();
- }
- else
- {
- std::string navMeshURL = getRetrieveNavMeshURLForRegion(pRegion);
-
- if (navMeshURL.empty())
- {
- navMeshPtr->handleNavMeshNotEnabled();
- }
- else
- {
- navMeshPtr->handleNavMeshStart(pNavMeshStatus);
- LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr);
- LLSD postData;
- LLHTTPClient::post(navMeshURL, postData, responder);
- }
+ std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navMeshRebakeCoro",
+ boost::bind(&LLPathfindingManager::navMeshRebakeCoro, this, navMeshStatusURL, pRebakeNavMeshCallback));
}
}
@@ -602,29 +448,250 @@ void LLPathfindingManager::handleDeferredGetCharactersForRegion(const LLUUID &pR
}
}
-void LLPathfindingManager::handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly)
+void LLPathfindingManager::navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly)
{
- LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pNavMeshStatus.getRegionUUID());
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavMeshStatusRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLViewerRegion *region = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!region)
+ {
+ LL_WARNS("PathfindingManager") << "Attempting to retrieve navmesh status for region that has gone away." << LL_ENDL;
+ return;
+ }
+ LLUUID regionUUID = region->getRegionID();
+
+ region = NULL;
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ region = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
- if (!pNavMeshStatus.isValid())
- {
- navMeshPtr->handleNavMeshError();
- }
- else
- {
- if (navMeshPtr->hasNavMeshVersion(pNavMeshStatus))
- {
- navMeshPtr->handleRefresh(pNavMeshStatus);
- }
- else if (pIsGetStatusOnly)
- {
- navMeshPtr->handleNavMeshNewVersion(pNavMeshStatus);
- }
- else
- {
- sendRequestGetNavMeshForRegion(navMeshPtr, pRegion, pNavMeshStatus);
- }
- }
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ LLPathfindingNavMeshStatus navMeshStatus(regionUUID);
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". Building using empty status." << LL_ENDL;
+ }
+ else
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ navMeshStatus = LLPathfindingNavMeshStatus(regionUUID, result);
+ }
+
+ LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(regionUUID);
+
+ if (!navMeshStatus.isValid())
+ {
+ navMeshPtr->handleNavMeshError();
+ return;
+ }
+ else if (navMeshPtr->hasNavMeshVersion(navMeshStatus))
+ {
+ navMeshPtr->handleRefresh(navMeshStatus);
+ return;
+ }
+ else if (isGetStatusOnly)
+ {
+ navMeshPtr->handleNavMeshNewVersion(navMeshStatus);
+ return;
+ }
+
+ if ((!region) || !region->isAlive())
+ {
+ LL_WARNS("PathfindingManager") << "About to update navmesh status for region that has gone away." << LL_ENDL;
+ navMeshPtr->handleNavMeshNotEnabled();
+ return;
+ }
+
+ std::string navMeshURL = getRetrieveNavMeshURLForRegion(region);
+
+ if (navMeshURL.empty())
+ {
+ navMeshPtr->handleNavMeshNotEnabled();
+ return;
+ }
+
+ navMeshPtr->handleNavMeshStart(navMeshStatus);
+
+ LLSD postData;
+ result = httpAdapter->postAndSuspend(httpRequest, navMeshURL, postData);
+
+ U32 navMeshVersion = navMeshStatus.getVersion();
+
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". reporting error." << LL_ENDL;
+ navMeshPtr->handleNavMeshError(navMeshVersion);
+ }
+ else
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ navMeshPtr->handleNavMeshResult(result, navMeshVersion);
+
+ }
+
+}
+
+void LLPathfindingManager::navAgentStateRequestCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavAgentStateRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ bool canRebake = false;
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". Building using empty status." << LL_ENDL;
+ }
+ else
+ {
+ llassert(result.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD));
+ llassert(result.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean());
+ canRebake = result.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean();
+ }
+
+ handleAgentState(canRebake);
+}
+
+void LLPathfindingManager::navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavMeshRebake", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+
+ LLSD postData = LLSD::emptyMap();
+ postData["command"] = "rebuild";
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ bool success = true;
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". Rebake failed." << LL_ENDL;
+ success = false;
+ }
+
+ rebakeNavMeshCallback(success);
+}
+
+// If called with putData undefined this coroutine will issue a get. If there
+// is data in putData it will be PUT to the URL.
+void LLPathfindingManager::linksetObjectsCoro(std::string url, LinksetsResponder::ptr_t linksetsResponsderPtr, LLSD putData) const
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetObjects", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result;
+
+ if (putData.isUndefined())
+ {
+ result = httpAdapter->getAndSuspend(httpRequest, url);
+ }
+ else
+ {
+ result = httpAdapter->putAndSuspend(httpRequest, url, putData);
+ }
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". linksetObjects failed." << LL_ENDL;
+ linksetsResponsderPtr->handleObjectLinksetsError();
+ }
+ else
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ linksetsResponsderPtr->handleObjectLinksetsResult(result);
+ }
+}
+
+// If called with putData undefined this coroutine will issue a GET. If there
+// is data in putData it will be PUT to the URL.
+void LLPathfindingManager::linksetTerrainCoro(std::string url, LinksetsResponder::ptr_t linksetsResponsderPtr, LLSD putData) const
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result;
+
+ if (putData.isUndefined())
+ {
+ result = httpAdapter->getAndSuspend(httpRequest, url);
+ }
+ else
+ {
+ result = httpAdapter->putAndSuspend(httpRequest, url, putData);
+ }
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". linksetTerrain failed." << LL_ENDL;
+ linksetsResponsderPtr->handleTerrainLinksetsError();
+ }
+ else
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ linksetsResponsderPtr->handleTerrainLinksetsResult(result);
+ }
+
+}
+
+void LLPathfindingManager::charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<
+ ". characters failed." << LL_ENDL;
+
+ LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList());
+ callback(requestId, LLPathfindingManager::kRequestError, characterListPtr);
+ }
+ else
+ {
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(result));
+ callback(requestId, LLPathfindingManager::kRequestCompleted, characterListPtr);
+ }
}
void LLPathfindingManager::handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus)
@@ -765,121 +832,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c
}
//---------------------------------------------------------------------------
-// NavMeshStatusResponder
-//---------------------------------------------------------------------------
-
-NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly)
- : LLHTTPClient::Responder(),
- mRegion(pRegion),
- mRegionUUID(),
- mIsGetStatusOnly(pIsGetStatusOnly)
-{
- if (mRegion != NULL)
- {
- mRegionUUID = mRegion->getRegionID();
- }
-}
-
-NavMeshStatusResponder::~NavMeshStatusResponder()
-{
-}
-
-void NavMeshStatusResponder::httpSuccess()
-{
- LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent());
- LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);
-}
-
-void NavMeshStatusResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID);
- LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly);
-}
-
-//---------------------------------------------------------------------------
-// NavMeshResponder
-//---------------------------------------------------------------------------
-
-NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr)
- : LLHTTPClient::Responder(),
- mNavMeshVersion(pNavMeshVersion),
- mNavMeshPtr(pNavMeshPtr)
-{
-}
-
-NavMeshResponder::~NavMeshResponder()
-{
-}
-
-void NavMeshResponder::httpSuccess()
-{
- mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion);
-}
-
-void NavMeshResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- mNavMeshPtr->handleNavMeshError(mNavMeshVersion);
-}
-
-//---------------------------------------------------------------------------
-// AgentStateResponder
-//---------------------------------------------------------------------------
-
-AgentStateResponder::AgentStateResponder()
-: LLHTTPClient::Responder()
-{
-}
-
-AgentStateResponder::~AgentStateResponder()
-{
-}
-
-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::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- LLPathfindingManager::getInstance()->handleAgentState(FALSE);
-}
-
-
-//---------------------------------------------------------------------------
-// navmesh rebake responder
-//---------------------------------------------------------------------------
-NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback)
- : LLHTTPClient::Responder(),
- mRebakeNavMeshCallback(pRebakeNavMeshCallback)
-{
-}
-
-NavMeshRebakeResponder::~NavMeshRebakeResponder()
-{
-}
-
-void NavMeshRebakeResponder::httpSuccess()
-{
- mRebakeNavMeshCallback(true);
-}
-
-void NavMeshRebakeResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- mRebakeNavMeshCallback(false);
-}
-
-//---------------------------------------------------------------------------
// LinksetsResponder
//---------------------------------------------------------------------------
-
LinksetsResponder::LinksetsResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested)
: mRequestId(pRequestId),
mLinksetsCallback(pLinksetsCallback),
@@ -957,82 +911,3 @@ void LinksetsResponder::sendCallback()
mLinksetsCallback(mRequestId, requestStatus, mObjectLinksetListPtr);
}
-
-//---------------------------------------------------------------------------
-// ObjectLinksetsResponder
-//---------------------------------------------------------------------------
-
-ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)
- : LLHTTPClient::Responder(),
- mLinksetsResponsderPtr(pLinksetsResponsderPtr)
-{
-}
-
-ObjectLinksetsResponder::~ObjectLinksetsResponder()
-{
-}
-
-void ObjectLinksetsResponder::httpSuccess()
-{
- mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent());
-}
-
-void ObjectLinksetsResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- mLinksetsResponsderPtr->handleObjectLinksetsError();
-}
-
-//---------------------------------------------------------------------------
-// TerrainLinksetsResponder
-//---------------------------------------------------------------------------
-
-TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)
- : LLHTTPClient::Responder(),
- mLinksetsResponsderPtr(pLinksetsResponsderPtr)
-{
-}
-
-TerrainLinksetsResponder::~TerrainLinksetsResponder()
-{
-}
-
-void TerrainLinksetsResponder::httpSuccess()
-{
- mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent());
-}
-
-void TerrainLinksetsResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
- mLinksetsResponsderPtr->handleTerrainLinksetsError();
-}
-
-//---------------------------------------------------------------------------
-// CharactersResponder
-//---------------------------------------------------------------------------
-
-CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback)
- : LLHTTPClient::Responder(),
- mRequestId(pRequestId),
- mCharactersCallback(pCharactersCallback)
-{
-}
-
-CharactersResponder::~CharactersResponder()
-{
-}
-
-void CharactersResponder::httpSuccess()
-{
- LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent()));
- mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr);
-}
-
-void CharactersResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList());
- mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr);
-}
diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h
index c61ff244fc..e8fad590ba 100755
--- a/indra/newview/llpathfindingmanager.h
+++ b/indra/newview/llpathfindingmanager.h
@@ -37,11 +37,15 @@
#include "llpathfindingobjectlist.h"
#include "llpathfindingnavmesh.h"
#include "llsingleton.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLPathfindingNavMeshStatus;
class LLUUID;
class LLViewerRegion;
+class LinksetsResponder;
+
class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
{
friend class LLNavMeshSimStateChangeNode;
@@ -92,16 +96,22 @@ public:
protected:
private:
- typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap;
- void sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, const LLPathfindingNavMeshStatus &pNavMeshStatus);
+ typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap;
void handleDeferredGetAgentStateForRegion(const LLUUID &pRegionUUID);
void handleDeferredGetNavMeshForRegion(const LLUUID &pRegionUUID, bool pIsGetStatusOnly);
void handleDeferredGetLinksetsForRegion(const LLUUID &pRegionUUID, request_id_t pRequestId, object_request_callback_t pLinksetsCallback) const;
void handleDeferredGetCharactersForRegion(const LLUUID &pRegionUUID, request_id_t pRequestId, object_request_callback_t pCharactersCallback) const;
- void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly);
+ void navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly);
+ void navAgentStateRequestCoro(std::string url);
+ void navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback);
+ void linksetObjectsCoro(std::string url, boost::shared_ptr<LinksetsResponder> linksetsResponsderPtr, LLSD putData) const;
+ void linksetTerrainCoro(std::string url, boost::shared_ptr<LinksetsResponder> linksetsResponsderPtr, LLSD putData) const;
+ void charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const;
+
+ //void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly);
void handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus);
void handleAgentState(BOOL pCanRebakeRegion);
diff --git a/indra/newview/llpostcard.cpp b/indra/newview/llpostcard.cpp
index 5987044bff..2e639b56eb 100755
--- a/indra/newview/llpostcard.cpp
+++ b/indra/newview/llpostcard.cpp
@@ -36,84 +36,36 @@
#include "llagent.h"
#include "llassetstorage.h"
-#include "llassetuploadresponders.h"
+#include "llviewerassetupload.h"
///////////////////////////////////////////////////////////////////////////////
-// misc
-static void postcard_upload_callback(const LLUUID& asset_id, void *user_data, S32 result, LLExtStat ext_status)
+LLPostcardUploadInfo::LLPostcardUploadInfo(std::string emailFrom, std::string nameFrom, std::string emailTo,
+ std::string subject, std::string message, LLVector3d globalPosition,
+ LLPointer<LLImageFormatted> image, invnUploadFinish_f finish) :
+ LLBufferedAssetUploadInfo(LLUUID::null, image, finish),
+ mEmailFrom(emailFrom),
+ mNameFrom(nameFrom),
+ mEmailTo(emailTo),
+ mSubject(subject),
+ mMessage(message),
+ mGlobalPosition(globalPosition)
{
- LLSD* postcard_data = (LLSD*)user_data;
-
- if (result)
- {
- // TODO: display the error messages in UI
- LL_WARNS() << "Failed to send postcard: " << LLAssetStorage::getErrorString(result) << LL_ENDL;
- LLPostCard::reportPostResult(false);
- }
- else
- {
- // only create the postcard once the upload succeeds
-
- // request the postcard
- const LLSD& data = *postcard_data;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("SendPostcard");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->addUUID("AssetID", data["asset-id"].asUUID());
- msg->addVector3d("PosGlobal", LLVector3d(data["pos-global"]));
- msg->addString("To", data["to"]);
- msg->addString("From", data["from"]);
- msg->addString("Name", data["name"]);
- msg->addString("Subject", data["subject"]);
- msg->addString("Msg", data["msg"]);
- msg->addBOOL("AllowPublish", FALSE);
- msg->addBOOL("MaturePublish", FALSE);
- gAgent.sendReliableMessage();
-
- LLPostCard::reportPostResult(true);
- }
-
- delete postcard_data;
}
-
-///////////////////////////////////////////////////////////////////////////////
-// LLPostcardSendResponder
-
-class LLPostcardSendResponder : public LLAssetUploadResponder
+LLSD LLPostcardUploadInfo::generatePostBody()
{
- LOG_CLASS(LLPostcardSendResponder);
-
-public:
- LLPostcardSendResponder(const LLSD &post_data,
- const LLUUID& vfile_id,
- LLAssetType::EType asset_type):
- LLAssetUploadResponder(post_data, vfile_id, asset_type)
- {
- }
-
- /*virtual*/ void httpFailure()
- {
- LL_WARNS() << "Sending postcard failed, status: " << getStatus() << LL_ENDL;
- LLPostCard::reportPostResult(false);
- }
-
- /*virtual*/ void uploadComplete(const LLSD& content)
- {
- LL_INFOS() << "Postcard sent" << LL_ENDL;
- LL_DEBUGS("Snapshots") << "content: " << content << LL_ENDL;
- LLPostCard::reportPostResult(true);
- }
+ LLSD postcard = LLSD::emptyMap();
+ postcard["pos-global"] = mGlobalPosition.getValue();
+ postcard["to"] = mEmailTo;
+ postcard["from"] = mEmailFrom;
+ postcard["name"] = mNameFrom;
+ postcard["subject"] = mSubject;
+ postcard["msg"] = mMessage;
+
+ return postcard;
+}
- /*virtual*/ void uploadFailure(const LLSD& content)
- {
- LL_WARNS() << "Sending postcard failed: " << content << LL_ENDL;
- LLPostCard::reportPostResult(false);
- }
-};
///////////////////////////////////////////////////////////////////////////////
// LLPostCard
@@ -121,38 +73,6 @@ public:
LLPostCard::result_callback_t LLPostCard::mResultCallback;
// static
-void LLPostCard::send(LLPointer<LLImageFormatted> image, const LLSD& postcard_data)
-{
- LLTransactionID transaction_id;
- LLAssetID asset_id;
-
- transaction_id.generate();
- asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID());
- LLVFile::writeFile(image->getData(), image->getDataSize(), gVFS, asset_id, LLAssetType::AT_IMAGE_JPEG);
-
- // upload the image
- std::string url = gAgent.getRegion()->getCapability("SendPostcard");
- if (!url.empty())
- {
- LL_INFOS() << "Sending postcard via capability" << LL_ENDL;
- // the capability already encodes: agent ID, region ID
- LL_DEBUGS("Snapshots") << "url: " << url << LL_ENDL;
- LL_DEBUGS("Snapshots") << "body: " << postcard_data << LL_ENDL;
- LL_DEBUGS("Snapshots") << "data size: " << image->getDataSize() << LL_ENDL;
- LLHTTPClient::post(url, postcard_data,
- new LLPostcardSendResponder(postcard_data, asset_id, LLAssetType::AT_IMAGE_JPEG));
- }
- else
- {
- LL_INFOS() << "Sending postcard" << LL_ENDL;
- LLSD* data = new LLSD(postcard_data);
- (*data)["asset-id"] = asset_id;
- gAssetStorage->storeAssetData(transaction_id, LLAssetType::AT_IMAGE_JPEG,
- &postcard_upload_callback, (void *)data, FALSE);
- }
-}
-
-// static
void LLPostCard::reportPostResult(bool ok)
{
if (mResultCallback)
diff --git a/indra/newview/llpostcard.h b/indra/newview/llpostcard.h
index 0eb118b906..24157be636 100755
--- a/indra/newview/llpostcard.h
+++ b/indra/newview/llpostcard.h
@@ -29,7 +29,12 @@
#include "llimage.h"
#include "lluuid.h"
+#include "llviewerassetupload.h"
+/// *TODO$: this LLPostCard class is a hold over and should be removed. Right now
+/// all it does is hold a pointer to a call back function which is invoked by
+/// llpanelsnapshotpostcard's finish function. (and all that call back does is
+/// set the status in the floater.
class LLPostCard
{
LOG_CLASS(LLPostCard);
@@ -37,7 +42,6 @@ class LLPostCard
public:
typedef boost::function<void(bool ok)> result_callback_t;
- static void send(LLPointer<LLImageFormatted> image, const LLSD& postcard_data);
static void setPostResultCallback(result_callback_t cb) { mResultCallback = cb; }
static void reportPostResult(bool ok);
@@ -45,4 +49,24 @@ private:
static result_callback_t mResultCallback;
};
+
+class LLPostcardUploadInfo : public LLBufferedAssetUploadInfo
+{
+public:
+ LLPostcardUploadInfo(std::string emailFrom, std::string nameFrom, std::string emailTo,
+ std::string subject, std::string message, LLVector3d globalPosition,
+ LLPointer<LLImageFormatted> image, invnUploadFinish_f finish);
+
+ virtual LLSD generatePostBody();
+private:
+ std::string mEmailFrom;
+ std::string mNameFrom;
+ std::string mEmailTo;
+ std::string mSubject;
+ std::string mMessage;
+ LLVector3d mGlobalPosition;
+
+};
+
+
#endif // LL_LLPOSTCARD_H
diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp
index c378738b05..ff9a70d05c 100755
--- a/indra/newview/llpreviewgesture.cpp
+++ b/indra/newview/llpreviewgesture.cpp
@@ -31,7 +31,6 @@
#include "llanimstatelabels.h"
#include "llanimationstates.h"
#include "llappviewer.h" // gVFS
-#include "llassetuploadresponders.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "lldatapacker.h"
@@ -52,6 +51,7 @@
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
+#include "llviewerassetupload.h"
std::string NONE_LABEL;
std::string SHIFT_LABEL;
@@ -1015,6 +1015,27 @@ struct LLSaveInfo
};
+void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId)
+{
+ // If this gesture is active, then we need to update the in-memory
+ // active map with the new pointer.
+ if (LLGestureMgr::instance().isGestureActive(itemId))
+ {
+ //*TODO: This is crashing for some reason. Fix it.
+ // Active gesture edited from menu.
+ LLGestureMgr::instance().replaceGesture(itemId, newAssetId);
+ gInventory.notifyObservers();
+ }
+
+ //gesture will have a new asset_id
+ LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(itemId));
+ if (previewp)
+ {
+ previewp->onUpdateSucceeded();
+ }
+}
+
+
void LLPreviewGesture::saveIfNeeded()
{
if (!gAssetStorage)
@@ -1028,116 +1049,127 @@ void LLPreviewGesture::saveIfNeeded()
return;
}
- // Copy the UI into a gesture
- LLMultiGesture* gesture = createGesture();
-
- // Serialize the gesture
- S32 max_size = gesture->getMaxSerialSize();
- char* buffer = new char[max_size];
-
- LLDataPackerAsciiBuffer dp(buffer, max_size);
-
- BOOL ok = gesture->serialize(dp);
-
- if (dp.getCurrentSize() > 1000)
- {
- LLNotificationsUtil::add("GestureSaveFailedTooManySteps");
-
- delete gesture;
- gesture = NULL;
- }
- else if (!ok)
- {
- LLNotificationsUtil::add("GestureSaveFailedTryAgain");
- delete gesture;
- gesture = NULL;
- }
- else
- {
- LLPreview::onCommit();
-
- // Every save gets a new UUID. Yup.
- LLTransactionID tid;
- LLAssetID asset_id;
- tid.generate();
- asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
-
- LLVFile file(gVFS, asset_id, LLAssetType::AT_GESTURE, LLVFile::APPEND);
-
- S32 size = dp.getCurrentSize();
- file.setMaxSize(size);
- file.write((U8*)buffer, size);
-
- BOOL delayedUpload = FALSE;
-
- // Upload that asset to the database
- LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
- if (item)
- {
- std::string agent_url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory");
- std::string task_url = gAgent.getRegion()->getCapability("UpdateGestureTaskInventory");
- if (mObjectUUID.isNull() && !agent_url.empty())
- {
- //need to disable the preview floater so item
- //isn't re-saved before new asset arrives
- //fake out refresh.
- item->setComplete(FALSE);
- refresh();
- item->setComplete(TRUE);
-
- // Saving into agent inventory
- LLSD body;
- body["item_id"] = mItemUUID;
- LLHTTPClient::post(agent_url, body,
- new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE));
- delayedUpload = TRUE;
- }
- else if (!mObjectUUID.isNull() && !task_url.empty())
- {
- // Saving into task inventory
- LLSD body;
- body["task_id"] = mObjectUUID;
- body["item_id"] = mItemUUID;
- LLHTTPClient::post(task_url, body,
- new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE));
- }
- else if (gAssetStorage)
- {
- LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
- LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
- gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, FALSE);
- }
- }
-
- // If this gesture is active, then we need to update the in-memory
- // active map with the new pointer.
- if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID))
- {
- // gesture manager now owns the pointer
- LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, asset_id);
-
- // replaceGesture may deactivate other gestures so let the
- // inventory know.
- gInventory.notifyObservers();
- }
- else
- {
- // we're done with this gesture
- delete gesture;
- gesture = NULL;
- }
-
- mDirty = FALSE;
- // refresh will be called when callback
- // if triggered when delayedUpload
- if(!delayedUpload)
- {
- refresh();
- }
- }
+ // Copy the UI into a gesture
+ LLMultiGesture* gesture = createGesture();
+
+ // Serialize the gesture
+ S32 maxSize = gesture->getMaxSerialSize();
+ char* buffer = new char[maxSize];
+
+ LLDataPackerAsciiBuffer dp(buffer, maxSize);
+
+ bool ok = gesture->serialize(dp);
+
+ if (dp.getCurrentSize() > 1000)
+ {
+ LLNotificationsUtil::add("GestureSaveFailedTooManySteps");
+
+ delete gesture;
+ gesture = NULL;
+ return;
+ }
+ else if (!ok)
+ {
+ LLNotificationsUtil::add("GestureSaveFailedTryAgain");
+ delete gesture;
+ gesture = NULL;
+ return;
+ }
+
+ LLAssetID assetId;
+ LLPreview::onCommit();
+ bool delayedUpload(false);
+
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem();
+ if (item)
+ {
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL;
+ return;
+ }
+ std::string agent_url = region->getCapability("UpdateGestureAgentInventory");
+ std::string task_url = region->getCapability("UpdateGestureTaskInventory");
+
+ if (!agent_url.empty() && !task_url.empty())
+ {
+ std::string url;
+ LLResourceUploadInfo::ptr_t uploadInfo;
+
+ if (mObjectUUID.isNull() && !agent_url.empty())
+ {
+ //need to disable the preview floater so item
+ //isn't re-saved before new asset arrives
+ //fake out refresh.
+ item->setComplete(false);
+ refresh();
+ item->setComplete(true);
+
+ uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mItemUUID, LLAssetType::AT_GESTURE, buffer,
+ boost::bind(&LLPreviewGesture::finishInventoryUpload, _1, _2)));
+ url = agent_url;
+ }
+ else if (!mObjectUUID.isNull() && !task_url.empty())
+ {
+ uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, NULL));
+ url = task_url;
+ }
+
+ if (!url.empty() && uploadInfo)
+ {
+ delayedUpload = true;
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+
+ }
+ else if (gAssetStorage)
+ {
+ // Every save gets a new UUID. Yup.
+ LLTransactionID tid;
+ tid.generate();
+ assetId = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ LLVFile file(gVFS, assetId, LLAssetType::AT_GESTURE, LLVFile::APPEND);
+
+ S32 size = dp.getCurrentSize();
+ file.setMaxSize(size);
+ file.write((U8*)buffer, size);
+
+ LLLineEditor* descEditor = getChild<LLLineEditor>("desc");
+ LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid);
+ gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, FALSE);
+ }
+
+ }
+
+ // If this gesture is active, then we need to update the in-memory
+ // active map with the new pointer.
+ if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID))
+ {
+ // gesture manager now owns the pointer
+ LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, assetId);
+
+ // replaceGesture may deactivate other gestures so let the
+ // inventory know.
+ gInventory.notifyObservers();
+ }
+ else
+ {
+ // we're done with this gesture
+ delete gesture;
+ gesture = NULL;
+ }
+
+ mDirty = false;
+ // refresh will be called when callback
+ // if triggered when delayedUpload
+ if(!delayedUpload)
+ {
+ refresh();
+ }
- delete [] buffer;
- buffer = NULL;
}
diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h
index 7ce5706a0d..3ba4f56295 100755
--- a/indra/newview/llpreviewgesture.h
+++ b/indra/newview/llpreviewgesture.h
@@ -132,6 +132,7 @@ protected:
static void onDonePreview(LLMultiGesture* gesture, void* data);
+ static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId);
private:
// LLPreview contains mDescEditor
LLLineEditor* mTriggerEditor;
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index 9f88b0db5f..af56fe367e 100755
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -31,7 +31,6 @@
#include "llinventory.h"
#include "llagent.h"
-#include "llassetuploadresponders.h"
#include "lldraghandle.h"
#include "llviewerwindow.h"
#include "llbutton.h"
@@ -56,6 +55,7 @@
#include "llappviewer.h" // app_abort_quit()
#include "lllineeditor.h"
#include "lluictrlfactory.h"
+#include "llviewerassetupload.h"
///----------------------------------------------------------------------------
/// Class LLPreviewNotecard
@@ -232,7 +232,7 @@ void LLPreviewNotecard::loadAsset()
}
else
{
- LLHost source_sim = LLHost::invalid;
+ LLHost source_sim = LLHost();
if (mObjectUUID.notNull())
{
LLViewerObject *objectp = gObjectList.findObject(mObjectUUID);
@@ -401,6 +401,35 @@ struct LLSaveNotecardInfo
}
};
+void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId)
+{
+ // Update the UI with the new asset.
+ LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(itemId));
+ if (nc)
+ {
+ // *HACK: we have to delete the asset in the VFS so
+ // that the viewer will redownload it. This is only
+ // really necessary if the asset had to be modified by
+ // the uploader, so this can be optimized away in some
+ // cases. A better design is to have a new uuid if the
+ // script actually changed the asset.
+ if (nc->hasEmbeddedInventory())
+ {
+ gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD);
+ }
+ if (newItemId.isNull())
+ {
+ nc->setAssetId(newAssetId);
+ nc->refreshFromInventory();
+ }
+ else
+ {
+ nc->refreshFromInventory(newItemId);
+ }
+ }
+}
+
+
bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
{
LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor");
@@ -413,14 +442,6 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
if(!editor->isPristine())
{
- // We need to update the asset information
- LLTransactionID tid;
- LLAssetID asset_id;
- tid.generate();
- asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
-
- LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND);
-
std::string buffer;
if (!editor->exportBuffer(buffer))
{
@@ -429,52 +450,64 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem)
editor->makePristine();
- S32 size = buffer.length() + 1;
- file.setMaxSize(size);
- file.write((U8*)buffer.c_str(), size);
-
const LLInventoryItem* item = getItem();
// save it out to database
- if (item)
- {
- const LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- {
- LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL;
- return false;
- }
- std::string agent_url = region->getCapability("UpdateNotecardAgentInventory");
- std::string task_url = region->getCapability("UpdateNotecardTaskInventory");
-
- if (mObjectUUID.isNull() && !agent_url.empty())
- {
- // Saving into agent inventory
- mAssetStatus = PREVIEW_ASSET_LOADING;
- setEnabled(FALSE);
- LLSD body;
- body["item_id"] = mItemUUID;
- LL_INFOS() << "Saving notecard " << mItemUUID
- << " into agent inventory via " << agent_url << LL_ENDL;
- LLHTTPClient::post(agent_url, body,
- new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
- }
- else if (!mObjectUUID.isNull() && !task_url.empty())
- {
- // Saving into task inventory
- mAssetStatus = PREVIEW_ASSET_LOADING;
- setEnabled(FALSE);
- LLSD body;
- body["task_id"] = mObjectUUID;
- body["item_id"] = mItemUUID;
- LL_INFOS() << "Saving notecard " << mItemUUID << " into task "
- << mObjectUUID << " via " << task_url << LL_ENDL;
- LLHTTPClient::post(task_url, body,
- new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD));
- }
+ if (item)
+ {
+ const LLViewerRegion* region = gAgent.getRegion();
+ if (!region)
+ {
+ LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL;
+ return false;
+ }
+ std::string agent_url = region->getCapability("UpdateNotecardAgentInventory");
+ std::string task_url = region->getCapability("UpdateNotecardTaskInventory");
+
+ if (!agent_url.empty() && !task_url.empty())
+ {
+ std::string url;
+ LLResourceUploadInfo::ptr_t uploadInfo;
+
+ if (mObjectUUID.isNull() && !agent_url.empty())
+ {
+ uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mItemUUID, LLAssetType::AT_NOTECARD, buffer,
+ boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _2, _3)));
+ url = agent_url;
+ }
+ else if (!mObjectUUID.isNull() && !task_url.empty())
+ {
+ uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer,
+ boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _3, LLUUID::null)));
+ url = task_url;
+ }
+
+ if (!url.empty() && uploadInfo)
+ {
+ mAssetStatus = PREVIEW_ASSET_LOADING;
+ setEnabled(false);
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+
+ }
else if (gAssetStorage)
{
+ // We need to update the asset information
+ LLTransactionID tid;
+ LLAssetID asset_id;
+ tid.generate();
+ asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND);
+
+
LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID,
tid, copyitem);
+
+ S32 size = buffer.length() + 1;
+ file.setMaxSize(size);
+ file.write((U8*)buffer.c_str(), size);
+
gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD,
&onSaveComplete,
(void*)info,
diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h
index 1cf08dedd6..ba571995f6 100755
--- a/indra/newview/llpreviewnotecard.h
+++ b/indra/newview/llpreviewnotecard.h
@@ -95,6 +95,8 @@ protected:
bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response);
bool handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response);
+ static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId);
+
protected:
LLViewerTextEditor* mEditor;
LLButton* mSaveBtn;
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 1bbb22416d..5f029ca6a2 100755
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -29,7 +29,6 @@
#include "llpreviewscript.h"
#include "llassetstorage.h"
-#include "llassetuploadresponders.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
@@ -88,7 +87,7 @@
#include "llfloatergotoline.h"
#include "llexperiencecache.h"
#include "llfloaterexperienceprofile.h"
-#include "llexperienceassociationresponder.h"
+#include "llviewerassetupload.h"
const std::string HELLO_LSL =
"default\n"
@@ -118,26 +117,6 @@ static bool have_script_upload_cap(LLUUID& object_id)
return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty());
}
-
-class ExperienceResponder : public LLHTTPClient::Responder
-{
-public:
- ExperienceResponder(const LLHandle<LLLiveLSLEditor>& parent):mParent(parent)
- {
- }
-
- LLHandle<LLLiveLSLEditor> mParent;
-
- /*virtual*/ void httpSuccess()
- {
- LLLiveLSLEditor* parent = mParent.get();
- if(!parent)
- return;
-
- parent->setExperienceIds(getContent()["experience_ids"]);
- }
-};
-
/// ---------------------------------------------------------------------------
/// LLLiveLSLFile
/// ---------------------------------------------------------------------------
@@ -1346,7 +1325,7 @@ void LLLiveLSLEditor::buildExperienceList()
position = ADD_TOP;
}
- const LLSD& experience = LLExperienceCache::get(id);
+ const LLSD& experience = LLExperienceCache::instance().get(id);
if(experience.isUndefined())
{
mExperiences->add(getString("loading"), id, position);
@@ -1365,7 +1344,7 @@ void LLLiveLSLEditor::buildExperienceList()
if(!foundAssociated )
{
- const LLSD& experience = LLExperienceCache::get(associated);
+ const LLSD& experience = LLExperienceCache::instance().get(associated);
if(experience.isDefined())
{
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
@@ -1386,7 +1365,7 @@ void LLLiveLSLEditor::buildExperienceList()
if(last.notNull())
{
mExperiences->setEnabled(FALSE);
- LLExperienceCache::get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));
+ LLExperienceCache::instance().get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));
}
else
{
@@ -1416,11 +1395,23 @@ void LLLiveLSLEditor::requestExperiences()
std::string lookup_url=region->getCapability("GetCreatorExperiences");
if(!lookup_url.empty())
{
- LLHTTPClient::get(lookup_url, new ExperienceResponder(getDerivedHandle<LLLiveLSLEditor>()));
+ LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success =
+ boost::bind(&LLLiveLSLEditor::receiveExperienceIds, _1, getDerivedHandle<LLLiveLSLEditor>());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url, success);
}
}
}
+/*static*/
+void LLLiveLSLEditor::receiveExperienceIds(LLSD result, LLHandle<LLLiveLSLEditor> hparent)
+{
+ LLLiveLSLEditor* parent = hparent.get();
+ if (!parent)
+ return;
+
+ parent->setExperienceIds(result["experience_ids"]);
+}
/// ---------------------------------------------------------------------------
@@ -1571,7 +1562,7 @@ void LLPreviewLSL::loadAsset()
if (gAgent.isGodlike() || (is_copyable && (is_modifiable || is_library)))
{
LLUUID* new_uuid = new LLUUID(mItemUUID);
- gAssetStorage->getInvItemAsset(LLHost::invalid,
+ gAssetStorage->getInvItemAsset(LLHost(),
gAgent.getID(),
gAgent.getSessionID(),
item->getPermissions().getOwner(),
@@ -1641,62 +1632,74 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save)
self->saveIfNeeded();
}
+/*static*/
+void LLPreviewLSL::finishedLSLUpload(LLUUID itemId, LLSD response)
+{
+ // Find our window and close it if requested.
+ LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", LLSD(itemId));
+ if (preview)
+ {
+ // Bytecode save completed
+ if (response["compiled"])
+ {
+ preview->callbackLSLCompileSucceeded();
+ }
+ else
+ {
+ preview->callbackLSLCompileFailed(response["errors"]);
+ }
+ }
+}
+
// Save needs to compile the text in the buffer. If the compile
// succeeds, then save both assets out to the database. If the compile
// fails, go ahead and save the text anyway.
void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/)
{
- // LL_INFOS() << "LLPreviewLSL::saveIfNeeded()" << LL_ENDL;
- if(!mScriptEd->hasChanged())
- {
- return;
- }
-
- mPendingUploads = 0;
- mScriptEd->mErrorList->deleteAllItems();
- mScriptEd->mEditor->makePristine();
-
- // save off asset into file
- LLTransactionID tid;
- tid.generate();
- LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
- std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
- std::string filename = filepath + ".lsl";
-
- mScriptEd->writeToFile(filename);
-
- if (sync)
- {
- mScriptEd->sync();
- }
-
- const LLInventoryItem *inv_item = getItem();
- // save it out to asset server
- std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
- if(inv_item)
- {
- getWindow()->incBusyCount();
- mPendingUploads++;
- if (!url.empty())
- {
- uploadAssetViaCaps(url, filename, mItemUUID);
- }
- else if (gAssetStorage)
- {
- uploadAssetLegacy(filename, mItemUUID, tid);
- }
- }
-}
-
-void LLPreviewLSL::uploadAssetViaCaps(const std::string& url,
- const std::string& filename,
- const LLUUID& item_id)
-{
- LL_INFOS() << "Update Agent Inventory via capability" << LL_ENDL;
- LLSD body;
- body["item_id"] = item_id;
- body["target"] = "lsl2";
- LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT));
+ if (!mScriptEd->hasChanged())
+ {
+ return;
+ }
+
+ mPendingUploads = 0;
+ mScriptEd->mErrorList->deleteAllItems();
+ mScriptEd->mEditor->makePristine();
+
+ if (sync)
+ {
+ mScriptEd->sync();
+ }
+
+ const LLInventoryItem *inv_item = getItem();
+ // save it out to asset server
+ std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
+ if(inv_item)
+ {
+ getWindow()->incBusyCount();
+ mPendingUploads++;
+ if (!url.empty())
+ {
+ std::string buffer(mScriptEd->mEditor->getText());
+ LLBufferedAssetUploadInfo::invnUploadFinish_f proc = boost::bind(&LLPreviewLSL::finishedLSLUpload, _1, _4);
+
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(mItemUUID, buffer, proc));
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+ else if (gAssetStorage)
+ {
+ // save off asset into file
+ LLTransactionID tid;
+ tid.generate();
+ LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+ std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, asset_id.asString());
+ std::string filename = filepath + ".lsl";
+
+ mScriptEd->writeToFile(filename);
+
+ uploadAssetLegacy(filename, mItemUUID, tid);
+ }
+ }
}
void LLPreviewLSL::uploadAssetLegacy(const std::string& filename,
@@ -2035,8 +2038,9 @@ void LLLiveLSLEditor::loadAsset()
if(item)
{
- ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1));
-
+ LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(),
+ boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1));
+
bool isGodlike = gAgent.isGodlike();
bool copyManipulate = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE);
mIsModifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE);
@@ -2321,6 +2325,33 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id,
mItem = new LLViewerInventoryItem(item);
}
+
+/*static*/
+void LLLiveLSLEditor::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, bool isRunning)
+{
+ LLSD floater_key;
+ floater_key["taskid"] = taskId;
+ floater_key["itemid"] = itemId;
+
+ LLLiveLSLEditor* preview = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", floater_key);
+ if (preview)
+ {
+ preview->mItem->setAssetUUID(newAssetId);
+
+ // Bytecode save completed
+ if (response["compiled"])
+ {
+ preview->callbackLSLCompileSucceeded(taskId, itemId, isRunning);
+ }
+ else
+ {
+ preview->callbackLSLCompileFailed(response["errors"]);
+ }
+ }
+
+}
+
+
// virtual
void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
{
@@ -2331,7 +2362,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
return;
}
- if(mItem.isNull() || !mItem->isFinished())
+ if (mItem.isNull() || !mItem->isFinished())
{
// $NOTE: While the error message may not be exactly correct,
// it's pretty close.
@@ -2339,78 +2370,68 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
return;
}
- // get the latest info about it. We used to be losing the script
- // name on save, because the viewer object version of the item,
- // and the editor version would get out of synch. Here's a good
- // place to synch them back up.
- LLInventoryItem* inv_item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mItemUUID));
- if(inv_item)
- {
- mItem->copyItem(inv_item);
- }
-
- // Don't need to save if we're pristine
- if(!mScriptEd->hasChanged())
- {
- return;
- }
-
- mPendingUploads = 0;
-
- // save the script
- mScriptEd->enableSave(FALSE);
- mScriptEd->mEditor->makePristine();
- mScriptEd->mErrorList->deleteAllItems();
-
- // set up the save on the local machine.
- mScriptEd->mEditor->makePristine();
- LLTransactionID tid;
- tid.generate();
- LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
- std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString());
- std::string filename = llformat("%s.lsl", filepath.c_str());
-
- mItem->setAssetUUID(asset_id);
- mItem->setTransactionID(tid);
+ // get the latest info about it. We used to be losing the script
+ // name on save, because the viewer object version of the item,
+ // and the editor version would get out of synch. Here's a good
+ // place to synch them back up.
+ LLInventoryItem* inv_item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mItemUUID));
+ if (inv_item)
+ {
+ mItem->copyItem(inv_item);
+ }
+
+ // Don't need to save if we're pristine
+ if(!mScriptEd->hasChanged())
+ {
+ return;
+ }
+
+ mPendingUploads = 0;
+
+ // save the script
+ mScriptEd->enableSave(FALSE);
+ mScriptEd->mEditor->makePristine();
+ mScriptEd->mErrorList->deleteAllItems();
+ mScriptEd->mEditor->makePristine();
+
+ if (sync)
+ {
+ mScriptEd->sync();
+ }
+ bool isRunning = getChild<LLCheckBoxCtrl>("running")->get();
+ getWindow()->incBusyCount();
+ mPendingUploads++;
+
+ std::string url = object->getRegion()->getCapability("UpdateScriptTask");
+
+ if (!url.empty())
+ {
+ std::string buffer(mScriptEd->mEditor->getText());
+ LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLLiveLSLEditor::finishLSLUpload, _1, _2, _3, _4, isRunning);
+
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(mObjectUUID, mItemUUID,
+ monoChecked() ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2,
+ isRunning, mScriptEd->getAssociatedExperience(), buffer, proc));
+
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
+ }
+ else if (gAssetStorage)
+ {
+ // set up the save on the local machine.
+ LLTransactionID tid;
+ tid.generate();
+ LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+ std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, asset_id.asString());
+ std::string filename = llformat("%s.lsl", filepath.c_str());
+
+ mItem->setAssetUUID(asset_id);
+ mItem->setTransactionID(tid);
+
+ mScriptEd->writeToFile(filename);
+
+ uploadAssetLegacy(filename, object, tid, isRunning);
+ }
- mScriptEd->writeToFile(filename);
-
- if (sync)
- {
- mScriptEd->sync();
- }
-
- // save it out to asset server
- std::string url = object->getRegion()->getCapability("UpdateScriptTask");
- getWindow()->incBusyCount();
- mPendingUploads++;
- BOOL is_running = getChild<LLCheckBoxCtrl>( "running")->get();
- if (!url.empty())
- {
- uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running, mScriptEd->getAssociatedExperience());
- }
- else if (gAssetStorage)
- {
- uploadAssetLegacy(filename, object, tid, is_running);
- }
-}
-
-void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
- const std::string& filename,
- const LLUUID& task_id,
- const LLUUID& item_id,
- BOOL is_running,
- const LLUUID& experience_public_id )
-{
- LL_INFOS() << "Update Task Inventory via capability " << url << LL_ENDL;
- LLSD body;
- body["task_id"] = task_id;
- body["item_id"] = item_id;
- body["is_script_running"] = is_running;
- body["target"] = monoChecked() ? "mono" : "lsl2";
- body["experience"] = experience_public_id;
- LLHTTPClient::post(url, body,
- new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT));
}
void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename,
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index 5f65be7383..02f236a089 100755
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -203,9 +203,7 @@ protected:
virtual void loadAsset();
/*virtual*/ void saveIfNeeded(bool sync = true);
- void uploadAssetViaCaps(const std::string& url,
- const std::string& filename,
- const LLUUID& item_id);
+
void uploadAssetLegacy(const std::string& filename,
const LLUUID& item_id,
const LLTransactionID& tid);
@@ -223,7 +221,7 @@ protected:
protected:
static void* createScriptEdPanel(void* userdata);
-
+ static void finishedLSLUpload(LLUUID itemId, LLSD response);
protected:
// Can safely close only after both text and bytecode are uploaded
@@ -270,12 +268,6 @@ private:
virtual void loadAsset();
void loadAsset(BOOL is_new);
/*virtual*/ void saveIfNeeded(bool sync = true);
- void uploadAssetViaCaps(const std::string& url,
- const std::string& filename,
- const LLUUID& task_id,
- const LLUUID& item_id,
- BOOL is_running,
- const LLUUID& experience_public_id);
void uploadAssetLegacy(const std::string& filename,
LLViewerObject* object,
const LLTransactionID& tid,
@@ -303,6 +295,9 @@ private:
static void onMonoCheckboxClicked(LLUICtrl*, void* userdata);
+ static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, bool isRunning);
+ static void receiveExperienceIds(LLSD result, LLHandle<LLLiveLSLEditor> parent);
+
private:
bool mIsNew;
//LLUUID mTransmitID;
diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp
index e92bf4590d..b663df4aae 100755
--- a/indra/newview/llproductinforequest.cpp
+++ b/indra/newview/llproductinforequest.cpp
@@ -32,31 +32,10 @@
#include "llagent.h" // for gAgent
#include "lltrans.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
-class LLProductInfoRequestResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLProductInfoRequestResponder);
-private:
- //If we get back a normal response, handle it here
- /* virtual */ void httpSuccess()
- {
- 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 httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
-};
-
-LLProductInfoRequestManager::LLProductInfoRequestManager() : mSkuDescriptions()
+LLProductInfoRequestManager::LLProductInfoRequestManager():
+ mSkuDescriptions()
{
}
@@ -65,15 +44,11 @@ void LLProductInfoRequestManager::initSingleton()
std::string url = gAgent.getRegion()->getCapability("ProductInfoRequest");
if (!url.empty())
{
- LLHTTPClient::get(url, new LLProductInfoRequestResponder());
+ LLCoros::instance().launch("LLProductInfoRequestManager::getLandDescriptionsCoro",
+ boost::bind(&LLProductInfoRequestManager::getLandDescriptionsCoro, this, url));
}
}
-void LLProductInfoRequestManager::setSkuDescriptions(const LLSD& content)
-{
- mSkuDescriptions = content;
-}
-
std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string& sku)
{
// The description LLSD is an array of maps; each array entry
@@ -90,3 +65,31 @@ std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string&
}
return LLTrans::getString("land_type_unknown");
}
+
+void LLProductInfoRequestManager::getLandDescriptionsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ return;
+ }
+
+ if (result.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT) &&
+ result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT].isArray())
+ {
+ mSkuDescriptions = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT];
+ }
+ else
+ {
+ LL_WARNS() << "Land SKU description response is malformed" << LL_ENDL;
+ }
+}
diff --git a/indra/newview/llproductinforequest.h b/indra/newview/llproductinforequest.h
index fe8f7093b0..75dbf220d1 100755
--- a/indra/newview/llproductinforequest.h
+++ b/indra/newview/llproductinforequest.h
@@ -28,27 +28,29 @@
#ifndef LL_LLPRODUCTINFOREQUEST_H
#define LL_LLPRODUCTINFOREQUEST_H
-#include "llhttpclient.h"
#include "llmemory.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
-/*
- This is a singleton to manage a cache of information about land types.
- The land system provides a capability to get information about the
- set of possible land sku, name, and description information.
- We use description in the UI, but the sku is provided in the various
- messages; this tool provides translation between the systems.
+/**
+ * This is a singleton to manage a cache of information about land types.
+ * The land system provides a capability to get information about the
+ * set of possible land sku, name, and description information.
+ * We use description in the UI, but the sku is provided in the various
+ * messages; this tool provides translation between the systems.
*/
-
class LLProductInfoRequestManager : public LLSingleton<LLProductInfoRequestManager>
{
public:
LLProductInfoRequestManager();
- void setSkuDescriptions(const LLSD& content);
std::string getDescriptionForSku(const std::string& sku);
+
private:
friend class LLSingleton<LLProductInfoRequestManager>;
/* virtual */ void initSingleton();
- LLSD mSkuDescriptions;
+
+ void getLandDescriptionsCoro(std::string url);
+ LLSD mSkuDescriptions;
};
#endif // LL_LLPRODUCTINFOREQUEST_H
diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index 29dcc12f9e..055ccd5818 100755
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -31,55 +31,16 @@
#include "message.h"
#include "llpanel.h"
-#include "llhttpclient.h"
#include "llsdserialize.h"
#include "llurlentry.h"
#include "llviewerregion.h"
#include "llview.h"
-
+#include "llsdutil.h"
+#include "llsdutil_math.h"
+#include "llregionhandle.h"
#include "llagent.h"
#include "llremoteparcelrequest.h"
-
-
-LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle)
- : mObserverHandle(observer_handle)
-{}
-
-//If we get back a normal response, handle it here
-//virtual
-void LLRemoteParcelRequestResponder::httpSuccess()
-{
- 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.
- LLRemoteParcelInfoObserver* observer = mObserverHandle.get();
- if (observer)
- {
- observer->setParcelID(parcel_id);
- }
-}
-
-//If we get back an error (not found, etc...), handle it here
-//virtual
-void LLRemoteParcelRequestResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- // Panel inspecting the information may be closed and destroyed
- // before this response is received.
- LLRemoteParcelInfoObserver* observer = mObserverHandle.get();
- if (observer)
- {
- observer->setErrorStatus(getStatus(), getReason());
- }
-}
+#include "llcorehttputil.h"
void LLRemoteParcelInfoProcessor::addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer)
{
@@ -200,3 +161,64 @@ void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id)
msg->addUUID("ParcelID", parcel_id);
gAgent.sendReliableMessage();
}
+
+bool LLRemoteParcelInfoProcessor::requestRegionParcelInfo(const std::string &url,
+ const LLUUID &regionId, const LLVector3 &regionPos, const LLVector3d&globalPos,
+ LLHandle<LLRemoteParcelInfoObserver> observerHandle)
+{
+
+ if (!url.empty())
+ {
+ LLCoros::instance().launch("LLRemoteParcelInfoProcessor::regionParcelInfoCoro",
+ boost::bind(&LLRemoteParcelInfoProcessor::regionParcelInfoCoro, this, url,
+ regionId, regionPos, globalPos, observerHandle));
+ return true;
+ }
+
+ return false;
+}
+
+void LLRemoteParcelInfoProcessor::regionParcelInfoCoro(std::string url,
+ LLUUID regionId, LLVector3 posRegion, LLVector3d posGlobal,
+ LLHandle<LLRemoteParcelInfoObserver> observerHandle)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("RemoteParcelRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD bodyData;
+
+ bodyData["location"] = ll_sd_from_vector3(posRegion);
+ if (!regionId.isNull())
+ {
+ bodyData["region_id"] = regionId;
+ }
+ if (!posGlobal.isExactlyZero())
+ {
+ U64 regionHandle = to_region_handle(posGlobal);
+ bodyData["region_handle"] = ll_sd_from_U64(regionHandle);
+ }
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, bodyData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ LLRemoteParcelInfoObserver* observer = observerHandle.get();
+ // Panel inspecting the information may be closed and destroyed
+ // before this response is received.
+ if (!observer)
+ return;
+
+ if (!status)
+ {
+ observer->setErrorStatus(status.getStatus(), status.getMessage());
+ }
+ else
+ {
+ LLUUID parcel_id = result["parcel_id"];
+ observer->setParcelID(parcel_id);
+ }
+
+}
diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h
index 35348b69ff..cb5af50c5f 100755
--- a/indra/newview/llremoteparcelrequest.h
+++ b/indra/newview/llremoteparcelrequest.h
@@ -29,29 +29,14 @@
#ifndef LL_LLREMOTEPARCELREQUEST_H
#define LL_LLREMOTEPARCELREQUEST_H
-#include "llhttpclient.h"
#include "llhandle.h"
#include "llsingleton.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLMessageSystem;
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 httpSuccess();
-
- //If we get back an error (not found, etc...), handle it here
- /*virtual*/ void httpFailure();
-
- LLHandle<LLRemoteParcelInfoObserver> mObserverHandle;
-};
-
struct LLParcelData
{
LLUUID parcel_id;
@@ -99,9 +84,14 @@ public:
static void processParcelInfoReply(LLMessageSystem* msg, void**);
+ bool requestRegionParcelInfo(const std::string &url, const LLUUID &regionId,
+ const LLVector3 &regionPos, const LLVector3d& globalPos, LLHandle<LLRemoteParcelInfoObserver> observerHandle);
+
private:
typedef std::multimap<LLUUID, LLHandle<LLRemoteParcelInfoObserver> > observer_multimap_t;
observer_multimap_t mObservers;
+
+ void regionParcelInfoCoro(std::string url, LLUUID regionId, LLVector3 posRegion, LLVector3d posGlobal, LLHandle<LLRemoteParcelInfoObserver> observerHandle);
};
#endif // LL_LLREMOTEPARCELREQUEST_H
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
index 43bb7b1596..4f9f83b6f2 100755
--- a/indra/newview/llsecapi.cpp
+++ b/indra/newview/llsecapi.cpp
@@ -32,7 +32,6 @@
#include <openssl/evp.h>
#include <openssl/err.h>
#include <map>
-#include "llhttpclient.h"
@@ -99,46 +98,6 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred)
return s << (std::string)cred;
}
-
-// secapiSSLCertVerifyCallback
-// basic callback called when a cert verification is requested.
-// calls SECAPI to validate the context
-// not initialized in the above initialization function, due to unit tests
-// see llappviewer
-
-int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
-{
- LLURLRequest *req = (LLURLRequest *)param;
- LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
- LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
- LLSD validation_params = LLSD::emptyMap();
- LLURI uri(req->getURL());
- validation_params[CERT_HOSTNAME] = uri.hostName();
- try
- {
- // we rely on libcurl to validate the hostname, as libcurl does more extensive validation
- // leaving our hostname validation call mechanism for future additions with respect to
- // OS native (Mac keyring, windows CAPI) validation.
- store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
- }
- catch (LLCertValidationTrustException& cert_exception)
- {
- LL_WARNS("AppInit") << "Cert not trusted: " << cert_exception.getMessage() << LL_ENDL;
- return 0;
- }
- catch (LLCertException& cert_exception)
- {
- LL_WARNS("AppInit") << "cert error " << cert_exception.getMessage() << LL_ENDL;
- return 0;
- }
- catch (...)
- {
- LL_WARNS("AppInit") << "cert error " << LL_ENDL;
- return 0;
- }
- return 1;
-}
-
LLSD LLCredential::getLoginParams()
{
LLSD result = LLSD::emptyMap();
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index c01d318f56..6fe3ee31cf 100755
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -489,7 +489,4 @@ void registerSecHandler(const std::string& handler_type,
extern LLPointer<LLSecAPIHandler> gSecAPIHandler;
-int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
-
-
#endif // LL_SECAPI_H
diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp
index 0e23e2ad10..67ac875428 100755
--- a/indra/newview/llsidepanelinventory.cpp
+++ b/indra/newview/llsidepanelinventory.cpp
@@ -37,7 +37,6 @@
#include "llfloatersidepanelcontainer.h"
#include "llfoldertype.h"
#include "llfolderview.h"
-#include "llhttpclient.h"
#include "llinventorybridge.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index a7cfc173af..12cbff888d 100755
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -44,7 +44,6 @@
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
-#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
#include "lltrans.h"
@@ -328,7 +327,9 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
LLTextBox* tb = getChild<LLTextBox>("LabelItemExperience");
tb->setText(getString("loading_experience"));
tb->setVisible(TRUE);
- ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1));
+
+ LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(),
+ boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1));
}
//////////////////////
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index 0ae8a338e0..8fb3340db0 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -1004,21 +1004,18 @@ void LLSnapshotLivePreview::saveTexture()
LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL);
std::string who_took_it;
LLAgentUI::buildFullname(who_took_it);
- LLAssetStorage::LLStoreAssetCallback callback = NULL;
S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
- void *userdata = NULL;
- upload_new_resource(tid, // tid
- LLAssetType::AT_TEXTURE,
- "Snapshot : " + pos_string,
- "Taken by " + who_took_it + " at " + pos_string,
- 0,
- LLFolderType::FT_SNAPSHOT_CATEGORY,
- LLInventoryType::IT_SNAPSHOT,
- PERM_ALL, // Note: Snapshots to inventory is a special case of content upload
- LLFloaterPerms::getGroupPerms("Uploads"), // that is more permissive than other uploads
- LLFloaterPerms::getEveryonePerms("Uploads"),
- "Snapshot : " + pos_string,
- callback, expected_upload_cost, userdata);
+ std::string name = "Snapshot: " + pos_string;
+ std::string desc = "Taken by " + who_took_it + " at " + pos_string;
+
+ LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo(
+ tid, LLAssetType::AT_TEXTURE, name, desc, 0,
+ LLFolderType::FT_SNAPSHOT_CATEGORY, LLInventoryType::IT_SNAPSHOT,
+ PERM_ALL, LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost));
+
+ upload_new_resource(assetUploadInfo);
+
gViewerWindow->playSnapshotAnimAndSound();
}
else
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 7867e1573c..974029254f 100755
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -34,11 +34,11 @@
#include "llgroupmgr.h"
#include "llsdutil.h"
#include "lluicolortable.h"
-#include "llhttpclient.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llvoavatar.h"
#include "llworld.h"
+#include "llcorehttputil.h"
extern LLControlGroup gSavedSettings;
@@ -265,49 +265,6 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)
}
//
-// ModerationResponder
-//
-
-class ModerationResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(ModerationResponder);
-public:
- ModerationResponder(const LLUUID& session_id)
- {
- mSessionID = session_id;
- }
-
-protected:
- virtual void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- if ( gIMMgr )
- {
- //403 == you're not a mod
- //should be disabled if you're not a moderator
- if ( HTTP_FORBIDDEN == getStatus() )
- {
- gIMMgr->showSessionEventError(
- "mute",
- "not_a_mod_error",
- mSessionID);
- }
- else
- {
- gIMMgr->showSessionEventError(
- "mute",
- "generic_request_error",
- mSessionID);
- }
- }
- }
-
-private:
- LLUUID mSessionID;
-};
-
-//
// LLSpeakerMgr
//
@@ -883,7 +840,8 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)
//current value represents ability to type, so invert
data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText;
- LLHTTPClient::post(url, data, new ModerationResponder(getSessionID()));
+ LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro",
+ boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data));
}
void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute)
@@ -907,10 +865,50 @@ void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmu
data["params"]["mute_info"] = LLSD::emptyMap();
data["params"]["mute_info"]["voice"] = !unmute;
- LLHTTPClient::post(
- url,
- data,
- new ModerationResponder(getSessionID()));
+ LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro",
+ boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data));
+}
+
+void LLIMSpeakerMgr::moderationActionCoro(std::string url, LLSD action)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("moderationActionCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+
+ LLUUID sessionId = action["session-id"];
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, action, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (gIMMgr)
+ {
+ //403 == you're not a mod
+ //should be disabled if you're not a moderator
+ if (status == LLCore::HttpStatus(HTTP_FORBIDDEN))
+ {
+ gIMMgr->showSessionEventError(
+ "mute",
+ "not_a_mod_error",
+ sessionId);
+ }
+ else
+ {
+ gIMMgr->showSessionEventError(
+ "mute",
+ "generic_request_error",
+ sessionId);
+ }
+ }
+ return;
+ }
}
void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone )
@@ -949,7 +947,8 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo
data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap();
data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice;
- LLHTTPClient::post(url, data, new ModerationResponder(session_id));
+ LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro",
+ boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data));
}
void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted)
diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h
index 0e69184125..5cff70f377 100755
--- a/indra/newview/llspeakers.h
+++ b/indra/newview/llspeakers.h
@@ -30,6 +30,8 @@
#include "llevent.h"
#include "lleventtimer.h"
#include "llvoicechannel.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLSpeakerMgr;
@@ -333,6 +335,8 @@ protected:
*/
void forceVoiceModeratedMode(bool should_be_muted);
+ void moderationActionCoro(std::string url, LLSD action);
+
};
class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr>
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d2050aec3e..ff8b79bc7c 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -46,7 +46,6 @@
#include "llaudioengine_openal.h"
#endif
-#include "llares.h"
#include "llavatarnamecache.h"
#include "llexperiencecache.h"
#include "lllandmark.h"
@@ -56,7 +55,6 @@
#include "llerrorcontrol.h"
#include "llfloaterreg.h"
#include "llfocusmgr.h"
-#include "llhttpsender.h"
#include "llfloaterimsession.h"
#include "lllocationhistory.h"
#include "llimageworker.h"
@@ -113,7 +111,6 @@
#include "llgroupmgr.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
-#include "llhttpclient.h"
#include "llimagebmp.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
@@ -292,20 +289,6 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
// local classes
//
-namespace
-{
- class LLNullHTTPSender : public LLHTTPSender
- {
- virtual void send(const LLHost& host,
- const std::string& message, const LLSD& body,
- LLHTTPClient::ResponderPtr response) const
- {
- LL_WARNS("AppInit") << " attemped to send " << message << " to " << host
- << " with null sender" << LL_ENDL;
- }
- };
-}
-
void update_texture_fetch()
{
LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
@@ -460,13 +443,6 @@ bool idle_startup()
// Load the throttle settings
gViewerThrottle.load();
- if (ll_init_ares() == NULL || !gAres->isInitialized())
- {
- std::string diagnostic = "Could not start address resolution system";
- LL_WARNS("AppInit") << diagnostic << LL_ENDL;
- LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
- }
-
//
// Initialize messaging system
//
@@ -511,8 +487,6 @@ bool idle_startup()
port = gSavedSettings.getU32("ConnectionPort");
}
- LLHTTPSender::setDefaultSender(new LLNullHTTPSender());
-
// TODO parameterize
const F32 circuit_heartbeat_interval = 5;
const F32 circuit_timeout = 100;
@@ -754,12 +728,12 @@ bool idle_startup()
if (gLoginMenuBarView == NULL)
{
LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL;
- display_startup();
+// display_startup();
initialize_edit_menu();
initialize_spellcheck_menu();
- display_startup();
+// display_startup();
init_menus();
- display_startup();
+// display_startup();
}
if (show_connect_box)
@@ -771,23 +745,23 @@ bool idle_startup()
if (gUserCredential.isNull())
{
LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL;
- display_startup();
+// display_startup();
gUserCredential = gLoginHandler.initializeLoginInfo();
- display_startup();
+// display_startup();
}
// Make sure the process dialog doesn't hide things
- display_startup();
+// display_startup();
gViewerWindow->setShowProgress(FALSE);
- display_startup();
+// display_startup();
// Show the login dialog
login_show();
- display_startup();
+// display_startup();
// connect dialog is already shown, so fill in the names
if (gUserCredential.notNull())
{
LLPanelLogin::setFields( gUserCredential, gRememberPassword);
}
- display_startup();
+// display_startup();
LLPanelLogin::giveFocus();
// MAINT-3231 Show first run dialog only for Desura viewer
@@ -813,22 +787,22 @@ bool idle_startup()
LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
}
- display_startup();
+// display_startup();
gViewerWindow->setNormalControlsVisible( FALSE );
- display_startup();
+// display_startup();
gLoginMenuBarView->setVisible( TRUE );
- display_startup();
+// display_startup();
gLoginMenuBarView->setEnabled( TRUE );
- display_startup();
+// display_startup();
show_debug_menus();
- display_startup();
+// display_startup();
// Hide the splash screen
LLSplashScreen::hide();
- display_startup();
+// display_startup();
// Push our window frontmost
gViewerWindow->getWindow()->show();
- display_startup();
+// display_startup();
// DEV-16927. The following code removes errant keystrokes that happen while the window is being
// first made visible.
@@ -836,9 +810,10 @@ bool idle_startup()
MSG msg;
while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) )
{ }
- display_startup();
+// display_startup();
#endif
- timeout.reset();
+ display_startup();
+ timeout.reset();
return FALSE;
}
@@ -2777,8 +2752,6 @@ void reset_login()
gAgent.cleanup();
LLWorld::getInstance()->destroyClass();
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
-
if ( gViewerWindow )
{ // Hide menus and normal buttons
gViewerWindow->setNormalControlsVisible( FALSE );
@@ -2788,6 +2761,7 @@ void reset_login()
// Hide any other stuff
LLFloaterReg::hideVisibleInstances();
+ LLStartUp::setStartupState( STATE_BROWSER_INIT );
}
//---------------------------------------------------------------------------
@@ -2837,9 +2811,11 @@ void LLStartUp::initNameCache()
void LLStartUp::initExperiences()
-{
- LLAppViewer::instance()->loadExperienceCache();
- LLExperienceCache::initClass();
+{
+ // Should trigger loading the cache.
+ LLExperienceCache::instance().setCapabilityQuery(
+ boost::bind(&LLAgent::getRegionCapability, &gAgent, _1));
+
LLExperienceLog::instance().initialize();
}
diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp
index 802dff1ead..9e54c521b5 100644
--- a/indra/newview/llsyntaxid.cpp
+++ b/indra/newview/llsyntaxid.cpp
@@ -31,70 +31,11 @@
#include "llsyntaxid.h"
#include "llagent.h"
#include "llappviewer.h"
-#include "llhttpclient.h"
#include "llsdserialize.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
//-----------------------------------------------------------------------------
-// fetchKeywordsFileResponder
-//-----------------------------------------------------------------------------
-class fetchKeywordsFileResponder : public LLHTTPClient::Responder
-{
-public:
- fetchKeywordsFileResponder(const std::string& filespec)
- : mFileSpec(filespec)
- {
- LL_DEBUGS("SyntaxLSL") << "Instantiating with file saving to: '" << filespec << "'" << LL_ENDL;
- }
-
- /* virtual */ void httpFailure()
- {
- LL_WARNS("SyntaxLSL") << "failed to fetch syntax file [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
- }
-
- /* virtual */ void httpSuccess()
- {
- // Continue only if a valid LLSD object was returned.
- const LLSD& content = getContent();
- if (content.isMap())
- {
- if (LLSyntaxIdLSL::getInstance()->isSupportedVersion(content))
- {
- LLSyntaxIdLSL::getInstance()->setKeywordsXml(content);
-
- cacheFile(content);
- LLSyntaxIdLSL::getInstance()->handleFileFetched(mFileSpec);
- }
- else
- {
- LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("SyntaxLSL") << "Syntax file '" << mFileSpec << "' contains invalid LLSD." << LL_ENDL;
- }
- }
-
- void cacheFile(const LLSD& content_ref)
- {
- std::stringstream str;
- LLSDSerialize::toXML(content_ref, str);
- const std::string xml = str.str();
-
- // save the str to disk, usually to the cache.
- llofstream file(mFileSpec.c_str(), std::ios_base::out);
- file.write(xml.c_str(), str.str().size());
- file.close();
-
- LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << mFileSpec << "'" << LL_ENDL;
- }
-
-private:
- std::string mFileSpec;
-};
-
-//-----------------------------------------------------------------------------
// LLSyntaxIdLSL
//-----------------------------------------------------------------------------
const std::string SYNTAX_ID_CAPABILITY_NAME = "LSLSyntax";
@@ -166,13 +107,72 @@ bool LLSyntaxIdLSL::syntaxIdChanged()
//-----------------------------------------------------------------------------
void LLSyntaxIdLSL::fetchKeywordsFile(const std::string& filespec)
{
- mInflightFetches.push_back(filespec);
- LLHTTPClient::get(mCapabilityURL,
- new fetchKeywordsFileResponder(filespec),
- LLSD(), 30.f);
+ LLCoros::instance().launch("LLSyntaxIdLSL::fetchKeywordsFileCoro",
+ boost::bind(&LLSyntaxIdLSL::fetchKeywordsFileCoro, this, mCapabilityURL, filespec));
LL_DEBUGS("SyntaxLSL") << "LSLSyntaxId capability URL is: " << mCapabilityURL << ". Filename to use is: '" << filespec << "'." << LL_ENDL;
}
+//-----------------------------------------------------------------------------
+// fetchKeywordsFileCoro
+//-----------------------------------------------------------------------------
+void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ std::pair<std::set<std::string>::iterator, bool> insrt = mInflightFetches.insert(fileSpec);
+ if (!insrt.second)
+ {
+ LL_WARNS("SyntaxLSL") << "Already downloading keyword file called \"" << fileSpec << "\"." << LL_ENDL;
+ return;
+ }
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ mInflightFetches.erase(fileSpec);
+
+ if (!status)
+ {
+ LL_WARNS("SyntaxLSL") << "Failed to fetch syntax file \"" << fileSpec << "\"" << LL_ENDL;
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+
+ if (isSupportedVersion(result))
+ {
+ setKeywordsXml(result);
+ cacheFile(fileSpec, result);
+ loadKeywordsIntoLLSD();
+ }
+ else
+ {
+ LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL;
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// cacheFile
+//-----------------------------------------------------------------------------
+void LLSyntaxIdLSL::cacheFile(const std::string &fileSpec, const LLSD& content_ref)
+{
+ std::stringstream str;
+ LLSDSerialize::toXML(content_ref, str);
+ const std::string xml = str.str();
+
+ // save the str to disk, usually to the cache.
+ llofstream file(fileSpec.c_str(), std::ios_base::out);
+ file.write(xml.c_str(), str.str().size());
+ file.close();
+
+ LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << fileSpec << "'" << LL_ENDL;
+}
//-----------------------------------------------------------------------------
// initialize
@@ -260,8 +260,8 @@ void LLSyntaxIdLSL::loadDefaultKeywordsIntoLLSD()
// loadKeywordsFileIntoLLSD
//-----------------------------------------------------------------------------
/**
- * @brief Load xml serialised LLSD
- * @desc Opens the specified filespec and attempts to deserialise the
+ * @brief Load xml serialized LLSD
+ * @desc Opens the specified filespec and attempts to deserializes the
* contained data to the specified LLSD object. indicate success/failure with
* sLoaded/sLoadFailed members.
*/
@@ -276,7 +276,7 @@ void LLSyntaxIdLSL::loadKeywordsIntoLLSD()
{
if (isSupportedVersion(content))
{
- LL_DEBUGS("SyntaxLSL") << "Deserialised: " << mFullFileSpec << LL_ENDL;
+ LL_DEBUGS("SyntaxLSL") << "Deserialized: " << mFullFileSpec << LL_ENDL;
}
else
{
@@ -317,12 +317,6 @@ void LLSyntaxIdLSL::handleCapsReceived(const LLUUID& region_uuid)
}
}
-void LLSyntaxIdLSL::handleFileFetched(const std::string& filepath)
-{
- mInflightFetches.remove(filepath);
- loadKeywordsIntoLLSD();
-}
-
boost::signals2::connection LLSyntaxIdLSL::addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb)
{
return mSyntaxIDChangedSignal.connect(cb);
diff --git a/indra/newview/llsyntaxid.h b/indra/newview/llsyntaxid.h
index 504fb0997e..0afa6dc04b 100644
--- a/indra/newview/llsyntaxid.h
+++ b/indra/newview/llsyntaxid.h
@@ -31,6 +31,8 @@
#include "llviewerprecompiledheaders.h"
#include "llsingleton.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class fetchKeywordsFileResponder;
@@ -40,7 +42,7 @@ class LLSyntaxIdLSL : public LLSingleton<LLSyntaxIdLSL>
friend class fetchKeywordsFileResponder;
private:
- std::list<std::string> mInflightFetches;
+ std::set<std::string> mInflightFetches;
typedef boost::signals2::signal<void()> syntax_id_changed_signal_t;
syntax_id_changed_signal_t mSyntaxIDChangedSignal;
boost::signals2::connection mRegionChangedCallback;
@@ -49,13 +51,15 @@ private:
bool isSupportedVersion(const LLSD& content);
void handleRegionChanged();
void handleCapsReceived(const LLUUID& region_uuid);
- void handleFileFetched(const std::string& filepath);
void setKeywordsXml(const LLSD& content) { mKeywordsXml = content; };
void buildFullFileSpec();
void fetchKeywordsFile(const std::string& filespec);
void loadDefaultKeywordsIntoLLSD();
void loadKeywordsIntoLLSD();
-
+
+ void fetchKeywordsFileCoro(std::string url, std::string fileSpec);
+ void cacheFile(const std::string &fileSpec, const LLSD& content_ref);
+
std::string mCapabilityURL;
std::string mFullFileSpec;
ELLPath mFilePath;
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index fab4203ec3..30d90431ea 100755
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -35,7 +35,6 @@
#include "lltexturefetch.h"
#include "lldir.h"
-#include "llhttpclient.h"
#include "llhttpconstants.h"
#include "llimage.h"
#include "llimagej2c.h"
@@ -1329,11 +1328,11 @@ bool LLTextureFetchWorker::doWork(S32 param)
static LLCachedControl<bool> use_http(gSavedSettings, "ImagePipelineUseHTTP", true);
-// if (mHost != LLHost::invalid) get_url = false;
+// if (mHost.isInvalid()) get_url = false;
if ( use_http && mCanUseHTTP && mUrl.empty())//get http url.
{
LLViewerRegion* region = NULL;
- if (mHost == LLHost::invalid)
+ if (mHost.isInvalid())
region = gAgent.getRegion();
else
region = LLWorld::getInstance()->getRegion(mHost);
@@ -1558,7 +1557,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
// 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;
+ LLCore::HttpOptions::ptr_t options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions;
if (disable_range_req)
{
// 'Range:' requests may be disabled in which case all HTTP
@@ -2510,11 +2509,11 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
mTotalHTTPRequests(0),
mQAMode(qa_mode),
mHttpRequest(NULL),
- mHttpOptions(NULL),
- mHttpOptionsWithHeaders(NULL),
- mHttpHeaders(NULL),
+ mHttpOptions(),
+ mHttpOptionsWithHeaders(),
+ mHttpHeaders(),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
- mHttpMetricsHeaders(NULL),
+ mHttpMetricsHeaders(),
mHttpMetricsPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mTotalCacheReadCount(0U),
mTotalCacheWriteCount(0U),
@@ -2529,13 +2528,13 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
mHttpRequest = new LLCore::HttpRequest;
- mHttpOptions = new LLCore::HttpOptions;
- mHttpOptionsWithHeaders = new LLCore::HttpOptions;
+ mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+ mHttpOptionsWithHeaders = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
mHttpOptionsWithHeaders->setWantHeaders(true);
- mHttpHeaders = new LLCore::HttpHeaders;
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);
mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_TEXTURE);
- mHttpMetricsHeaders = new LLCore::HttpHeaders;
+ mHttpMetricsHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpMetricsHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
mHttpMetricsPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_REPORTING);
mHttpHighWater = HTTP_NONPIPE_REQUESTS_HIGH_WATER;
@@ -2569,30 +2568,6 @@ LLTextureFetch::~LLTextureFetch()
delete req;
}
- if (mHttpOptions)
- {
- mHttpOptions->release();
- mHttpOptions = NULL;
- }
-
- if (mHttpOptionsWithHeaders)
- {
- mHttpOptionsWithHeaders->release();
- mHttpOptionsWithHeaders = NULL;
- }
-
- if (mHttpHeaders)
- {
- mHttpHeaders->release();
- mHttpHeaders = NULL;
- }
-
- if (mHttpMetricsHeaders)
- {
- mHttpMetricsHeaders->release();
- mHttpMetricsHeaders = NULL;
- }
-
mHttpWaitResource.clear();
delete mHttpRequest;
@@ -3249,7 +3224,7 @@ void LLTextureFetch::sendRequestListToSimulators()
{
LLHost host = iter1->first;
// invalid host = use agent host
- if (host == LLHost::invalid)
+ if (host.isInvalid())
{
host = gAgent.getRegionHost();
}
@@ -3329,7 +3304,7 @@ void LLTextureFetch::sendRequestListToSimulators()
iter1 != mCancelQueue.end(); ++iter1)
{
LLHost host = iter1->first;
- if (host == LLHost::invalid)
+ if (host.isInvalid())
{
host = gAgent.getRegionHost();
}
@@ -4044,7 +4019,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
report_priority,
mCapsURL,
sd,
- NULL,
+ LLCore::HttpOptions::ptr_t(),
fetcher->getMetricsHeaders(),
handler);
LLTextureFetch::svMetricsDataBreak = false;
@@ -4163,7 +4138,7 @@ LLTextureFetchDebugger::LLTextureFetchDebugger(LLTextureFetch* fetcher, LLTextur
mFetcher(fetcher),
mTextureCache(cache),
mImageDecodeThread(imagedecodethread),
- mHttpHeaders(NULL),
+ mHttpHeaders(),
mHttpPolicyClass(fetcher->getPolicyClass()),
mNbCurlCompleted(0),
mTempIndex(0),
@@ -4177,11 +4152,6 @@ LLTextureFetchDebugger::~LLTextureFetchDebugger()
mFetchingHistory.clear();
mStopDebug = TRUE;
tryToStopDebug();
- if (mHttpHeaders)
- {
- mHttpHeaders->release();
- mHttpHeaders = NULL;
- }
}
void LLTextureFetchDebugger::init()
@@ -4226,7 +4196,7 @@ void LLTextureFetchDebugger::init()
if (! mHttpHeaders)
{
- mHttpHeaders = new LLCore::HttpHeaders;
+ mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders);
mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C);
}
}
@@ -4626,7 +4596,7 @@ S32 LLTextureFetchDebugger::fillCurlQueue()
texture_url,
0,
requestedSize,
- NULL,
+ LLCore::HttpOptions::ptr_t(),
mHttpHeaders,
this);
if (LLCORE_HTTP_HANDLE_INVALID != handle)
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 27779a31e0..50233eee5e 100755
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -37,7 +37,6 @@
#include "lltextureinfo.h"
#include "llapr.h"
#include "llimageworker.h"
-#include "llcurl.h"
#include "httprequest.h"
#include "httpoptions.h"
#include "httpheaders.h"
@@ -177,7 +176,7 @@ public:
// to do that to hold a reference for any length of time.
//
// Threads: T*
- LLCore::HttpHeaders * getMetricsHeaders() const { return mHttpMetricsHeaders; }
+ LLCore::HttpHeaders::ptr_t getMetricsHeaders() const { return mHttpMetricsHeaders; }
// Threads: T*
LLCore::HttpRequest::policy_t getMetricsPolicyClass() const { return mHttpMetricsPolicyClass; }
@@ -354,11 +353,11 @@ private:
// to make our HTTP requests. These replace the various
// LLCurl interfaces used in the past.
LLCore::HttpRequest * mHttpRequest; // Ttf
- LLCore::HttpOptions * mHttpOptions; // Ttf
- LLCore::HttpOptions * mHttpOptionsWithHeaders; // Ttf
- LLCore::HttpHeaders * mHttpHeaders; // Ttf
+ LLCore::HttpOptions::ptr_t mHttpOptions; // Ttf
+ LLCore::HttpOptions::ptr_t mHttpOptionsWithHeaders; // Ttf
+ LLCore::HttpHeaders::ptr_t mHttpHeaders; // Ttf
LLCore::HttpRequest::policy_t mHttpPolicyClass; // T*
- LLCore::HttpHeaders * mHttpMetricsHeaders; // Ttf
+ LLCore::HttpHeaders::ptr_t mHttpMetricsHeaders; // Ttf
LLCore::HttpRequest::policy_t mHttpMetricsPolicyClass; // T*
S32 mHttpHighWater; // Ttf
S32 mHttpLowWater; // Ttf
@@ -510,7 +509,7 @@ private:
LLTextureFetch* mFetcher;
LLTextureCache* mTextureCache;
LLImageDecodeThread* mImageDecodeThread;
- LLCore::HttpHeaders* mHttpHeaders;
+ LLCore::HttpHeaders::ptr_t mHttpHeaders;
LLCore::HttpRequest::policy_t mHttpPolicyClass;
S32 mNumFetchedTextures;
diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp
index ca42d710f8..8ded148e17 100755
--- a/indra/newview/lltexturestats.cpp
+++ b/indra/newview/lltexturestats.cpp
@@ -30,8 +30,8 @@
#include "llagent.h"
#include "lltexturefetch.h"
#include "lltexturestats.h"
-#include "lltexturestatsuploader.h"
#include "llviewerregion.h"
+#include "llcorehttputil.h"
void send_texture_stats_to_sim(const LLSD &texture_stats)
{
@@ -49,6 +49,16 @@ void send_texture_stats_to_sim(const LLSD &texture_stats)
std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats");
LL_INFOS() << "uploading texture stats data to simulator" << LL_ENDL;
- LLTextureStatsUploader::uploadStatsToSimulator(texture_cap_url, texture_stats);
+
+ if (texture_cap_url != "")
+ {
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(texture_cap_url, texture_stats,
+ "Texture statistics posted to sim.", "Error posting texture statistics to sim");
+ }
+ else
+ {
+ LL_INFOS() << "Not sending texture stats: " << texture_stats
+ << " as there is no cap url." << LL_ENDL;
+ }
}
diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp
deleted file mode 100755
index c4809bc8e7..0000000000
--- a/indra/newview/lltexturestatsuploader.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file lltexturerstats.cpp
- * @brief texture stats upload class
- *
- * $LicenseInfo:firstyear=2002&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 "lltexturestatsuploader.h"
-
-#include "llhttpclient.h"
-
-
-// static
-void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats)
-{
- if ( texture_cap_url != "" )
- {
- LLHTTPClient::post(texture_cap_url, texture_stats, NULL);
- }
- else
- {
- LL_INFOS() << "Not sending texture stats: "
- << texture_stats
- << " as there is no cap url."
- << LL_ENDL;
- }
-}
-
diff --git a/indra/newview/lltexturestatsuploader.h b/indra/newview/lltexturestatsuploader.h
deleted file mode 100755
index ac268c2516..0000000000
--- a/indra/newview/lltexturestatsuploader.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * @file lltexturestatsuploader.h
- * @brief Class to send the texture stats to the simulatore
- *
- * $LicenseInfo:firstyear=2009&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_LLTEXTURESTATSUPLOADER_H
-#define LL_LLTEXTURESTATSUPLOADER_H
-
-#include "llappviewer.h"
-
-// utility functions to capture data on texture download speeds and send to simulator periodically
-
-class LLTextureStatsUploader
-{
-public:
- static void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats);
-};
-
-#endif // LL_LLTEXTURESTATSUPLOADER_H
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 81fbc471b3..8f482c5dca 100755
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -821,21 +821,6 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop,
if (!handled)
{
- // *TODO: Suppress the "outbox" case once "marketplace" is used everywhere for everyone
- // Disallow drag and drop to 3D from the outbox
- const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- if (outbox_id.notNull())
- {
- for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++)
- {
- if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id))
- {
- *acceptance = ACCEPT_NO;
- mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld");
- return;
- }
- }
- }
// Disallow drag and drop to 3D from the marketplace
const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);
if (marketplacelistings_id.notNull())
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index c0ba0a1f39..76fba82ef6 100755
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -35,31 +35,254 @@
#include "llui.h"
#include "llversioninfo.h"
#include "llviewercontrol.h"
-
+#include "llcoros.h"
#include "reader.h"
+#include "llcorehttputil.h"
+
+
+/**
+* Handler of an HTTP machine translation service.
+*
+* Derived classes know the service URL
+* and how to parse the translation result.
+*/
+class LLTranslationAPIHandler
+{
+public:
+ typedef std::pair<std::string, std::string> LanguagePair_t;
+
+ /**
+ * Get URL for translation of the given string.
+ *
+ * Sending HTTP GET request to the URL will initiate translation.
+ *
+ * @param[out] url Place holder for the result.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param text Text to translate.
+ */
+ virtual std::string getTranslateURL(
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const = 0;
+
+ /**
+ * Get URL to verify the given API key.
+ *
+ * Sending request to the URL verifies the key.
+ * Positive HTTP response (code 200) means that the key is valid.
+ *
+ * @param[out] url Place holder for the URL.
+ * @param[in] key Key to verify.
+ */
+ virtual std::string getKeyVerificationURL(
+ const std::string &key) const = 0;
+
+ /**
+ * Parse translation response.
+ *
+ * @param[in,out] status HTTP status. May be modified while parsing.
+ * @param body Response text.
+ * @param[out] translation Translated text.
+ * @param[out] detected_lang Detected source language. May be empty.
+ * @param[out] err_msg Error message (in case of error).
+ */
+ virtual bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const = 0;
+
+ /**
+ * @return if the handler is configured to function properly
+ */
+ virtual bool isConfigured() const = 0;
+
+ virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0;
+ virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
+
+
+ virtual ~LLTranslationAPIHandler() {}
+
+ void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc);
+ void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure);
+};
+
+void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
+{
+ LLCoros::instance().launch("Translation", boost::bind(&LLTranslationAPIHandler::translateMessageCoro,
+ this, fromTo, msg, success, failure));
+
+}
+
+
+void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+
+ std::string user_agent = llformat("%s %d.%d.%d (%d)",
+ LLVersionInfo::getChannel().c_str(),
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ LLVersionInfo::getBuild());
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+ httpOpts->setFollowRedirects(true);
+
+ std::string url = this->getKeyVerificationURL(key);
+ if (url.empty())
+ {
+ LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
+ return;
+ }
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ bool bOk = true;
+ if (!status)
+ bOk = false;
+
+ if (!fnc.empty())
+ fnc(service, bOk);
+}
+
+void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg,
+ LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+
+ std::string user_agent = llformat("%s %d.%d.%d (%d)",
+ LLVersionInfo::getChannel().c_str(),
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ LLVersionInfo::getBuild());
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
+
+ std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg);
+ if (url.empty())
+ {
+ LL_INFOS("Translate") << "No translation URL" << LL_ENDL;
+ return;
+ }
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ std::string translation, detected_lang, err_msg;
+
+ int parseResult = status.getType();
+ if (this->parseResponse(parseResult, result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asString(),
+ translation, detected_lang, err_msg))
+ {
+ // Fix up the response
+ LLStringUtil::replaceString(translation, "&lt;", "<");
+ LLStringUtil::replaceString(translation, "&gt;", ">");
+ LLStringUtil::replaceString(translation, "&quot;", "\"");
+ LLStringUtil::replaceString(translation, "&#39;", "'");
+ LLStringUtil::replaceString(translation, "&amp;", "&");
+ LLStringUtil::replaceString(translation, "&apos;", "'");
+
+ if (!success.empty())
+ success(translation, detected_lang);
+ }
+ else
+ {
+ if (err_msg.empty())
+ {
+ err_msg = LLTrans::getString("TranslationResponseParseError");
+ }
+
+ LL_WARNS() << "Translation request failed: " << err_msg << LL_ENDL;
+ if (!failure.empty())
+ failure(status, err_msg);
+ }
+
+
+}
+
+//=========================================================================
+/// Google Translate v2 API handler.
+class LLGoogleTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLGoogleTranslationHandler);
+
+public:
+ /*virtual*/ std::string getTranslateURL(
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ std::string getKeyVerificationURL(
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
+
+ /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+
+private:
+ static void parseErrorResponse(
+ const Json::Value& root,
+ int& status,
+ std::string& err_msg);
+ static bool parseTranslation(
+ const Json::Value& root,
+ std::string& translation,
+ std::string& detected_lang);
+ static std::string getAPIKey();
+
+};
+
+//-------------------------------------------------------------------------
// virtual
-void LLGoogleTranslationHandler::getTranslateURL(
- std::string &url,
+std::string LLGoogleTranslationHandler::getTranslateURL(
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const
{
- url = std::string("https://www.googleapis.com/language/translate/v2?key=")
+ std::string url = std::string("https://www.googleapis.com/language/translate/v2?key=")
+ getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang;
if (!from_lang.empty())
{
url += "&source=" + from_lang;
}
+ return url;
}
// virtual
-void LLGoogleTranslationHandler::getKeyVerificationURL(
- std::string& url,
+std::string LLGoogleTranslationHandler::getKeyVerificationURL(
const std::string& key) const
{
- url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+ std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+ key + "&target=en";
+ return url;
}
// virtual
@@ -154,28 +377,66 @@ std::string LLGoogleTranslationHandler::getAPIKey()
return gSavedSettings.getString("GoogleTranslateAPIKey");
}
+/*virtual*/
+void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
+{
+ LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
+ this, LLTranslate::SERVICE_GOOGLE, key, fnc));
+}
+
+
+//=========================================================================
+/// Microsoft Translator v2 API handler.
+class LLBingTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLBingTranslationHandler);
+
+public:
+ /*virtual*/ std::string getTranslateURL(
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ std::string getKeyVerificationURL(
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
+
+ /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc);
+private:
+ static std::string getAPIKey();
+ static std::string getAPILanguageCode(const std::string& lang);
+
+};
+
+//-------------------------------------------------------------------------
// virtual
-void LLBingTranslationHandler::getTranslateURL(
- std::string &url,
+std::string LLBingTranslationHandler::getTranslateURL(
const std::string &from_lang,
const std::string &to_lang,
const std::string &text) const
{
- url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
+ std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
+ getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang);
if (!from_lang.empty())
{
url += "&from=" + getAPILanguageCode(from_lang);
}
+ return url;
}
+
// virtual
-void LLBingTranslationHandler::getKeyVerificationURL(
- std::string& url,
+std::string LLBingTranslationHandler::getKeyVerificationURL(
const std::string& key) const
{
- url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
+ std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
+ key;
+ return url;
}
// virtual
@@ -242,96 +503,31 @@ std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang
return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese
}
-LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang)
-: mFromLang(from_lang)
-, mToLang(to_lang)
-, mHandler(LLTranslate::getPreferredHandler())
+/*virtual*/
+void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc)
{
+ LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro,
+ this, LLTranslate::SERVICE_BING, key, fnc));
}
-// virtual
-void LLTranslate::TranslationReceiver::completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+//=========================================================================
+/*static*/
+void LLTranslate::translateMessage(const std::string &from_lang, const std::string &to_lang,
+ const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure)
{
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
-
- const std::string body = strstrm.str();
- std::string translation, detected_lang, err_msg;
- 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))
- {
- // Fix up the response
- LLStringUtil::replaceString(translation, "&lt;", "<");
- LLStringUtil::replaceString(translation, "&gt;",">");
- LLStringUtil::replaceString(translation, "&quot;","\"");
- LLStringUtil::replaceString(translation, "&#39;","'");
- LLStringUtil::replaceString(translation, "&amp;","&");
- LLStringUtil::replaceString(translation, "&apos;","'");
-
- handleResponse(translation, detected_lang);
- }
- else
- {
- if (err_msg.empty())
- {
- err_msg = LLTrans::getString("TranslationResponseParseError");
- }
+ LLTranslationAPIHandler& handler = getPreferredHandler();
- LL_WARNS() << "Translation request failed: " << err_msg << LL_ENDL;
- handleFailure(status, err_msg);
- }
+ handler.translateMessage(LLTranslationAPIHandler::LanguagePair_t(from_lang, to_lang), mesg, success, failure);
}
-LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service)
-: mService(service)
+/*static*/
+void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc)
{
-}
+ LLTranslationAPIHandler& handler = getHandler(service);
-LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
-{
- return mService;
+ handler.verifyKey(key, fnc);
}
-// virtual
-void LLTranslate::KeyVerificationReceiver::completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
-{
- bool ok = (getStatus() == HTTP_OK);
- setVerificationStatus(ok);
-}
-
-//static
-void LLTranslate::translateMessage(
- TranslationReceiverPtr &receiver,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &mesg)
-{
- std::string url;
- receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg);
-
- LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL;
- sendRequest(url, receiver);
-}
-
-// static
-void LLTranslate::verifyKey(
- KeyVerificationReceiverPtr& receiver,
- const std::string& key)
-{
- std::string url;
- const LLTranslationAPIHandler& handler = getHandler(receiver->getService());
- handler.getKeyVerificationURL(url, key);
-
- LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL;
- sendRequest(url, receiver);
-}
//static
std::string LLTranslate::getTranslateLanguage()
@@ -352,7 +548,7 @@ bool LLTranslate::isTranslationConfigured()
}
// static
-const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
+LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
{
EService service = SERVICE_BING;
@@ -366,7 +562,7 @@ const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
}
// static
-const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
+LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
{
static LLGoogleTranslationHandler google;
static LLBingTranslationHandler bing;
@@ -378,25 +574,3 @@ const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
return bing;
}
-
-// static
-void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder)
-{
- static const float REQUEST_TIMEOUT = 5;
- static LLSD sHeader;
-
- if (!sHeader.size())
- {
- std::string user_agent = llformat("%s %d.%d.%d (%d)",
- LLVersionInfo::getChannel().c_str(),
- LLVersionInfo::getMajor(),
- LLVersionInfo::getMinor(),
- LLVersionInfo::getPatch(),
- LLVersionInfo::getBuild());
-
- 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 972274714a..bf431cdfbb 100755
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -27,136 +27,15 @@
#ifndef LL_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
-#include "llhttpclient.h"
#include "llbufferstream.h"
+#include <boost/function.hpp>
namespace Json
{
class Value;
}
-/**
- * Handler of an HTTP machine translation service.
- *
- * Derived classes know the service URL
- * and how to parse the translation result.
- */
-class LLTranslationAPIHandler
-{
-public:
- /**
- * Get URL for translation of the given string.
- *
- * Sending HTTP GET request to the URL will initiate translation.
- *
- * @param[out] url Place holder for the result.
- * @param from_lang Source language. Leave empty for auto-detection.
- * @param to_lang Target language.
- * @param text Text to translate.
- */
- virtual void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const = 0;
-
- /**
- * Get URL to verify the given API key.
- *
- * Sending request to the URL verifies the key.
- * Positive HTTP response (code 200) means that the key is valid.
- *
- * @param[out] url Place holder for the URL.
- * @param[in] key Key to verify.
- */
- virtual void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const = 0;
-
- /**
- * Parse translation response.
- *
- * @param[in,out] status HTTP status. May be modified while parsing.
- * @param body Response text.
- * @param[out] translation Translated text.
- * @param[out] detected_lang Detected source language. May be empty.
- * @param[out] err_msg Error message (in case of error).
- */
- virtual bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const = 0;
-
- /**
- * @return if the handler is configured to function properly
- */
- virtual bool isConfigured() const = 0;
-
- virtual ~LLTranslationAPIHandler() {}
-};
-
-/// Google Translate v2 API handler.
-class LLGoogleTranslationHandler : public LLTranslationAPIHandler
-{
- LOG_CLASS(LLGoogleTranslationHandler);
-
-public:
- /*virtual*/ void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const;
- /*virtual*/ void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const;
- /*virtual*/ bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const;
- /*virtual*/ bool isConfigured() const;
-
-private:
- static void parseErrorResponse(
- const Json::Value& root,
- int& status,
- std::string& err_msg);
- static bool parseTranslation(
- const Json::Value& root,
- std::string& translation,
- std::string& detected_lang);
- static std::string getAPIKey();
-};
-
-/// Microsoft Translator v2 API handler.
-class LLBingTranslationHandler : public LLTranslationAPIHandler
-{
- LOG_CLASS(LLBingTranslationHandler);
-
-public:
- /*virtual*/ void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const;
- /*virtual*/ void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const;
- /*virtual*/ bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const;
- /*virtual*/ bool isConfigured() const;
-private:
- static std::string getAPIKey();
- static std::string getAPILanguageCode(const std::string& lang);
-};
-
+class LLTranslationAPIHandler;
/**
* Entry point for machine translation services.
*
@@ -180,84 +59,9 @@ public :
SERVICE_GOOGLE,
} EService;
- /**
- * Subclasses are supposed to handle translation results (e.g. show them in chat)
- */
- class TranslationReceiver: public LLHTTPClient::Responder
- {
- public:
-
- /**
- * Using mHandler, parse incoming response.
- *
- * Calls either handleResponse() or handleFailure()
- * depending on the HTTP status code and parsing success.
- *
- * @see handleResponse()
- * @see handleFailure()
- * @see mHandler
- */
- /*virtual*/ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
-
- protected:
- friend class LLTranslate;
-
- /// Remember source and target languages for subclasses to be able to filter inappropriate results.
- TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
-
- /// Override point to handle successful translation.
- virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
-
- /// Override point to handle unsuccessful translation.
- virtual void handleFailure(int status, const std::string& err_msg) = 0;
-
- std::string mFromLang;
- std::string mToLang;
- const LLTranslationAPIHandler& mHandler;
- };
-
- /**
- * Subclasses are supposed to handle API key verification result.
- */
- class KeyVerificationReceiver: public LLHTTPClient::Responder
- {
- public:
- EService getService() const;
-
- protected:
- /**
- * Save the translation service the key belongs to.
- *
- * Subclasses need to know it.
- *
- * @see getService()
- */
- KeyVerificationReceiver(EService service);
-
- /**
- * Parse verification response.
- *
- * Calls setVerificationStatus() with the verification status,
- * which is true if HTTP status code is 200.
- *
- * @see setVerificationStatus()
- */
- /*virtual*/ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
-
- /**
- * Override point for subclasses to handle key verification status.
- */
- virtual void setVerificationStatus(bool ok) = 0;
-
- EService mService;
- };
-
- typedef LLPointer<TranslationReceiver> TranslationReceiverPtr;
- typedef LLPointer<KeyVerificationReceiver> KeyVerificationReceiverPtr;
+ typedef boost::function<void(EService, bool)> KeyVerificationResult_fn;
+ typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn;
+ typedef boost::function<void(int, std::string)> TranslationFailure_fn;
/**
* Translate given text.
@@ -267,15 +71,15 @@ public :
* @param to_lang Target language.
* @param mesg Text to translate.
*/
- static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
+ static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure);
- /**
+ /**
* Verify given API key of a translation service.
*
* @param receiver Object to pass verification result to.
* @param key Key to verify.
*/
- static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
+ static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc);
/**
* @return translation target language
@@ -288,9 +92,8 @@ public :
static bool isTranslationConfigured();
private:
- static const LLTranslationAPIHandler& getPreferredHandler();
- static const LLTranslationAPIHandler& getHandler(EService service);
- static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder);
+ static LLTranslationAPIHandler& getPreferredHandler();
+ static LLTranslationAPIHandler& getHandler(EService service);
};
#endif
diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp
index e983bc883f..9b7c13b57d 100644
--- a/indra/newview/lltwitterconnect.cpp
+++ b/indra/newview/lltwitterconnect.cpp
@@ -32,7 +32,6 @@
#include "llagent.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcommandhandler.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llurlaction.h"
#include "llimagepng.h"
@@ -43,6 +42,7 @@
#include "llfloaterwebcontent.h"
#include "llfloaterreg.h"
+#include "llcorehttputil.h"
boost::scoped_ptr<LLEventPump> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState"));
boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo"));
@@ -67,228 +67,305 @@ void toast_user_for_twitter_success()
///////////////////////////////////////////////////////////////////////////////
//
-class LLTwitterConnectResponder : public LLHTTPClient::Responder
+void LLTwitterConnect::twitterConnectCoro(std::string requestToken, std::string oauthVerifier)
{
- LOG_CLASS(LLTwitterConnectResponder);
-public:
-
- LLTwitterConnectResponder()
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD body;
+ if (!requestToken.empty())
+ body["request_token"] = requestToken;
+ if (!oauthVerifier.empty())
+ body["oauth_verifier"] = oauthVerifier;
+
+ LLSD result = httpAdapter->putAndSuspend(httpRequest, getTwitterConnectURL("/connection"), body, httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
{
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+ if ( status == LLCore::HttpStatus(HTTP_FOUND) )
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openTwitterWeb(location);
+ }
+ }
+ else
+ {
+ LL_WARNS("TwitterConnect") << "Connection failed " << status.toString() << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+ log_twitter_connect_error("Connect", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
}
-
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
- }
-
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse()
- << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- else
- {
- LLTwitterConnect::instance().openTwitterWeb(location);
- }
- }
- else
- {
- LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
- const LLSD& content = getContent();
- log_twitter_connect_error("Connect", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ else
+ {
+ LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLTwitterShareResponder : public LLHTTPClient::Responder
+bool LLTwitterConnect::testShareStatus(LLSD &result)
{
- LOG_CLASS(LLTwitterShareResponder);
-public:
-
- LLTwitterShareResponder()
- {
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTING);
- }
-
- /* virtual */ void httpSuccess()
- {
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status)
+ return true;
+
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openTwitterWeb(location);
+ }
+ }
+ if (status == LLCore::HttpStatus(HTTP_NOT_FOUND))
+ {
+ LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL;
+ connectToTwitter();
+ }
+ else
+ {
+ LL_WARNS("TwitterConnect") << "HTTP Status error " << status.toString() << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED);
+ log_twitter_connect_error("Share", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ return false;
+}
+
+void LLTwitterConnect::twitterShareCoro(std::string route, LLSD share)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL(route, true), share, httpOpts);
+
+ if (testShareStatus(result))
+ {
toast_user_for_twitter_success();
- LL_DEBUGS("TwitterConnect") << "Post successful. " << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTED);
- }
-
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse()
- << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- else
- {
- LLTwitterConnect::instance().openTwitterWeb(location);
- }
- }
- else if ( HTTP_NOT_FOUND == getStatus() )
- {
- LLTwitterConnect::instance().connectToTwitter();
- }
- else
- {
- LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED);
- const LLSD& content = getContent();
- log_twitter_connect_error("Share", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_POSTED);
+ }
+}
+
+void LLTwitterConnect::twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ std::string imageFormat;
+ if (dynamic_cast<LLImagePNG*>(image.get()))
+ {
+ imageFormat = "png";
+ }
+ else if (dynamic_cast<LLImageJPEG*>(image.get()))
+ {
+ imageFormat = "jpg";
+ }
+ else
+ {
+ LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL;
+ return;
+ }
+
+ // All this code is mostly copied from LLWebProfile::post()
+ const std::string boundary = "----------------------------0123abcdefab";
+
+ std::string contentType = "multipart/form-data; boundary=" + boundary;
+ httpHeaders->append("Content-Type", contentType.c_str());
+
+ LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); //
+ LLCore::BufferArrayStream body(raw.get());
+
+ // *NOTE: The order seems to matter.
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"status\"\r\n\r\n"
+ << status << "\r\n";
+
+ body << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
+ << "Content-Type: image/" << imageFormat << "\r\n\r\n";
+
+ // Insert the image data.
+ // *FIX: Treating this as a string will probably screw it up ...
+ U8* image_data = image->getData();
+ for (S32 i = 0; i < image->getDataSize(); ++i)
+ {
+ body << image_data[i];
+ }
+
+ body << "\r\n--" << boundary << "--\r\n";
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL("/share/photo", true), raw, httpOpts, httpHeaders);
+
+ if (testShareStatus(result))
+ {
+ toast_user_for_twitter_success();
+ LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_POSTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLTwitterDisconnectResponder : public LLHTTPClient::Responder
+void LLTwitterConnect::twitterDisconnectCoro()
{
- LOG_CLASS(LLTwitterDisconnectResponder);
-public:
-
- LLTwitterDisconnectResponder()
- {
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING);
- }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- void setUserDisconnected()
- {
- // Clear data
- LLTwitterConnect::instance().clearInfo();
+ httpOpts->setFollowRedirects(false);
- //Notify state change
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
- }
+ LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getTwitterConnectURL("/connection"), httpOpts);
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL;
- setUserDisconnected();
- }
-
- /* virtual */ void httpFailure()
- {
- //User not found so already disconnected
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- LL_DEBUGS("TwitterConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;
- setUserDisconnected();
- }
- else
- {
- LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED);
- const LLSD& content = getContent();
- log_twitter_connect_error("Disconnect", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND)))
+ {
+ LL_WARNS("TwitterConnect") << "Disconnect failed!" << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED);
+
+ log_twitter_connect_error("Disconnect", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
+ {
+ LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << LL_ENDL;
+ clearInfo();
+ setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLTwitterConnectedResponder : public LLHTTPClient::Responder
+void LLTwitterConnect::twitterConnectedCoro(bool autoConnect)
{
- LOG_CLASS(LLTwitterConnectedResponder);
-public:
-
- LLTwitterConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect)
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+
+ httpOpts->setFollowRedirects(false);
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/connection", true), httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ if (status == LLCore::HttpStatus(HTTP_NOT_FOUND))
+ {
+ LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL;
+ if (autoConnect)
+ {
+ connectToTwitter();
+ }
+ else
+ {
+ setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
+ }
+ }
+ else
+ {
+ LL_WARNS("TwitterConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL;
+
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
+ log_twitter_connect_error("Connected", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ }
+ else
{
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+ LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL;
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
}
-
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);
- }
-
- /* virtual */ void httpFailure()
- {
- // show the facebook login page if not connected yet
- if ( HTTP_NOT_FOUND == getStatus() )
- {
- LL_DEBUGS("TwitterConnect") << "Not connected. " << dumpResponse() << LL_ENDL;
- if (mAutoConnect)
- {
- LLTwitterConnect::instance().connectToTwitter();
- }
- else
- {
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED);
- }
- }
- else
- {
- LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED);
- const LLSD& content = getContent();
- log_twitter_connect_error("Connected", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-
-private:
- bool mAutoConnect;
-};
+
+}
///////////////////////////////////////////////////////////////////////////////
//
-class LLTwitterInfoResponder : public LLHTTPClient::Responder
+void LLTwitterConnect::twitterInfoCoro()
{
- LOG_CLASS(LLTwitterInfoResponder);
-public:
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
- /* virtual */ void httpSuccess()
- {
- LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL;
- LL_DEBUGS("TwitterConnect") << "Getting Twitter info successful. " << dumpResponse() << LL_ENDL;
- LLTwitterConnect::instance().storeInfo(getContent());
- }
-
- /* virtual */ void httpFailure()
- {
- if ( HTTP_FOUND == getStatus() )
- {
- const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (location.empty())
- {
- LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse()
- << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- else
- {
- LLTwitterConnect::instance().openTwitterWeb(location);
- }
- }
- else
- {
- LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL;
- const LLSD& content = getContent();
- log_twitter_connect_error("Info", getStatus(), getReason(),
- content.get("error_code"), content.get("error_description"));
- }
- }
-};
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/info", true), httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status == LLCore::HttpStatus(HTTP_FOUND))
+ {
+ std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION];
+ if (location.empty())
+ {
+ LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL;
+ }
+ else
+ {
+ openTwitterWeb(location);
+ }
+ }
+ else if (!status)
+ {
+ LL_WARNS("TwitterConnect") << "Twitter Info failed: " << status.toString() << LL_ENDL;
+ log_twitter_connect_error("Info", status.getStatus(), status.toString(),
+ result.get("error_code"), result.get("error_description"));
+ }
+ else
+ {
+ LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL;
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ storeInfo(result);
+ }
+}
///////////////////////////////////////////////////////////////////////////////
//
@@ -341,36 +418,32 @@ std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, boo
void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier)
{
- LLSD body;
- if (!request_token.empty())
- body["request_token"] = request_token;
- if (!oauth_verifier.empty())
- body["oauth_verifier"] = oauth_verifier;
-
- LLHTTPClient::put(getTwitterConnectURL("/connection"), body, new LLTwitterConnectResponder());
+ setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS);
+
+ LLCoros::instance().launch("LLTwitterConnect::twitterConnectCoro",
+ boost::bind(&LLTwitterConnect::twitterConnectCoro, this, request_token, oauth_verifier));
}
void LLTwitterConnect::disconnectFromTwitter()
{
- LLHTTPClient::del(getTwitterConnectURL("/connection"), new LLTwitterDisconnectResponder());
+ setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING);
+
+ LLCoros::instance().launch("LLTwitterConnect::twitterDisconnectCoro",
+ boost::bind(&LLTwitterConnect::twitterDisconnectCoro, this));
}
void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getTwitterConnectURL("/connection", true), new LLTwitterConnectedResponder(auto_connect),
- LLSD(), timeout, follow_redirects);
+ LLCoros::instance().launch("LLTwitterConnect::twitterConnectedCoro",
+ boost::bind(&LLTwitterConnect::twitterConnectedCoro, this, auto_connect));
}
void LLTwitterConnect::loadTwitterInfo()
{
if(mRefreshInfo)
{
- const bool follow_redirects = false;
- const F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- LLHTTPClient::get(getTwitterConnectURL("/info", true), new LLTwitterInfoResponder(),
- LLSD(), timeout, follow_redirects);
+ LLCoros::instance().launch("LLTwitterConnect::twitterInfoCoro",
+ boost::bind(&LLTwitterConnect::twitterInfoCoro, this));
}
}
@@ -379,62 +452,19 @@ void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::stri
LLSD body;
body["image"] = image_url;
body["status"] = status;
-
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::post(getTwitterConnectURL("/share/photo", true), body, new LLTwitterShareResponder());
+
+ setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+
+ LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro",
+ boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/photo", body));
}
void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status)
{
- std::string imageFormat;
- if (dynamic_cast<LLImagePNG*>(image.get()))
- {
- imageFormat = "png";
- }
- else if (dynamic_cast<LLImageJPEG*>(image.get()))
- {
- imageFormat = "jpg";
- }
- else
- {
- LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL;
- return;
- }
-
- // All this code is mostly copied from LLWebProfile::post()
- const std::string boundary = "----------------------------0123abcdefab";
-
- LLSD headers;
- headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+ setConnectionState(LLTwitterConnect::TWITTER_POSTING);
- std::ostringstream body;
-
- // *NOTE: The order seems to matter.
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"status\"\r\n\r\n"
- << status << "\r\n";
-
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n"
- << "Content-Type: image/" << imageFormat << "\r\n\r\n";
-
- // Insert the image data.
- // *FIX: Treating this as a string will probably screw it up ...
- U8* image_data = image->getData();
- for (S32 i = 0; i < image->getDataSize(); ++i)
- {
- body << image_data[i];
- }
-
- body << "\r\n--" << boundary << "--\r\n";
-
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = body.str().size();
- U8 *data = new U8[size];
- memcpy(data, body.str().data(), size);
-
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::postRaw(getTwitterConnectURL("/share/photo", true), data, size, new LLTwitterShareResponder(), headers);
+ LLCoros::instance().launch("LLTwitterConnect::twitterShareImageCoro",
+ boost::bind(&LLTwitterConnect::twitterShareImageCoro, this, image, status));
}
void LLTwitterConnect::updateStatus(const std::string& status)
@@ -442,8 +472,10 @@ void LLTwitterConnect::updateStatus(const std::string& status)
LLSD body;
body["status"] = status;
- // Note: we can use that route for different publish action. We should be able to use the same responder.
- LLHTTPClient::post(getTwitterConnectURL("/share/status", true), body, new LLTwitterShareResponder());
+ setConnectionState(LLTwitterConnect::TWITTER_POSTING);
+
+ LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro",
+ boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/status", body));
}
void LLTwitterConnect::storeInfo(const LLSD& info)
diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h
index c1df13f18c..be481a17c1 100644
--- a/indra/newview/lltwitterconnect.h
+++ b/indra/newview/lltwitterconnect.h
@@ -30,6 +30,8 @@
#include "llsingleton.h"
#include "llimage.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
class LLEventPump;
@@ -94,6 +96,14 @@ private:
static boost::scoped_ptr<LLEventPump> sStateWatcher;
static boost::scoped_ptr<LLEventPump> sInfoWatcher;
static boost::scoped_ptr<LLEventPump> sContentWatcher;
+
+ bool testShareStatus(LLSD &result);
+ void twitterConnectCoro(std::string requestToken, std::string oauthVerifier);
+ void twitterDisconnectCoro();
+ void twitterConnectedCoro(bool autoConnect);
+ void twitterInfoCoro();
+ void twitterShareCoro(std::string route, LLSD share);
+ void twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status);
};
#endif // LL_LLTWITTERCONNECT_H
diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp
deleted file mode 100755
index 69b9b1f9f1..0000000000
--- a/indra/newview/lluploadfloaterobservers.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * @file lluploadfloaterobservers.cpp
- * @brief LLUploadModelPermissionsResponder definition
- *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, 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 "lluploadfloaterobservers.h"
-
-LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer)
-:mObserverHandle(observer)
-{
-}
-
-void LLUploadModelPermissionsResponder::httpFailure()
-{
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- LLUploadPermissionsObserver* observer = mObserverHandle.get();
-
- if (observer)
- {
- observer->setPermissonsErrorStatus(getStatus(), getReason());
- }
-}
-
-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)
- {
- observer->onPermissionsReceived(content);
- }
-}
-
diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h
index 4ff4a827a5..15c3dad38e 100755
--- a/indra/newview/lluploadfloaterobservers.h
+++ b/indra/newview/lluploadfloaterobservers.h
@@ -28,7 +28,6 @@
#define LL_LLUPLOADFLOATEROBSERVERS_H
#include "llfloater.h"
-#include "llhttpclient.h"
#include "llhandle.h"
class LLUploadPermissionsObserver
@@ -79,18 +78,4 @@ protected:
LLRootHandle<LLWholeModelUploadObserver> mWholeModelUploadObserverHandle;
};
-
-class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLUploadModelPermissionsResponder);
-public:
- LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer);
-
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
-
- LLHandle<LLUploadPermissionsObserver> mObserverHandle;
-};
-
#endif /* LL_LLUPLOADFLOATEROBSERVERS_H */
diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp
new file mode 100644
index 0000000000..ea3d81c2f6
--- /dev/null
+++ b/indra/newview/llviewerassetupload.cpp
@@ -0,0 +1,839 @@
+/**
+* @file llviewerassetupload.cpp
+* @author optional
+* @brief brief description of the file
+*
+* $LicenseInfo:firstyear=2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2011, 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 "linden_common.h"
+#include "llviewertexturelist.h"
+#include "llimage.h"
+#include "lltrans.h"
+#include "lluuid.h"
+#include "llvorbisencode.h"
+#include "lluploaddialog.h"
+#include "llpreviewscript.h"
+#include "llnotificationsutil.h"
+#include "lleconomy.h"
+#include "llagent.h"
+#include "llfloaterreg.h"
+#include "llstatusbar.h"
+#include "llinventorypanel.h"
+#include "llsdutil.h"
+#include "llviewerassetupload.h"
+#include "llappviewer.h"
+#include "llviewerstats.h"
+#include "llvfile.h"
+#include "llgesturemgr.h"
+#include "llpreviewnotecard.h"
+#include "llpreviewgesture.h"
+#include "llcoproceduremanager.h"
+
+void dialog_refresh_all();
+
+LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId,
+ LLAssetType::EType assetType, std::string name, std::string description,
+ S32 compressionInfo, LLFolderType::EType destinationType,
+ LLInventoryType::EType inventoryType, U32 nextOWnerPerms,
+ U32 groupPerms, U32 everyonePerms, S32 expectedCost) :
+ mTransactionId(transactId),
+ mAssetType(assetType),
+ mName(name),
+ mDescription(description),
+ mCompressionInfo(compressionInfo),
+ mDestinationFolderType(destinationType),
+ mInventoryType(inventoryType),
+ mNextOwnerPerms(nextOWnerPerms),
+ mGroupPerms(groupPerms),
+ mEveryonePerms(everyonePerms),
+ mExpectedUploadCost(expectedCost),
+ mFolderId(LLUUID::null),
+ mItemId(LLUUID::null),
+ mAssetId(LLAssetID::null)
+{ }
+
+
+LLResourceUploadInfo::LLResourceUploadInfo(std::string name,
+ std::string description, S32 compressionInfo,
+ LLFolderType::EType destinationType, LLInventoryType::EType inventoryType,
+ U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost):
+ mName(name),
+ mDescription(description),
+ mCompressionInfo(compressionInfo),
+ mDestinationFolderType(destinationType),
+ mInventoryType(inventoryType),
+ mNextOwnerPerms(nextOWnerPerms),
+ mGroupPerms(groupPerms),
+ mEveryonePerms(everyonePerms),
+ mExpectedUploadCost(expectedCost),
+ mTransactionId(),
+ mAssetType(LLAssetType::AT_NONE),
+ mFolderId(LLUUID::null),
+ mItemId(LLUUID::null),
+ mAssetId(LLAssetID::null)
+{
+ mTransactionId.generate();
+}
+
+LLResourceUploadInfo::LLResourceUploadInfo(LLAssetID assetId, LLAssetType::EType assetType, std::string name) :
+ mAssetId(assetId),
+ mAssetType(assetType),
+ mName(name),
+ mDescription(),
+ mCompressionInfo(0),
+ mDestinationFolderType(LLFolderType::FT_NONE),
+ mInventoryType(LLInventoryType::IT_NONE),
+ mNextOwnerPerms(0),
+ mGroupPerms(0),
+ mEveryonePerms(0),
+ mExpectedUploadCost(0),
+ mTransactionId(),
+ mFolderId(LLUUID::null),
+ mItemId(LLUUID::null)
+{
+}
+
+LLSD LLResourceUploadInfo::prepareUpload()
+{
+ if (mAssetId.isNull())
+ generateNewAssetId();
+
+ incrementUploadStats();
+ assignDefaults();
+
+ return LLSD().with("success", LLSD::Boolean(true));
+}
+
+std::string LLResourceUploadInfo::getAssetTypeString() const
+{
+ return LLAssetType::lookup(mAssetType);
+}
+
+std::string LLResourceUploadInfo::getInventoryTypeString() const
+{
+ return LLInventoryType::lookup(mInventoryType);
+}
+
+LLSD LLResourceUploadInfo::generatePostBody()
+{
+ LLSD body;
+
+ body["folder_id"] = mFolderId;
+ body["asset_type"] = getAssetTypeString();
+ body["inventory_type"] = getInventoryTypeString();
+ body["name"] = mName;
+ body["description"] = mDescription;
+ body["next_owner_mask"] = LLSD::Integer(mNextOwnerPerms);
+ body["group_mask"] = LLSD::Integer(mGroupPerms);
+ body["everyone_mask"] = LLSD::Integer(mEveryonePerms);
+
+ return body;
+
+}
+
+void LLResourceUploadInfo::logPreparedUpload()
+{
+ LL_INFOS() << "*** Uploading: " << std::endl <<
+ "Type: " << LLAssetType::lookup(mAssetType) << std::endl <<
+ "UUID: " << mAssetId.asString() << std::endl <<
+ "Name: " << mName << std::endl <<
+ "Desc: " << mDescription << std::endl <<
+ "Expected Upload Cost: " << mExpectedUploadCost << std::endl <<
+ "Folder: " << mFolderId << std::endl <<
+ "Asset Type: " << LLAssetType::lookup(mAssetType) << LL_ENDL;
+}
+
+S32 LLResourceUploadInfo::getEconomyUploadCost()
+{
+ // Update L$ and ownership credit information
+ // since it probably changed on the server
+ if (getAssetType() == LLAssetType::AT_TEXTURE ||
+ getAssetType() == LLAssetType::AT_SOUND ||
+ getAssetType() == LLAssetType::AT_ANIMATION ||
+ getAssetType() == LLAssetType::AT_MESH)
+ {
+ return LLGlobalEconomy::Singleton::instance().getPriceUpload();
+ }
+
+ return 0;
+}
+
+
+LLUUID LLResourceUploadInfo::finishUpload(LLSD &result)
+{
+ if (getFolderId().isNull())
+ {
+ return LLUUID::null;
+ }
+
+ U32 permsEveryone = PERM_NONE;
+ U32 permsGroup = PERM_NONE;
+ U32 permsNextOwner = PERM_ALL;
+
+ if (result.has("new_next_owner_mask"))
+ {
+ // The server provided creation perms so use them.
+ // Do not assume we got the perms we asked for in
+ // since the server may not have granted them all.
+ permsEveryone = result["new_everyone_mask"].asInteger();
+ permsGroup = result["new_group_mask"].asInteger();
+ permsNextOwner = result["new_next_owner_mask"].asInteger();
+ }
+ else
+ {
+ // The server doesn't provide creation perms
+ // so use old assumption-based perms.
+ if (getAssetTypeString() != "snapshot")
+ {
+ permsNextOwner = PERM_MOVE | PERM_TRANSFER;
+ }
+ }
+
+ LLPermissions new_perms;
+ new_perms.init(
+ gAgent.getID(),
+ gAgent.getID(),
+ LLUUID::null,
+ LLUUID::null);
+
+ new_perms.initMasks(
+ PERM_ALL,
+ PERM_ALL,
+ permsEveryone,
+ permsGroup,
+ permsNextOwner);
+
+ U32 flagsInventoryItem = 0;
+ if (result.has("inventory_flags"))
+ {
+ flagsInventoryItem = static_cast<U32>(result["inventory_flags"].asInteger());
+ if (flagsInventoryItem != 0)
+ {
+ LL_INFOS() << "inventory_item_flags " << flagsInventoryItem << LL_ENDL;
+ }
+ }
+ S32 creationDate = time_corrected();
+
+ LLUUID serverInventoryItem = result["new_inventory_item"].asUUID();
+ LLUUID serverAssetId = result["new_asset"].asUUID();
+
+ LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+ serverInventoryItem,
+ getFolderId(),
+ new_perms,
+ serverAssetId,
+ getAssetType(),
+ getInventoryType(),
+ getName(),
+ getDescription(),
+ LLSaleInfo::DEFAULT,
+ flagsInventoryItem,
+ creationDate);
+
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+
+ return serverInventoryItem;
+}
+
+
+LLAssetID LLResourceUploadInfo::generateNewAssetId()
+{
+ if (gDisconnected)
+ {
+ LLAssetID rv;
+
+ rv.setNull();
+ return rv;
+ }
+ mAssetId = mTransactionId.makeAssetID(gAgent.getSecureSessionID());
+
+ return mAssetId;
+}
+
+void LLResourceUploadInfo::incrementUploadStats() const
+{
+ if (LLAssetType::AT_SOUND == mAssetType)
+ {
+ add(LLStatViewer::UPLOAD_SOUND, 1);
+ }
+ else if (LLAssetType::AT_TEXTURE == mAssetType)
+ {
+ add(LLStatViewer::UPLOAD_TEXTURE, 1);
+ }
+ else if (LLAssetType::AT_ANIMATION == mAssetType)
+ {
+ add(LLStatViewer::ANIMATION_UPLOADS, 1);
+ }
+}
+
+void LLResourceUploadInfo::assignDefaults()
+{
+ if (LLInventoryType::IT_NONE == mInventoryType)
+ {
+ mInventoryType = LLInventoryType::defaultForAssetType(mAssetType);
+ }
+ LLStringUtil::stripNonprintable(mName);
+ LLStringUtil::stripNonprintable(mDescription);
+
+ if (mName.empty())
+ {
+ mName = "(No Name)";
+ }
+ if (mDescription.empty())
+ {
+ mDescription = "(No Description)";
+ }
+
+ mFolderId = gInventory.findCategoryUUIDForType(
+ (mDestinationFolderType == LLFolderType::FT_NONE) ?
+ (LLFolderType::EType)mAssetType : mDestinationFolderType);
+
+}
+
+std::string LLResourceUploadInfo::getDisplayName() const
+{
+ return (mName.empty()) ? mAssetId.asString() : mName;
+};
+
+//=========================================================================
+LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo(
+ std::string fileName,
+ std::string name,
+ std::string description,
+ S32 compressionInfo,
+ LLFolderType::EType destinationType,
+ LLInventoryType::EType inventoryType,
+ U32 nextOWnerPerms,
+ U32 groupPerms,
+ U32 everyonePerms,
+ S32 expectedCost) :
+ LLResourceUploadInfo(name, description, compressionInfo,
+ destinationType, inventoryType,
+ nextOWnerPerms, groupPerms, everyonePerms, expectedCost),
+ mFileName(fileName)
+{
+}
+
+LLSD LLNewFileResourceUploadInfo::prepareUpload()
+{
+ if (getAssetId().isNull())
+ generateNewAssetId();
+
+ LLSD result = exportTempFile();
+ if (result.has("error"))
+ return result;
+
+ return LLResourceUploadInfo::prepareUpload();
+}
+
+LLSD LLNewFileResourceUploadInfo::exportTempFile()
+{
+ std::string filename = gDirUtilp->getTempFilename();
+
+ std::string exten = gDirUtilp->getExtension(getFileName());
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
+
+ LLAssetType::EType assetType = LLAssetType::AT_NONE;
+ std::string errorMessage;
+ std::string errorLabel;
+
+ bool error = false;
+
+ if (exten.empty())
+ {
+ std::string shortName = gDirUtilp->getBaseFileName(filename);
+
+ // No extension
+ errorMessage = llformat(
+ "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
+ shortName.c_str());
+ errorLabel = "NoFileExtension";
+ error = true;
+ }
+ else if (codec != IMG_CODEC_INVALID)
+ {
+ // It's an image file, the upload procedure is the same for all
+ assetType = LLAssetType::AT_TEXTURE;
+ if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec))
+ {
+ errorMessage = llformat("Problem with file %s:\n\n%s\n",
+ getFileName().c_str(), LLImage::getLastError().c_str());
+ errorLabel = "ProblemWithFile";
+ error = true;
+ }
+ }
+ else if (exten == "wav")
+ {
+ assetType = LLAssetType::AT_SOUND; // tag it as audio
+ S32 encodeResult = 0;
+
+ LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL;
+
+ encodeResult = encode_vorbis_file(getFileName(), filename);
+
+ if (LLVORBISENC_NOERR != encodeResult)
+ {
+ switch (encodeResult)
+ {
+ case LLVORBISENC_DEST_OPEN_ERR:
+ errorMessage = llformat("Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
+ errorLabel = "CannotOpenTemporarySoundFile";
+ break;
+
+ default:
+ errorMessage = llformat("Unknown vorbis encode failure on: %s\n", getFileName().c_str());
+ errorLabel = "UnknownVorbisEncodeFailure";
+ break;
+ }
+ error = true;
+ }
+ }
+ else if (exten == "bvh")
+ {
+ errorMessage = llformat("We do not currently support bulk upload of animation files\n");
+ errorLabel = "DoNotSupportBulkAnimationUpload";
+ error = true;
+ }
+ else if (exten == "anim")
+ {
+ assetType = LLAssetType::AT_ANIMATION;
+ filename = getFileName();
+ }
+ else
+ {
+ // Unknown extension
+ errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
+ errorLabel = "ErrorMessage";
+ error = TRUE;;
+ }
+
+ if (error)
+ {
+ LLSD errorResult(LLSD::emptyMap());
+
+ errorResult["error"] = LLSD::Binary(true);
+ errorResult["message"] = errorMessage;
+ errorResult["label"] = errorLabel;
+ return errorResult;
+ }
+
+ setAssetType(assetType);
+
+ // copy this file into the vfs for upload
+ S32 file_size;
+ LLAPRFile infile;
+ infile.open(filename, LL_APR_RB, NULL, &file_size);
+ if (infile.getFileHandle())
+ {
+ LLVFile file(gVFS, getAssetId(), assetType, LLVFile::WRITE);
+
+ file.setMaxSize(file_size);
+
+ const S32 buf_size = 65536;
+ U8 copy_buf[buf_size];
+ while ((file_size = infile.read(copy_buf, buf_size)))
+ {
+ file.write(copy_buf, file_size);
+ }
+ }
+ else
+ {
+ errorMessage = llformat("Unable to access output file: %s", filename.c_str());
+ LLSD errorResult(LLSD::emptyMap());
+
+ errorResult["error"] = LLSD::Binary(true);
+ errorResult["message"] = errorMessage;
+ return errorResult;
+ }
+
+ return LLSD();
+
+}
+
+//=========================================================================
+LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish) :
+ LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ 0, 0, 0, 0),
+ mTaskUpload(false),
+ mTaskId(LLUUID::null),
+ mContents(buffer),
+ mInvnFinishFn(finish),
+ mTaskFinishFn(NULL),
+ mStoredToVFS(false)
+{
+ setItemId(itemId);
+ setAssetType(assetType);
+}
+
+LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish) :
+ LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ 0, 0, 0, 0),
+ mTaskUpload(false),
+ mTaskId(LLUUID::null),
+ mContents(),
+ mInvnFinishFn(finish),
+ mTaskFinishFn(NULL),
+ mStoredToVFS(false)
+{
+ setItemId(itemId);
+
+ EImageCodec codec = static_cast<EImageCodec>(image->getCodec());
+
+ switch (codec)
+ {
+ case IMG_CODEC_JPEG:
+ setAssetType(LLAssetType::AT_IMAGE_JPEG);
+ LL_INFOS() << "Upload Asset type set to JPEG." << LL_ENDL;
+ break;
+ case IMG_CODEC_TGA:
+ setAssetType(LLAssetType::AT_IMAGE_TGA);
+ LL_INFOS() << "Upload Asset type set to TGA." << LL_ENDL;
+ break;
+ default:
+ LL_WARNS() << "Unknown codec to asset type transition. Codec=" << (int)codec << "." << LL_ENDL;
+ break;
+ }
+
+ size_t imageSize = image->getDataSize();
+ mContents.reserve(imageSize);
+ mContents.assign((char *)image->getData(), imageSize);
+}
+
+LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish) :
+ LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ 0, 0, 0, 0),
+ mTaskUpload(true),
+ mTaskId(taskId),
+ mContents(buffer),
+ mInvnFinishFn(NULL),
+ mTaskFinishFn(finish),
+ mStoredToVFS(false)
+{
+ setItemId(itemId);
+ setAssetType(assetType);
+}
+
+LLSD LLBufferedAssetUploadInfo::prepareUpload()
+{
+ if (getAssetId().isNull())
+ generateNewAssetId();
+
+ LLVFile file(gVFS, getAssetId(), getAssetType(), LLVFile::APPEND);
+
+ S32 size = mContents.length() + 1;
+ file.setMaxSize(size);
+ file.write((U8*)mContents.c_str(), size);
+
+ mStoredToVFS = true;
+
+ return LLSD().with("success", LLSD::Boolean(true));
+}
+
+LLSD LLBufferedAssetUploadInfo::generatePostBody()
+{
+ LLSD body;
+
+ if (!getTaskId().isNull())
+ {
+ body["task_id"] = getTaskId();
+ }
+ body["item_id"] = getItemId();
+
+ return body;
+}
+
+LLUUID LLBufferedAssetUploadInfo::finishUpload(LLSD &result)
+{
+ LLUUID newAssetId = result["new_asset"].asUUID();
+ LLUUID itemId = getItemId();
+
+ if (mStoredToVFS)
+ {
+ LLAssetType::EType assetType(getAssetType());
+ gVFS->renameFile(getAssetId(), assetType, newAssetId, assetType);
+ }
+
+ if (mTaskUpload)
+ {
+ LLUUID taskId = getTaskId();
+
+ dialog_refresh_all();
+
+ if (mTaskFinishFn)
+ {
+ mTaskFinishFn(itemId, taskId, newAssetId, result);
+ }
+ }
+ else
+ {
+ LLUUID newItemId(LLUUID::null);
+
+ if (itemId.notNull())
+ {
+ LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(itemId);
+ if (!item)
+ {
+ LL_WARNS() << "Inventory item for " << getDisplayName() << " is no longer in agent inventory." << LL_ENDL;
+ return newAssetId;
+ }
+
+ // Update viewer inventory item
+ LLPointer<LLViewerInventoryItem> newItem = new LLViewerInventoryItem(item);
+ newItem->setAssetUUID(newAssetId);
+
+ gInventory.updateItem(newItem);
+
+ newItemId = newItem->getUUID();
+ LL_INFOS() << "Inventory item " << item->getName() << " saved into " << newAssetId.asString() << LL_ENDL;
+ }
+
+ if (mInvnFinishFn)
+ {
+ mInvnFinishFn(itemId, newAssetId, newItemId, result);
+ }
+ gInventory.notifyObservers();
+ }
+
+ return newAssetId;
+}
+
+//=========================================================================
+
+LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish):
+ LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish),
+ mExerienceId(),
+ mTargetType(LSL2),
+ mIsRunning(false)
+{
+}
+
+LLScriptAssetUpload::LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType,
+ bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish):
+ LLBufferedAssetUploadInfo(taskId, itemId, LLAssetType::AT_LSL_TEXT, buffer, finish),
+ mExerienceId(exerienceId),
+ mTargetType(targetType),
+ mIsRunning(isRunning)
+{
+}
+
+LLSD LLScriptAssetUpload::generatePostBody()
+{
+ LLSD body;
+
+ if (getTaskId().isNull())
+ {
+ body["item_id"] = getItemId();
+ body["target"] = "lsl2";
+ }
+ else
+ {
+ body["task_id"] = getTaskId();
+ body["item_id"] = getItemId();
+ body["is_script_running"] = getIsRunning();
+ body["target"] = (getTargetType() == MONO) ? "mono" : "lsl2";
+ body["experience"] = getExerienceId();
+ }
+
+ return body;
+}
+
+//=========================================================================
+/*static*/
+LLUUID LLViewerAssetUpload::EnqueueInventoryUpload(const std::string &url, const LLResourceUploadInfo::ptr_t &uploadInfo)
+{
+ std::string procName("LLViewerAssetUpload::AssetInventoryUploadCoproc(");
+
+ LLUUID queueId = LLCoprocedureManager::instance().enqueueCoprocedure("Upload",
+ procName + LLAssetType::lookup(uploadInfo->getAssetType()) + ")",
+ boost::bind(&LLViewerAssetUpload::AssetInventoryUploadCoproc, _1, _2, url, uploadInfo));
+
+ return queueId;
+}
+
+//=========================================================================
+/*static*/
+void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter,
+ const LLUUID &id, std::string url, LLResourceUploadInfo::ptr_t uploadInfo)
+{
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = uploadInfo->prepareUpload();
+ uploadInfo->logPreparedUpload();
+
+ if (result.has("error"))
+ {
+ HandleUploadError(LLCore::HttpStatus(499), result, uploadInfo);
+ return;
+ }
+
+ llcoro::suspend();
+
+ if (uploadInfo->showUploadDialog())
+ {
+ std::string uploadMessage = "Uploading...\n\n";
+ uploadMessage.append(uploadInfo->getDisplayName());
+ LLUploadDialog::modalUploadDialog(uploadMessage);
+ }
+
+ LLSD body = uploadInfo->generatePostBody();
+
+ result = httpAdapter->postAndSuspend(httpRequest, url, body);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if ((!status) || (result.has("error")))
+ {
+ HandleUploadError(status, result, uploadInfo);
+ if (uploadInfo->showUploadDialog())
+ LLUploadDialog::modalUploadFinished();
+ return;
+ }
+
+ std::string uploader = result["uploader"].asString();
+
+ bool success = false;
+ if (!uploader.empty() && uploadInfo->getAssetId().notNull())
+ {
+ result = httpAdapter->postFileAndSuspend(httpRequest, uploader, uploadInfo->getAssetId(), uploadInfo->getAssetType());
+ httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ HandleUploadError(status, result, uploadInfo);
+ if (uploadInfo->showUploadDialog())
+ LLUploadDialog::modalUploadFinished();
+ return;
+ }
+
+ S32 uploadPrice = uploadInfo->getEconomyUploadCost();
+
+ if (uploadPrice > 0)
+ {
+ // this upload costed us L$, update our balance
+ // and display something saying that it cost L$
+ LLStatusBar::sendMoneyBalanceRequest();
+
+ LLSD args;
+ args["AMOUNT"] = llformat("%d", uploadPrice);
+ LLNotificationsUtil::add("UploadPayment", args);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "No upload url provided. Nothing uploaded, responding with previous result." << LL_ENDL;
+ }
+ LLUUID serverInventoryItem = uploadInfo->finishUpload(result);
+
+ if (uploadInfo->showInventoryPanel())
+ {
+ if (serverInventoryItem.notNull())
+ {
+ success = true;
+
+ // Show the preview panel for textures and sounds to let
+ // user know that the image (or snapshot) arrived intact.
+ LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel();
+ if (panel)
+ {
+ LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+ panel->setSelection(serverInventoryItem, TAKE_FOCUS_NO);
+
+ // restore keyboard focus
+ gFocusMgr.setKeyboardFocus(focus);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL;
+ }
+ }
+
+ // remove the "Uploading..." message
+ if (uploadInfo->showUploadDialog())
+ LLUploadDialog::modalUploadFinished();
+
+ // Let the Snapshot floater know we have finished uploading a snapshot to inventory.
+ LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot");
+ if (uploadInfo->getAssetType() == LLAssetType::AT_TEXTURE && floater_snapshot)
+ {
+ floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory")));
+ }
+}
+
+//=========================================================================
+/*static*/
+void LLViewerAssetUpload::HandleUploadError(LLCore::HttpStatus status, LLSD &result, LLResourceUploadInfo::ptr_t &uploadInfo)
+{
+ std::string reason;
+ std::string label("CannotUploadReason");
+
+ LL_WARNS() << ll_pretty_print_sd(result) << LL_ENDL;
+
+ if (result.has("label"))
+ {
+ label = result["label"].asString();
+ }
+
+ if (result.has("message"))
+ {
+ reason = result["message"].asString();
+ }
+ else
+ {
+ if (status.getType() == 499)
+ {
+ reason = "The server is experiencing unexpected difficulties.";
+ }
+ else
+ {
+ reason = "Error in upload request. Please visit "
+ "http://secondlife.com/support for help fixing this problem.";
+ }
+ }
+
+ LLSD args;
+ args["FILE"] = uploadInfo->getDisplayName();
+ args["REASON"] = reason;
+
+ LLNotificationsUtil::add(label, args);
+
+ // unfreeze script preview
+ if (uploadInfo->getAssetType() == LLAssetType::AT_LSL_TEXT)
+ {
+ LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script",
+ uploadInfo->getItemId());
+ if (preview)
+ {
+ LLSD errors;
+ errors.append(LLTrans::getString("UploadFailed") + reason);
+ preview->callbackLSLCompileFailed(errors);
+ }
+ }
+
+}
+
diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h
new file mode 100644
index 0000000000..43e23a0d42
--- /dev/null
+++ b/indra/newview/llviewerassetupload.h
@@ -0,0 +1,236 @@
+/**
+* @file llviewerassetupload.h
+* @author optional
+* @brief brief description of the file
+*
+* $LicenseInfo:firstyear=2011&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2011, 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_VIEWER_ASSET_UPLOAD_H
+#define LL_VIEWER_ASSET_UPLOAD_H
+
+#include "llfoldertype.h"
+#include "llassettype.h"
+#include "llinventorytype.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
+#include "llcorehttputil.h"
+#include "llimage.h"
+
+//=========================================================================
+class LLResourceUploadInfo
+{
+public:
+ typedef boost::shared_ptr<LLResourceUploadInfo> ptr_t;
+
+ LLResourceUploadInfo(
+ LLTransactionID transactId,
+ LLAssetType::EType assetType,
+ std::string name,
+ std::string description,
+ S32 compressionInfo,
+ LLFolderType::EType destinationType,
+ LLInventoryType::EType inventoryType,
+ U32 nextOWnerPerms,
+ U32 groupPerms,
+ U32 everyonePerms,
+ S32 expectedCost);
+
+ virtual ~LLResourceUploadInfo()
+ { }
+
+ virtual LLSD prepareUpload();
+ virtual LLSD generatePostBody();
+ virtual void logPreparedUpload();
+ virtual S32 getEconomyUploadCost();
+ virtual LLUUID finishUpload(LLSD &result);
+
+ LLTransactionID getTransactionId() const { return mTransactionId; }
+ LLAssetType::EType getAssetType() const { return mAssetType; }
+ std::string getAssetTypeString() const;
+ std::string getName() const { return mName; };
+ std::string getDescription() const { return mDescription; };
+ S32 getCompressionInfo() const { return mCompressionInfo; };
+ LLFolderType::EType getDestinationFolderType() const { return mDestinationFolderType; };
+ LLInventoryType::EType getInventoryType() const { return mInventoryType; };
+ std::string getInventoryTypeString() const;
+ U32 getNextOwnerPerms() const { return mNextOwnerPerms; };
+ U32 getGroupPerms() const { return mGroupPerms; };
+ U32 getEveryonePerms() const { return mEveryonePerms; };
+ S32 getExpectedUploadCost() const { return mExpectedUploadCost; };
+
+ virtual bool showUploadDialog() const { return true; }
+ virtual bool showInventoryPanel() const { return true; }
+
+ virtual std::string getDisplayName() const;
+
+ LLUUID getFolderId() const { return mFolderId; }
+ LLUUID getItemId() const { return mItemId; }
+ LLAssetID getAssetId() const { return mAssetId; }
+
+protected:
+ LLResourceUploadInfo(
+ std::string name,
+ std::string description,
+ S32 compressionInfo,
+ LLFolderType::EType destinationType,
+ LLInventoryType::EType inventoryType,
+ U32 nextOWnerPerms,
+ U32 groupPerms,
+ U32 everyonePerms,
+ S32 expectedCost);
+
+ LLResourceUploadInfo(
+ LLAssetID assetId,
+ LLAssetType::EType assetType,
+ std::string name );
+
+ void setTransactionId(LLTransactionID tid) { mTransactionId = tid; }
+ void setAssetType(LLAssetType::EType assetType) { mAssetType = assetType; }
+ void setItemId(LLUUID itemId) { mItemId = itemId; }
+
+ LLAssetID generateNewAssetId();
+ void incrementUploadStats() const;
+ virtual void assignDefaults();
+
+ void setAssetId(LLUUID assetId) { mAssetId = assetId; }
+
+private:
+ LLTransactionID mTransactionId;
+ LLAssetType::EType mAssetType;
+ std::string mName;
+ std::string mDescription;
+ S32 mCompressionInfo;
+ LLFolderType::EType mDestinationFolderType;
+ LLInventoryType::EType mInventoryType;
+ U32 mNextOwnerPerms;
+ U32 mGroupPerms;
+ U32 mEveryonePerms;
+ S32 mExpectedUploadCost;
+
+ LLUUID mFolderId;
+ LLUUID mItemId;
+ LLAssetID mAssetId;
+};
+
+//-------------------------------------------------------------------------
+class LLNewFileResourceUploadInfo : public LLResourceUploadInfo
+{
+public:
+ LLNewFileResourceUploadInfo(
+ std::string fileName,
+ std::string name,
+ std::string description,
+ S32 compressionInfo,
+ LLFolderType::EType destinationType,
+ LLInventoryType::EType inventoryType,
+ U32 nextOWnerPerms,
+ U32 groupPerms,
+ U32 everyonePerms,
+ S32 expectedCost);
+
+ virtual LLSD prepareUpload();
+
+ std::string getFileName() const { return mFileName; };
+
+protected:
+
+ virtual LLSD exportTempFile();
+
+private:
+ std::string mFileName;
+
+};
+
+//-------------------------------------------------------------------------
+class LLBufferedAssetUploadInfo : public LLResourceUploadInfo
+{
+public:
+ typedef boost::function<void(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)> invnUploadFinish_f;
+ typedef boost::function<void(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response)> taskUploadFinish_f;
+
+ LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish);
+ LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish);
+ LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish);
+
+ virtual LLSD prepareUpload();
+ virtual LLSD generatePostBody();
+ virtual LLUUID finishUpload(LLSD &result);
+
+ LLUUID getTaskId() const { return mTaskId; }
+ const std::string & getContents() const { return mContents; }
+
+ virtual bool showUploadDialog() const { return false; }
+ virtual bool showInventoryPanel() const { return false; }
+
+protected:
+
+
+private:
+ bool mTaskUpload;
+ LLUUID mTaskId;
+ std::string mContents;
+ invnUploadFinish_f mInvnFinishFn;
+ taskUploadFinish_f mTaskFinishFn;
+ bool mStoredToVFS;
+};
+
+//-------------------------------------------------------------------------
+class LLScriptAssetUpload : public LLBufferedAssetUploadInfo
+{
+public:
+ enum TargetType_t
+ {
+ LSL2,
+ MONO
+ };
+
+ LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish);
+ LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType,
+ bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish);
+
+ virtual LLSD generatePostBody();
+
+ LLUUID getExerienceId() const { return mExerienceId; }
+ TargetType_t getTargetType() const { return mTargetType; }
+ bool getIsRunning() const { return mIsRunning; }
+
+private:
+ LLUUID mExerienceId;
+ TargetType_t mTargetType;
+ bool mIsRunning;
+
+};
+
+//=========================================================================
+class LLViewerAssetUpload
+{
+public:
+ static LLUUID EnqueueInventoryUpload(const std::string &url, const LLResourceUploadInfo::ptr_t &uploadInfo);
+
+ static void AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, const LLUUID &id, std::string url, LLResourceUploadInfo::ptr_t uploadInfo);
+
+private:
+ static void HandleUploadError(LLCore::HttpStatus status, LLSD &result, LLResourceUploadInfo::ptr_t &uploadInfo);
+};
+
+#endif // !VIEWER_ASSET_UPLOAD_H
diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp
deleted file mode 100755
index e390e8776d..0000000000
--- a/indra/newview/llviewerdisplayname.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * @file llviewerdisplayname.cpp
- * @brief Wrapper for display name functionality
- *
- * $LicenseInfo:firstyear=2010&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 "llviewerdisplayname.h"
-
-// viewer includes
-#include "llagent.h"
-#include "llviewerregion.h"
-#include "llvoavatar.h"
-
-// library includes
-#include "llavatarnamecache.h"
-#include "llhttpclient.h"
-#include "llhttpnode.h"
-#include "llnotificationsutil.h"
-#include "llui.h" // getLanguage()
-
-namespace LLViewerDisplayName
-{
- // Fired when viewer receives server response to display name change
- set_name_signal_t sSetDisplayNameSignal;
-
- // Fired when there is a change in the agent's name
- name_changed_signal_t sNameChangedSignal;
-
- void addNameChangedCallback(const name_changed_signal_t::slot_type& cb)
- {
- sNameChangedSignal.connect(cb);
- }
-
- void doNothing() { }
-}
-
-class LLSetDisplayNameResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLSetDisplayNameResponder);
-private:
- // only care about errors
- /*virtual*/ void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD());
- LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
- }
-};
-
-void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot)
-{
- // TODO: simple validation here
-
- LLViewerRegion* region = gAgent.getRegion();
- llassert(region);
- std::string cap_url = region->getCapability("SetDisplayName");
- if (cap_url.empty())
- {
- // this server does not support display names, report error
- slot(false, "unsupported", LLSD());
- return;
- }
-
- // People API can return localized error messages. Indicate our
- // language preference via header.
- LLSD headers;
- 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
- // to request a change, so we can use direct lookup without callback.
- LLAvatarName av_name;
- if (!LLAvatarNameCache::get( gAgent.getID(), &av_name))
- {
- slot(false, "name unavailable", LLSD());
- return;
- }
-
- // People API expects array of [ "old value", "new value" ]
- LLSD change_array = LLSD::emptyArray();
- change_array.append(av_name.getDisplayName());
- change_array.append(display_name);
-
- LL_INFOS() << "Set name POST to " << cap_url << LL_ENDL;
-
- // Record our caller for when the server sends back a reply
- sSetDisplayNameSignal.connect(slot);
-
- // POST the requested change. The sim will not send a response back to
- // this request directly, rather it will send a separate message after it
- // communicates with the back-end.
- LLSD body;
- body["display_name"] = change_array;
- LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers);
-}
-
-class LLSetDisplayNameReply : public LLHTTPNode
-{
- LOG_CLASS(LLSetDisplayNameReply);
-public:
- /*virtual*/ void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
- LLSD body = input["body"];
-
- S32 status = body["status"].asInteger();
- bool success = (status == HTTP_OK);
- std::string reason = body["reason"].asString();
- LLSD content = body["content"];
-
- LL_INFOS() << "status " << status << " reason " << reason << LL_ENDL;
-
- // 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 == HTTP_CONFLICT)
- {
- LLUUID agent_id = gAgent.getID();
- // Flush stale data
- LLAvatarNameCache::erase( agent_id );
- // Queue request for new data: nothing to do on callback though...
- // Note: no need to disconnect the callback as it never gets out of scope
- LLAvatarNameCache::get(agent_id, boost::bind(&LLViewerDisplayName::doNothing));
- // Kill name tag, as it is wrong
- LLVOAvatar::invalidateNameTag( agent_id );
- }
-
- // inform caller of result
- LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content);
- LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots();
- }
-};
-
-
-class LLDisplayNameUpdate : public LLHTTPNode
-{
- /*virtual*/ void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
- LLSD body = input["body"];
- LLUUID agent_id = body["agent_id"];
- std::string old_display_name = body["old_display_name"];
- // By convention this record is called "agent" in the People API
- LLSD name_data = body["agent"];
-
- // Inject the new name data into cache
- LLAvatarName av_name;
- av_name.fromLLSD( name_data );
-
- LL_INFOS() << "name-update now " << LLDate::now()
- << " next_update " << LLDate(av_name.mNextUpdate)
- << LL_ENDL;
-
- // Name expiration time may be provided in headers, or we may use a
- // default value
- // *TODO: get actual headers out of ResponsePtr
- //LLSD headers = response->mHeaders;
- LLSD headers;
- av_name.mExpires =
- LLAvatarNameCache::nameExpirationFromHeaders(headers);
-
- LLAvatarNameCache::insert(agent_id, av_name);
-
- // force name tag to update
- LLVOAvatar::invalidateNameTag(agent_id);
-
- LLSD args;
- args["OLD_NAME"] = old_display_name;
- args["SLID"] = av_name.getUserName();
- args["NEW_NAME"] = av_name.getDisplayName();
- LLNotificationsUtil::add("DisplayNameUpdate", args);
- if (agent_id == gAgent.getID())
- {
- LLViewerDisplayName::sNameChangedSignal();
- }
- }
-};
-
-LLHTTPRegistration<LLSetDisplayNameReply>
- gHTTPRegistrationMessageSetDisplayNameReply(
- "/message/SetDisplayNameReply");
-
-LLHTTPRegistration<LLDisplayNameUpdate>
- gHTTPRegistrationMessageDisplayNameUpdate(
- "/message/DisplayNameUpdate");
diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h
deleted file mode 100755
index 16d59ae43b..0000000000
--- a/indra/newview/llviewerdisplayname.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * @file llviewerdisplayname.h
- * @brief Wrapper for display name functionality
- *
- * $LicenseInfo:firstyear=2010&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 LLVIEWERDISPLAYNAME_H
-#define LLVIEWERDISPLAYNAME_H
-
-#include <boost/signals2.hpp>
-
-class LLSD;
-class LLUUID;
-
-namespace LLViewerDisplayName
-{
- typedef boost::signals2::signal<
- void (bool success, const std::string& reason, const LLSD& content)>
- set_name_signal_t;
- typedef set_name_signal_t::slot_type set_name_slot_t;
-
- typedef boost::signals2::signal<void (void)> name_changed_signal_t;
- typedef name_changed_signal_t::slot_type name_changed_slot_t;
-
- // Sends an update to the server to change a display name
- // and call back when done. May not succeed due to service
- // unavailable or name not available.
- void set(const std::string& display_name, const set_name_slot_t& slot);
-
- void addNameChangedCallback(const name_changed_signal_t::slot_type& cb);
-}
-
-#endif // LLVIEWERDISPLAYNAME_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 1178652408..7e76db20c5 100755
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -56,7 +56,6 @@
#include "llfloaterconversationpreview.h"
#include "llfloaterdeleteenvpreset.h"
#include "llfloaterdestinations.h"
-#include "llfloaterdisplayname.h"
#include "llfloatereditdaycycle.h"
#include "llfloatereditsky.h"
#include "llfloatereditwater.h"
@@ -92,7 +91,6 @@
#include "llfloaternotificationsconsole.h"
#include "llfloaterobjectweights.h"
#include "llfloateropenobject.h"
-#include "llfloateroutbox.h"
#include "llfloaterpathfindingcharacters.h"
#include "llfloaterpathfindingconsole.h"
#include "llfloaterpathfindinglinksets.h"
@@ -247,7 +245,6 @@ void LLViewerFloaterReg::registerFloaters()
LLInspectRemoteObjectUtil::registerFloater();
LLFloaterVoiceVolumeUtil::registerFloater();
LLNotificationsUI::registerFloater();
- LLFloaterDisplayNameUtil::registerFloater();
LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>);
LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>);
@@ -272,7 +269,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>);
LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>);
- LLFloaterReg::add("outbox", "floater_merchant_outbox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutbox>);
LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>);
LLFloaterPayUtil::registerFloater();
diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp
index 158cacbc81..b8ff2cc9b4 100644
--- a/indra/newview/llviewerfoldertype.cpp
+++ b/indra/newview/llviewerfoldertype.cpp
@@ -137,7 +137,7 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()
bool boxes_invisible = !gSavedSettings.getBOOL("InventoryOutboxMakeVisible");
addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Received Items", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible));
- addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible));
+ addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, true));
addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "Inv_SysOpen", "Inv_SysClosed", FALSE, true));
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 24096e3222..573791aca3 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -79,6 +79,16 @@ static const char * const LOG_INV("Inventory");
static const char * const LOG_LOCAL("InventoryLocalize");
static const char * const LOG_NOTECARD("copy_inventory_from_notecard");
+#if 1
+// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model.
+// temp code in transition
+void doInventoryCb(LLPointer<LLInventoryCallback> cb, LLUUID id)
+{
+ if (cb.notNull())
+ cb->fire(id);
+}
+#endif
+
///----------------------------------------------------------------------------
/// Helper class to store special inventory item names and their localized values.
///----------------------------------------------------------------------------
@@ -1280,16 +1290,14 @@ void link_inventory_array(const LLUUID& category,
#endif
}
- bool ais_ran = false;
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
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();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::CreateInventory(category, new_inventory, cr);
}
-
- if (!ais_ran)
+ else
{
LLMessageSystem* msg = gMessageSystem;
for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter )
@@ -1346,8 +1354,7 @@ void update_inventory_item(
LLPointer<LLInventoryCallback> cb)
{
const LLUUID& item_id = update_item->getUUID();
- bool ais_ran = false;
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
LLSD updates = update_item->asLLSD();
// Replace asset_id and/or shadow_id with transaction_id (hash_id)
@@ -1361,10 +1368,10 @@ void update_inventory_item(
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();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::UpdateItem(item_id, updates, cr);
}
- if (!ais_ran)
+ else
{
LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL;
@@ -1400,13 +1407,12 @@ void update_inventory_item(
const LLSD& updates,
LLPointer<LLInventoryCallback> cb)
{
- bool ais_ran = false;
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
- LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
- ais_ran = cmd_ptr->run_command();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::UpdateItem(item_id, updates, cr);
}
- if (!ais_ran)
+ else
{
LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL;
@@ -1456,11 +1462,11 @@ void update_inventory_category(
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())
+ if (AISAPI::isAvailable())
{
LLSD new_llsd = new_cat->asLLSD();
- LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb);
- cmd_ptr->run_command();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::UpdateCategory(cat_id, new_llsd, cr);
}
else // no cap
{
@@ -1522,10 +1528,10 @@ void remove_inventory_item(
{
const LLUUID item_id(obj->getUUID());
LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << obj->getName() << LL_ENDL;
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
- LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb);
- cmd_ptr->run_command();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::RemoveItem(item_id, cr);
if (immediate_delete)
{
@@ -1598,10 +1604,10 @@ void remove_inventory_category(
LLNotificationsUtil::add("CannotRemoveProtectedCategories");
return;
}
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
- LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb);
- cmd_ptr->run_command();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::RemoveCategory(cat_id, cr);
}
else // no cap
{
@@ -1701,10 +1707,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
}
else
{
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
- LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb);
- cmd_ptr->run_command();
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::PurgeDescendents(id, cr);
}
else // no cap
{
@@ -1780,27 +1786,20 @@ void copy_inventory_from_notecard(const LLUUID& destination_id,
return;
}
- // check capability to prevent a crash while LL_ERRS in LLCapabilityListener::capListener. See EXT-8459.
- std::string url = viewer_region->getCapability("CopyInventoryFromNotecard");
- if (url.empty())
- {
- LL_WARNS(LOG_NOTECARD) << "There is no 'CopyInventoryFromNotecard' capability"
- << " for region: " << viewer_region->getName()
- << LL_ENDL;
- return;
- }
-
- LLSD request, body;
+ LLSD body;
body["notecard-id"] = notecard_inv_id;
body["object-id"] = object_id;
body["item-id"] = src->getUUID();
body["folder-id"] = destination_id;
body["callback-id"] = (LLSD::Integer)callback_id;
- request["message"] = "CopyInventoryFromNotecard";
- request["payload"] = body;
-
- viewer_region->getCapAPI().post(request);
+ /// *TODO: RIDER: This posts the request under the agents policy.
+ /// When I convert the inventory over this call should be moved under that
+ /// policy as well.
+ if (!gAgent.requestPostCapability("CopyInventoryFromNotecard", body))
+ {
+ LL_WARNS() << "SIM does not have the capability to copy from notecard." << LL_ENDL;
+ }
}
void create_new_item(const std::string& name,
@@ -1858,12 +1857,13 @@ void slam_inventory_folder(const LLUUID& folder_id,
const LLSD& contents,
LLPointer<LLInventoryCallback> cb)
{
- if (AISCommand::isAPIAvailable())
+ if (AISAPI::isAvailable())
{
LL_DEBUGS(LOG_INV) << "using AISv3 to slam folder, id " << folder_id
<< " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL;
- LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb);
- cmd_ptr->run_command();
+
+ AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t();
+ AISAPI::SlamFolder(folder_id, contents, cr);
}
else // no cap
{
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 3eae0f8d86..75a201d92f 100755
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -69,6 +69,7 @@
#include "llwebprofile.h"
#include "llwindow.h"
#include "llvieweraudio.h"
+#include "llcorehttputil.h"
#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows.
@@ -152,190 +153,6 @@ LLViewerMediaObserver::~LLViewerMediaObserver()
}
-// Move this to its own file.
-// helper class that tries to download a URL from a web site and calls a method
-// on the Panel Land Media and to discover the MIME type
-class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLMimeDiscoveryResponder);
-public:
- LLMimeDiscoveryResponder( viewer_media_t media_impl)
- : mMediaImpl(media_impl),
- mInitialized(false)
- {
- if(mMediaImpl->mMimeTypeProbe != NULL)
- {
- LL_ERRS() << "impl already has an outstanding responder" << LL_ENDL;
- }
-
- mMediaImpl->mMimeTypeProbe = this;
- }
-
- ~LLMimeDiscoveryResponder()
- {
- disconnectOwner();
- }
-
-private:
- /* virtual */ void httpCompleted()
- {
- if (!isGoodStatus())
- {
- LL_WARNS() << dumpResponse()
- << " [headers:" << getResponseHeaders() << "]" << LL_ENDL;
- }
- 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);
-
- LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL;
-
- // 2xx status codes indicate success.
- // Most 4xx status codes are successful enough for our purposes.
- // 499 is the error code for host not found, timeout, etc.
- // 500 means "Internal Server error" but we decided it's okay to
- // accept this and go past it in the MIME type probe
- // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com
- // 499 is a code specifc to join.secondlife.com apparently safe to ignore
-// if( ((status >= 200) && (status < 300)) ||
-// ((status >= 400) && (status < 499)) ||
-// (status == 500) ||
-// (status == 302) ||
-// (status == 499)
-// )
- // 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)
- {
- // 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 = HTTP_CONTENT_TEXT_HTML;
- }
- }
- //else
- //{
- // LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL;
- //
- // if(mMediaImpl)
- // {
- // mMediaImpl->mMediaSourceFailed = true;
- // }
- // return;
- //}
-
- // 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;
-
- if(impl && !mInitialized && ! mime_type.empty())
- {
- if(impl->initializeMedia(mime_type))
- {
- mInitialized = true;
- impl->loadURI();
- disconnectOwner();
- }
- }
- }
-
-public:
- void cancelRequest()
- {
- disconnectOwner();
- }
-
-private:
- void disconnectOwner()
- {
- if(mMediaImpl)
- {
- if(mMediaImpl->mMimeTypeProbe != this)
- {
- LL_ERRS() << "internal error: mMediaImpl->mMimeTypeProbe != this" << LL_ENDL;
- }
-
- mMediaImpl->mMimeTypeProbe = NULL;
- }
- mMediaImpl = NULL;
- }
-
-
-public:
- LLViewerMediaImpl *mMediaImpl;
- bool mInitialized;
-};
-
-class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLViewerMediaOpenIDResponder);
-public:
- LLViewerMediaOpenIDResponder( )
- {
- }
-
- ~LLViewerMediaOpenIDResponder()
- {
- }
-
- /* virtual */ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- // 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);
- }
-
-};
-
-class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder
-{
-LOG_CLASS(LLViewerMediaWebProfileResponder);
-public:
- LLViewerMediaWebProfileResponder(std::string host)
- {
- mHost = host;
- }
-
- ~LLViewerMediaWebProfileResponder()
- {
- }
-
- void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- // 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 = getResponseHeaders();
- // *TODO: Check that this works.
- stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE);
- LL_WARNS("MediaAuth") << stripped_content << LL_ENDL;
-
- 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.
- std::string auth_cookie = cookie.substr(0, cookie.find(";")); // strip path
- LLWebProfile::setAuthCookie(auth_cookie);
- }
-
- std::string mHost;
-};
-
-
LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
LLURL LLViewerMedia::sOpenIDURL;
std::string LLViewerMedia::sOpenIDCookie;
@@ -1388,87 +1205,172 @@ LLSD LLViewerMedia::getHeaders()
return headers;
}
+LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders()
+{
+ LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders);
+
+ headers->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
+ headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML);
+ headers->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie);
+ headers->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent());
+
+ return headers;
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
// static
void LLViewerMedia::setOpenIDCookie()
{
if(!sOpenIDCookie.empty())
{
- // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port]
- // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that.
- // We therefore do it here.
- std::string authority = sOpenIDURL.mAuthority;
- std::string::size_type host_start = authority.find('@');
- if(host_start == std::string::npos)
- {
- // no username/password
- host_start = 0;
- }
- else
- {
- // Hostname starts after the @.
- // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.)
- ++host_start;
- }
- std::string::size_type host_end = authority.rfind(':');
- if((host_end == std::string::npos) || (host_end < host_start))
- {
- // no port
- host_end = authority.size();
- }
-
- getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start));
+ std::string profileUrl = getProfileURL("");
+
+ LLCoros::instance().launch("LLViewerMedia::getOpenIDCookieCoro",
+ boost::bind(&LLViewerMedia::getOpenIDCookieCoro, profileUrl));
+ }
+}
+
+/*static*/
+void LLViewerMedia::getOpenIDCookieCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getOpenIDCookieCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ httpOpts->setFollowRedirects(true);
+ httpOpts->setWantHeaders(true);
+
+ LLURL hostUrl(url.c_str());
+ std::string hostAuth = hostUrl.getAuthority();
+
+ // *TODO: Expand LLURL to split and extract this information better.
+ // The structure of a URL is well defined and needing to retrieve parts of it are common.
+ // original comment:
+ // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port]
+ // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that.
+ // We therefore do it here.
+ std::string authority = sOpenIDURL.mAuthority;
+ std::string::size_type hostStart = authority.find('@');
+ if (hostStart == std::string::npos)
+ { // no username/password
+ hostStart = 0;
+ }
+ else
+ { // Hostname starts after the @.
+ // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.)
+ ++hostStart;
+ }
+ std::string::size_type hostEnd = authority.rfind(':');
+ if ((hostEnd == std::string::npos) || (hostEnd < hostStart))
+ { // no port
+ hostEnd = authority.size();
+ }
- // Do a web profile get so we can store the cookie
- LLSD headers = LLSD::emptyMap();
- headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
- headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie;
- headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent();
+ getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(hostStart, hostEnd - hostStart));
- std::string profile_url = getProfileURL("");
- LLURL raw_profile_url( profile_url.c_str() );
+ // Do a web profile get so we can store the cookie
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie);
+ httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent());
+
+
+ LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL;
+ LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL;
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("MediaAuth") << "Error getting web profile." << LL_ENDL;
+ return;
+ }
+
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+ if (!resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE))
+ {
+ LL_WARNS("MediaAuth") << "No cookie in response." << LL_ENDL;
+ return;
+ }
+
+ const std::string& cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asStringRef();
+ LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL;
+
+ // *TODO: What about bad status codes? Does this destroy previous cookies?
+ LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, hostAuth);
+
+ // Set cookie for snapshot publishing.
+ std::string authCookie = cookie.substr(0, cookie.find(";")); // strip path
+ LLWebProfile::setAuthCookie(authCookie);
- LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << LL_ENDL;
- LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL;
- LLHTTPClient::get(profile_url,
- new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
- headers);
- }
}
/////////////////////////////////////////////////////////////////////////////////////////
// static
-void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token)
+void LLViewerMedia::openIDSetup(const std::string &openidUrl, const std::string &openidToken)
{
- LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL;
+ LL_DEBUGS("MediaAuth") << "url = \"" << openidUrl << "\", token = \"" << openidToken << "\"" << LL_ENDL;
- // post the token to the url
- // the responder will need to extract the cookie(s).
+ LLCoros::instance().launch("LLViewerMedia::openIDSetupCoro",
+ boost::bind(&LLViewerMedia::openIDSetupCoro, openidUrl, openidToken));
+}
- // Save the OpenID URL for later -- we may need the host when adding the cookie.
- sOpenIDURL.init(openid_url.c_str());
-
- // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies.
- sOpenIDCookie.clear();
+/*static*/
+void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidToken)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("openIDSetupCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
- LLSD headers = LLSD::emptyMap();
- // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header
- 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[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();
- U8 *data = new U8[size];
- memcpy(data, openid_token.data(), size);
-
- LLHTTPClient::postRaw(
- openid_url,
- data,
- size,
- new LLViewerMediaOpenIDResponder(),
- headers);
-
+ httpOpts->setWantHeaders(true);
+
+ // post the token to the url
+ // the responder will need to extract the cookie(s).
+ // Save the OpenID URL for later -- we may need the host when adding the cookie.
+ sOpenIDURL.init(openidUrl.c_str());
+ // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies.
+ sOpenIDCookie.clear();
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded");
+
+ LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray);
+ LLCore::BufferArrayStream bas(rawbody.get());
+
+ bas << std::noskipws << openidToken;
+
+ LLSD result = httpAdapter->postRawAndSuspend(httpRequest, openidUrl, rawbody, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("MediaAuth") << "Error getting Open ID cookie" << LL_ENDL;
+ return;
+ }
+
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+ if (!resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE))
+ {
+ LL_WARNS("MediaAuth") << "No cookie in response." << LL_ENDL;
+ return;
+ }
+
+ // We don't care about the content of the response, only the Set-Cookie header.
+ const std::string &cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE];
+
+ // *TODO: What about bad status codes? Does this destroy previous cookies?
+ LLViewerMedia::openIDCookieResponse(cookie);
+ LL_DEBUGS("MediaAuth") << "OpenID cookie set." << LL_ENDL;
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -1661,7 +1563,6 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
mIsParcelMedia(false),
mProximity(-1),
mProximityDistance(0.0f),
- mMimeTypeProbe(NULL),
mMediaAutoPlay(false),
mInNearbyMediaList(false),
mClearCache(false),
@@ -1671,8 +1572,10 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
mIsUpdated(false),
mTrustedBrowser(false),
mZoomFactor(1.0),
- mCleanBrowser(false)
-{
+ mCleanBrowser(false),
+ mMimeProbe(),
+ mCanceling(false)
+{
// Set up the mute list observer if it hasn't been set up already.
if(!sViewerMediaMuteListObserverInitialized)
@@ -2610,7 +2513,8 @@ void LLViewerMediaImpl::navigateInternal()
return;
}
- if(mMimeTypeProbe != NULL)
+
+ if (!mMimeProbe.expired())
{
LL_WARNS() << "MIME type probe already in progress -- bailing out." << LL_ENDL;
return;
@@ -2648,14 +2552,8 @@ void LLViewerMediaImpl::navigateInternal()
if(scheme.empty() || "http" == scheme || "https" == scheme)
{
- // If we don't set an Accept header, LLHTTPClient will add one like this:
- // Accept: application/llsd+xml
- // which is really not what we want.
- LLSD headers = LLSD::emptyMap();
- headers[HTTP_OUT_HEADER_ACCEPT] = "*/*";
- // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com
- headers[HTTP_OUT_HEADER_COOKIE] = "";
- LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f);
+ LLCoros::instance().launch("LLViewerMediaImpl::mimeDiscoveryCoro",
+ boost::bind(&LLViewerMediaImpl::mimeDiscoveryCoro, this, mMediaURL));
}
else if("data" == scheme || "file" == scheme || "about" == scheme)
{
@@ -2685,6 +2583,66 @@ void LLViewerMediaImpl::navigateInternal()
}
}
+void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("mimeDiscoveryCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+
+ mMimeProbe = httpAdapter;
+
+ httpOpts->setFollowRedirects(true);
+ httpOpts->setHeadersOnly(true);
+
+ httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*");
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, "");
+
+ LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders);
+
+ mMimeProbe.reset();
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS() << "Error retrieving media headers." << LL_ENDL;
+ }
+
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
+
+ const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE].asStringRef();
+
+ std::string::size_type idx1 = mediaType.find_first_of(";");
+ std::string mimeType = mediaType.substr(0, idx1);
+
+ // We now no longer need to 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.
+ // The probe was successful.
+ if (mimeType.empty())
+ {
+ // Some sites don't return any content-type header at all.
+ // Treat an empty mime type as text/html.
+ mimeType = HTTP_CONTENT_TEXT_HTML;
+ }
+
+ LL_DEBUGS() << "Media type \"" << mediaType << "\", mime type is \"" << mimeType << "\"" << LL_ENDL;
+
+ // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
+ // Make a local copy so we can call loadURI() afterwards.
+
+ if (!mimeType.empty())
+ {
+ if (initializeMedia(mimeType))
+ {
+ loadURI();
+ }
+ }
+}
+
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::navigateStop()
{
@@ -2783,7 +2741,7 @@ void LLViewerMediaImpl::update()
{
// Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state.
}
- else if(mMimeTypeProbe != NULL)
+ else if (!mMimeProbe.expired())
{
// this media source is doing a MIME type probe -- don't try loading it again.
}
@@ -3673,18 +3631,10 @@ void LLViewerMediaImpl::setNavigateSuspended(bool suspend)
void LLViewerMediaImpl::cancelMimeTypeProbe()
{
- if(mMimeTypeProbe != NULL)
- {
- // There doesn't seem to be a way to actually cancel an outstanding request.
- // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results.
- mMimeTypeProbe->cancelRequest();
-
- // The above should already have set mMimeTypeProbe to NULL.
- if(mMimeTypeProbe != NULL)
- {
- LL_ERRS() << "internal error: mMimeTypeProbe is not NULL after cancelling request." << LL_ENDL;
- }
- }
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t probeAdapter = mMimeProbe.lock();
+
+ if (probeAdapter)
+ probeAdapter->cancelSuspendedOperation();
}
void LLViewerMediaImpl::addObject(LLVOVolume* obj)
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 6803adfaa2..92d644c900 100755
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -40,6 +40,9 @@
#include "llnotificationptr.h"
#include "llurl.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
+#include "llcorehttputil.h"
class LLViewerMediaImpl;
class LLUUID;
@@ -161,11 +164,15 @@ public:
static void setOnlyAudibleMediaTextureID(const LLUUID& texture_id);
static LLSD getHeaders();
+ static LLCore::HttpHeaders::ptr_t getHttpHeaders();
private:
static void setOpenIDCookie();
static void onTeleportFinished();
-
+
+ static void openIDSetupCoro(std::string openidUrl, std::string openidToken);
+ static void getOpenIDCookieCoro(std::string url);
+
static LLPluginCookieStore *sCookieStore;
static LLURL sOpenIDURL;
static std::string sOpenIDCookie;
@@ -180,7 +187,6 @@ class LLViewerMediaImpl
public:
friend class LLViewerMedia;
- friend class LLMimeDiscoveryResponder;
LLViewerMediaImpl(
const LLUUID& texture_id,
@@ -453,7 +459,6 @@ private:
S32 mProximity;
F64 mProximityDistance;
F64 mProximityCamera;
- LLMimeDiscoveryResponder *mMimeTypeProbe;
bool mMediaAutoPlay;
std::string mMediaEntryURL;
bool mInNearbyMediaList; // used by LLPanelNearbyMedia::refreshList() for performance reasons
@@ -470,6 +475,10 @@ private:
BOOL mIsUpdated ;
std::list< LLVOVolume* > mObjectList ;
+ void mimeDiscoveryCoro(std::string url);
+ LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mMimeProbe;
+ bool mCanceling;
+
private:
LLViewerMediaTexture *updatePlaceholderImage();
};
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2505ae6a9c..d8ec44b132 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -390,32 +390,10 @@ void set_underclothes_menu_options()
void set_merchant_SLM_menu()
{
- // DD-170 : SLM Alpha and Beta program : for the moment, we always show the SLM menu and
- // tools so that all merchants can try out the UI, even if not migrated.
- // *TODO : Keep SLM UI hidden for non migrated merchant in released viewer
-
- //if (LLMarketplaceData::instance().getSLMStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT)
- //{
- // Merchant not migrated: show only the old Merchant Outbox menu
- // gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(TRUE);
- //}
- //else
- //{
- // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool
- gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE);
- LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
- gToolBarView->enableCommand(command->id(), true);
- //}
-}
-
-void set_merchant_outbox_menu(U32 status, const LLSD& content)
-{
- // If the merchant is fully migrated, the API is disabled (503) and we won't show the old menu item.
- // In all other cases, we show it.
- if (status != MarketplaceErrorCodes::IMPORT_SERVER_API_DISABLED)
- {
- gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(TRUE);
- }
+ // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool
+ gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE);
+ LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings");
+ gToolBarView->enableCommand(command->id(), true);
}
void check_merchant_status()
@@ -434,17 +412,6 @@ void check_merchant_status()
// Launch an SLM test connection to get the merchant status
LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu));
-
- // Do the Merchant Outbox init only once per session
- if (LLMarketplaceInventoryImporter::instance().getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED)
- {
- // Hide merchant outbox related menu item
- gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(FALSE);
-
- // Launch a Merchant Outbox test connection to get the migration status
- LLMarketplaceInventoryImporter::instance().setStatusReportCallback(boost::bind(&set_merchant_outbox_menu,_1, _2));
- LLMarketplaceInventoryImporter::instance().initialize();
- }
}
}
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index f8e50ba463..4f24dfafac 100755
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -62,11 +62,10 @@
#include "lluploaddialog.h"
#include "lltrans.h"
#include "llfloaterbuycurrency.h"
+#include "llviewerassetupload.h"
// linden libraries
-#include "llassetuploadresponders.h"
#include "lleconomy.h"
-#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llsdutil.h"
@@ -83,8 +82,9 @@ class LLFileEnableUpload : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
- return new_value;
+ return true;
+// bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
+// return new_value;
}
};
@@ -410,7 +410,6 @@ class LLFileUploadBulk : public view_listener_t
}
// TODO:
- // Iterate over all files
// Check extensions for uploadability, cost
// Check user balance for entire cost
// Charge user entire cost
@@ -422,37 +421,33 @@ class LLFileUploadBulk : public view_listener_t
LLFilePicker& picker = LLFilePicker::instance();
if (picker.getMultipleOpenFiles())
{
- const std::string& filename = picker.getFirstFile();
- std::string name = gDirUtilp->getBaseFileName(filename, true);
-
- std::string asset_name = name;
- LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
- LLStringUtil::replaceChar(asset_name, '|', '?');
- LLStringUtil::stripNonprintable(asset_name);
- LLStringUtil::trim(asset_name);
-
- std::string display_name = LLStringUtil::null;
- LLAssetStorage::LLStoreAssetCallback callback = NULL;
- S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
- void *userdata = NULL;
-
- upload_new_resource(
- filename,
- asset_name,
- asset_name,
- 0,
- LLFolderType::FT_NONE,
- LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- display_name,
- callback,
- expected_upload_cost,
- userdata);
-
- // *NOTE: Ew, we don't iterate over the file list here,
- // we handle the next files in upload_done_callback()
+ std::string filename = picker.getFirstFile();
+ S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+
+ while (!filename.empty())
+ {
+ std::string name = gDirUtilp->getBaseFileName(filename, true);
+
+ std::string asset_name = name;
+ LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
+ filename,
+ asset_name,
+ asset_name, 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost));
+
+ upload_new_resource(uploadInfo, NULL, NULL);
+
+ filename = picker.getNextFile();
+ }
}
else
{
@@ -621,6 +616,7 @@ void handle_compress_image(void*)
}
}
+
LLUUID upload_new_resource(
const std::string& src_filename,
std::string name,
@@ -636,276 +632,16 @@ LLUUID upload_new_resource(
S32 expected_upload_cost,
void *userdata)
{
- // Generate the temporary UUID.
- std::string filename = gDirUtilp->getTempFilename();
- LLTransactionID tid;
- LLAssetID uuid;
-
- LLSD args;
-
- std::string exten = gDirUtilp->getExtension(src_filename);
- U32 codec = LLImageBase::getCodecFromExtension(exten);
- LLAssetType::EType asset_type = LLAssetType::AT_NONE;
- std::string error_message;
-
- BOOL error = FALSE;
-
- if (exten.empty())
- {
- std::string short_name = gDirUtilp->getBaseFileName(filename);
-
- // No extension
- error_message = llformat(
- "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
- short_name.c_str());
- args["FILE"] = short_name;
- upload_error(error_message, "NoFileExtension", filename, args);
- return LLUUID();
- }
- else if (codec != IMG_CODEC_INVALID)
- {
- // It's an image file, the upload procedure is the same for all
- asset_type = LLAssetType::AT_TEXTURE;
- if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec ))
- {
- error_message = llformat( "Problem with file %s:\n\n%s\n",
- src_filename.c_str(), LLImage::getLastError().c_str());
- args["FILE"] = src_filename;
- args["ERROR"] = LLImage::getLastError();
- upload_error(error_message, "ProblemWithFile", filename, args);
- return LLUUID();
- }
- }
- else if(exten == "wav")
- {
- asset_type = LLAssetType::AT_SOUND; // tag it as audio
- S32 encode_result = 0;
-
- LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL;
-
- encode_result = encode_vorbis_file(src_filename, filename);
-
- if (LLVORBISENC_NOERR != encode_result)
- {
- switch(encode_result)
- {
- case LLVORBISENC_DEST_OPEN_ERR:
- error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
- args["FILE"] = filename;
- upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
- break;
-
- default:
- error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str());
- args["FILE"] = src_filename;
- upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
- break;
- }
- return LLUUID();
- }
- }
- else if(exten == "tmp")
- {
- // This is a generic .lin resource file
- asset_type = LLAssetType::AT_OBJECT;
- LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */
- if (in)
- {
- // read in the file header
- char buf[16384]; /* Flawfinder: ignore */
- size_t readbytes;
- S32 version;
- if (fscanf(in, "LindenResource\nversion %d\n", &version))
- {
- if (2 == version)
- {
- // *NOTE: This buffer size is hard coded into scanf() below.
- char label[MAX_STRING]; /* Flawfinder: ignore */
- char value[MAX_STRING]; /* Flawfinder: ignore */
- S32 tokens_read;
- while (fgets(buf, 1024, in))
- {
- label[0] = '\0';
- value[0] = '\0';
- tokens_read = sscanf( /* Flawfinder: ignore */
- buf,
- "%254s %254s\n",
- label, value);
-
- LL_INFOS() << "got: " << label << " = " << value
- << LL_ENDL;
-
- if (EOF == tokens_read)
- {
- fclose(in);
- error_message = llformat("corrupt resource file: %s", src_filename.c_str());
- args["FILE"] = src_filename;
- upload_error(error_message, "CorruptResourceFile", filename, args);
- return LLUUID();
- }
-
- if (2 == tokens_read)
- {
- if (! strcmp("type", label))
- {
- asset_type = (LLAssetType::EType)(atoi(value));
- }
- }
- else
- {
- if (! strcmp("_DATA_", label))
- {
- // below is the data section
- break;
- }
- }
- // other values are currently discarded
- }
-
- }
- else
- {
- fclose(in);
- error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
- args["FILE"] = src_filename;
- upload_error(error_message, "UnknownResourceFileVersion", filename, args);
- return LLUUID();
- }
- }
- else
- {
- // this is an original binary formatted .lin file
- // start over at the beginning of the file
- fseek(in, 0, SEEK_SET);
-
- const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;
- const S32 MAX_ASSET_NAME_LENGTH = 64;
- S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;
- S16 type_num;
-
- // read in and throw out most of the header except for the type
- if (fread(buf, header_size, 1, in) != 1)
- {
- LL_WARNS() << "Short read" << LL_ENDL;
- }
- memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */
- asset_type = (LLAssetType::EType)type_num;
- }
-
- // copy the file's data segment into another file for uploading
- LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */
- if (out)
- {
- while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
- {
- if (fwrite(buf, 1, readbytes, out) != readbytes)
- {
- LL_WARNS() << "Short write" << LL_ENDL;
- }
- }
- fclose(out);
- }
- else
- {
- fclose(in);
- error_message = llformat( "Unable to create output file: %s", filename.c_str());
- args["FILE"] = filename;
- upload_error(error_message, "UnableToCreateOutputFile", filename, args);
- return LLUUID();
- }
-
- fclose(in);
- }
- else
- {
- LL_INFOS() << "Couldn't open .lin file " << src_filename << LL_ENDL;
- }
- }
- else if (exten == "bvh")
- {
- error_message = llformat("We do not currently support bulk upload of animation files\n");
- upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
- return LLUUID();
- }
- else if (exten == "anim")
- {
- asset_type = LLAssetType::AT_ANIMATION;
- filename = src_filename;
- }
- else
- {
- // Unknown extension
- error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
- error = TRUE;;
- }
-
- // gen a new transaction ID for this asset
- tid.generate();
- if (!error)
- {
- uuid = tid.makeAssetID(gAgent.getSecureSessionID());
- // copy this file into the vfs for upload
- S32 file_size;
- LLAPRFile infile ;
- infile.open(filename, LL_APR_RB, NULL, &file_size);
- if (infile.getFileHandle())
- {
- LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
-
- file.setMaxSize(file_size);
-
- const S32 buf_size = 65536;
- U8 copy_buf[buf_size];
- while ((file_size = infile.read(copy_buf, buf_size)))
- {
- file.write(copy_buf, file_size);
- }
- }
- else
- {
- error_message = llformat( "Unable to access output file: %s", filename.c_str());
- error = TRUE;
- }
- }
-
- if (!error)
- {
- std::string t_disp_name = display_name;
- if (t_disp_name.empty())
- {
- t_disp_name = src_filename;
- }
- upload_new_resource(
- tid,
- asset_type,
- name,
- desc,
- compression_info, // tid
- destination_folder_type,
- inv_type,
- next_owner_perms,
- group_perms,
- everyone_perms,
- display_name,
- callback,
- expected_upload_cost,
- userdata);
- }
- else
- {
- LL_WARNS() << error_message << LL_ENDL;
- LLSD args;
- args["ERROR_MESSAGE"] = error_message;
- LLNotificationsUtil::add("ErrorMessage", args);
- if(LLFile::remove(filename) == -1)
- {
- LL_DEBUGS() << "unable to remove temp file" << LL_ENDL;
- }
- LLFilePicker::instance().reset();
- }
+ LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo(
+ src_filename,
+ name, desc, compression_info,
+ destination_folder_type, inv_type,
+ next_owner_perms, group_perms, everyone_perms,
+ expected_upload_cost));
+ upload_new_resource(uploadInfo, callback, userdata);
- return uuid;
+ return LLUUID::null;
}
void upload_done_callback(
@@ -1035,189 +771,62 @@ void upload_done_callback(
}
}
-static LLAssetID upload_new_resource_prep(
- const LLTransactionID& tid,
- LLAssetType::EType asset_type,
- LLInventoryType::EType& inventory_type,
- std::string& name,
- const std::string& display_name,
- std::string& description)
-{
- LLAssetID uuid = generate_asset_id_for_new_upload(tid);
-
- increase_new_upload_stats(asset_type);
-
- assign_defaults_and_show_upload_message(
- asset_type,
- inventory_type,
- name,
- display_name,
- description);
-
- return uuid;
-}
-
-LLSD generate_new_resource_upload_capability_body(
- LLAssetType::EType asset_type,
- const std::string& name,
- const std::string& desc,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms)
-{
- LLSD body;
-
- body["folder_id"] = gInventory.findCategoryUUIDForType(
- (destination_folder_type == LLFolderType::FT_NONE) ?
- (LLFolderType::EType) asset_type :
- destination_folder_type);
-
- body["asset_type"] = LLAssetType::lookup(asset_type);
- body["inventory_type"] = LLInventoryType::lookup(inv_type);
- body["name"] = name;
- body["description"] = desc;
- body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
- body["group_mask"] = LLSD::Integer(group_perms);
- body["everyone_mask"] = LLSD::Integer(everyone_perms);
-
- return body;
-}
-
void upload_new_resource(
- const LLTransactionID &tid,
- LLAssetType::EType asset_type,
- std::string name,
- std::string desc,
- S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata)
+ LLResourceUploadInfo::ptr_t &uploadInfo,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ void *userdata)
{
if(gDisconnected)
{
return ;
}
-
- LLAssetID uuid =
- upload_new_resource_prep(
- tid,
- asset_type,
- inv_type,
- name,
- display_name,
- desc);
-
- if( LLAssetType::AT_SOUND == asset_type )
- {
- add(LLStatViewer::UPLOAD_SOUND, 1);
- }
- else
- if( LLAssetType::AT_TEXTURE == asset_type )
- {
- add(LLStatViewer::UPLOAD_TEXTURE, 1);
- }
- else
- if( LLAssetType::AT_ANIMATION == asset_type)
- {
- add(LLStatViewer::ANIMATION_UPLOADS, 1);
- }
- if(LLInventoryType::IT_NONE == inv_type)
- {
- inv_type = LLInventoryType::defaultForAssetType(asset_type);
- }
- LLStringUtil::stripNonprintable(name);
- LLStringUtil::stripNonprintable(desc);
- if(name.empty())
- {
- name = "(No Name)";
- }
- if(desc.empty())
- {
- desc = "(No Description)";
- }
-
- // At this point, we're ready for the upload.
- std::string upload_message = "Uploading...\n\n";
- upload_message.append(display_name);
- LLUploadDialog::modalUploadDialog(upload_message);
-
- LL_INFOS() << "*** Uploading: " << LL_ENDL;
- LL_INFOS() << "Type: " << LLAssetType::lookup(asset_type) << LL_ENDL;
- LL_INFOS() << "UUID: " << uuid << LL_ENDL;
- LL_INFOS() << "Name: " << name << LL_ENDL;
- LL_INFOS() << "Desc: " << desc << LL_ENDL;
- LL_INFOS() << "Expected Upload Cost: " << expected_upload_cost << LL_ENDL;
- LL_DEBUGS() << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << LL_ENDL;
- LL_DEBUGS() << "Asset Type: " << LLAssetType::lookup(asset_type) << LL_ENDL;
-
- std::string url = gAgent.getRegion()->getCapability(
- "NewFileAgentInventory");
+// uploadInfo->setAssetType(assetType);
+// uploadInfo->setTransactionId(tid);
+
+
+ std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
if ( !url.empty() )
{
- LL_INFOS() << "New Agent Inventory via capability" << LL_ENDL;
-
- LLSD body;
- body = generate_new_resource_upload_capability_body(
- asset_type,
- name,
- desc,
- destination_folder_type,
- inv_type,
- next_owner_perms,
- group_perms,
- everyone_perms);
-
- LLHTTPClient::post(
- url,
- body,
- new LLNewAgentInventoryResponder(
- body,
- uuid,
- asset_type));
+ LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
}
else
{
+ uploadInfo->prepareUpload();
+ uploadInfo->logPreparedUpload();
+
LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL;
// check for adequate funds
// TODO: do this check on the sim
- if (LLAssetType::AT_SOUND == asset_type ||
- LLAssetType::AT_TEXTURE == asset_type ||
- LLAssetType::AT_ANIMATION == asset_type)
+ if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() ||
+ LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() ||
+ LLAssetType::AT_ANIMATION == uploadInfo->getAssetType())
{
S32 balance = gStatusBar->getBalance();
- if (balance < expected_upload_cost)
+ if (balance < uploadInfo->getExpectedUploadCost())
{
// insufficient funds, bail on this upload
LLStringUtil::format_map_t args;
- args["NAME"] = name;
- args["AMOUNT"] = llformat("%d", expected_upload_cost);
- LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
+ args["NAME"] = uploadInfo->getName();
+ args["AMOUNT"] = llformat("%d", uploadInfo->getExpectedUploadCost());
+ LLBuyCurrencyHTML::openCurrencyFloater(LLTrans::getString("UploadingCosts", args), uploadInfo->getExpectedUploadCost());
return;
}
}
LLResourceData* data = new LLResourceData;
- data->mAssetInfo.mTransactionID = tid;
- data->mAssetInfo.mUuid = uuid;
- data->mAssetInfo.mType = asset_type;
+ data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId();
+ data->mAssetInfo.mUuid = uploadInfo->getAssetId();
+ data->mAssetInfo.mType = uploadInfo->getAssetType();
data->mAssetInfo.mCreatorID = gAgentID;
- data->mInventoryType = inv_type;
- data->mNextOwnerPerm = next_owner_perms;
- data->mExpectedUploadCost = expected_upload_cost;
+ data->mInventoryType = uploadInfo->getInventoryType();
+ data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms();
+ data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost();
data->mUserData = userdata;
- data->mAssetInfo.setName(name);
- data->mAssetInfo.setDescription(desc);
- data->mPreferredLocation = destination_folder_type;
+ data->mAssetInfo.setName(uploadInfo->getName());
+ data->mAssetInfo.setDescription(uploadInfo->getDescription());
+ data->mPreferredLocation = uploadInfo->getDestinationFolderType();
LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
if (callback)
@@ -1233,66 +842,6 @@ void upload_new_resource(
}
}
-LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
-{
- if ( gDisconnected )
- {
- LLAssetID rv;
-
- rv.setNull();
- return rv;
- }
-
- LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
-
- return uuid;
-}
-
-void increase_new_upload_stats(LLAssetType::EType asset_type)
-{
- if ( LLAssetType::AT_SOUND == asset_type )
- {
- add(LLStatViewer::UPLOAD_SOUND, 1);
- }
- else if ( LLAssetType::AT_TEXTURE == asset_type )
- {
- add(LLStatViewer::UPLOAD_TEXTURE, 1);
- }
- else if ( LLAssetType::AT_ANIMATION == asset_type )
- {
- add(LLStatViewer::ANIMATION_UPLOADS, 1);
- }
-}
-
-void assign_defaults_and_show_upload_message(
- LLAssetType::EType asset_type,
- LLInventoryType::EType& inventory_type,
- std::string& name,
- const std::string& display_name,
- std::string& description)
-{
- if ( LLInventoryType::IT_NONE == inventory_type )
- {
- inventory_type = LLInventoryType::defaultForAssetType(asset_type);
- }
- LLStringUtil::stripNonprintable(name);
- LLStringUtil::stripNonprintable(description);
-
- if ( name.empty() )
- {
- name = "(No Name)";
- }
- if ( description.empty() )
- {
- description = "(No Description)";
- }
-
- // At this point, we're ready for the upload.
- std::string upload_message = "Uploading...\n\n";
- upload_message.append(display_name);
- LLUploadDialog::modalUploadDialog(upload_message);
-}
-
void init_menu_file()
{
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index 3034d00b22..6941b4dc0e 100755
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -34,45 +34,35 @@
#include "llthread.h"
#include <queue>
+#include "llviewerassetupload.h"
+
class LLTransactionID;
void init_menu_file();
+
LLUUID upload_new_resource(
- const std::string& src_filename,
- std::string name,
- std::string desc,
- S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata);
+ const std::string& src_filename,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata);
void upload_new_resource(
- const LLTransactionID &tid,
- LLAssetType::EType type,
- std::string name,
- std::string desc,
- S32 compression_info,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms,
- const std::string& display_name,
- LLAssetStorage::LLStoreAssetCallback callback,
- S32 expected_upload_cost,
- void *userdata);
+ LLResourceUploadInfo::ptr_t &uploadInfo,
+ LLAssetStorage::LLStoreAssetCallback callback = NULL,
+ void *userdata = NULL);
-LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid);
-void increase_new_upload_stats(LLAssetType::EType asset_type);
void assign_defaults_and_show_upload_message(
LLAssetType::EType asset_type,
LLInventoryType::EType& inventory_type,
@@ -80,26 +70,6 @@ void assign_defaults_and_show_upload_message(
const std::string& display_name,
std::string& description);
-LLSD generate_new_resource_upload_capability_body(
- LLAssetType::EType asset_type,
- const std::string& name,
- const std::string& desc,
- LLFolderType::EType destination_folder_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perms,
- U32 group_perms,
- U32 everyone_perms);
-
-void on_new_single_inventory_upload_complete(
- LLAssetType::EType asset_type,
- LLInventoryType::EType inventory_type,
- const std::string inventory_type_string,
- const LLUUID& item_folder_id,
- const std::string& item_name,
- const std::string& item_description,
- const LLSD& server_response,
- S32 upload_price);
-
class LLFilePickerThread : public LLThread
{ //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread)
public:
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 886725be79..4062228ae5 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -120,6 +120,8 @@
#include "llnotificationmanager.h" //
#include "llexperiencecache.h"
+#include "llexperiencecache.h"
+
#if LL_MSVC
// disable boost::lexical_cast warning
#pragma warning (disable:4702)
@@ -3490,53 +3492,29 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)
LLNotificationsUtil::add("CallingCardDeclined");
}
-class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
+void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std::string expectLang, std::string translation, const std::string detected_language)
{
-public :
- ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg,
- const LLChat &chat, const LLSD &toast_args)
- : LLTranslate::TranslationReceiver(from_lang, to_lang),
- m_chat(chat),
- m_toastArgs(toast_args),
- m_origMesg(mesg)
- {
- }
-
- static ChatTranslationReceiver* build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args)
- {
- return new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args);
- }
-
-protected:
- void handleResponse(const std::string &translation, const std::string &detected_language)
- {
- // filter out non-interesting responeses
- if ( !translation.empty()
- && (mToLang != detected_language)
- && (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) )
- {
- m_chat.mText += " (" + translation + ")";
- }
+ // filter out non-interesting responses
+ if (!translation.empty()
+ && (expectLang != detected_language)
+ && (LLStringUtil::compareInsensitive(translation, originalMsg) != 0))
+ {
+ chat.mText += " (" + translation + ")";
+ }
- LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs);
- }
+ LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs);
+}
- void handleFailure(int status, const std::string& err_msg)
- {
- LL_WARNS() << "Translation failed for mesg " << m_origMesg << " toLang " << mToLang << " fromLang " << mFromLang << LL_ENDL;
+void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string err_msg)
+{
+ std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
+ LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
+ chat.mText += " (" + msg + ")";
- std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg));
- LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages
- m_chat.mText += " (" + msg + ")";
+ LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs);
+}
- LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs);
- }
-private:
- LLChat m_chat;
- std::string m_origMesg;
- LLSD m_toastArgs;
-};
void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
{
LLChat chat;
@@ -3772,8 +3750,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
const std::string from_lang = ""; // leave empty to trigger autodetect
const std::string to_lang = LLTranslate::getTranslateLanguage();
- LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, args);
- LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
+ LLTranslate::translateMessage(from_lang, to_lang, mesg,
+ boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2),
+ boost::bind(&translateFailure, chat, args, _1, _2));
+
}
else
{
@@ -6468,17 +6448,14 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
if (!region)
return false;
- std::string lookup_url=region->getCapability("ExperiencePreferences");
- if(lookup_url.empty())
- return false;
- LLSD permission;
- LLSD data;
- permission["permission"]="Block";
+ LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), LLExperienceCache::ExperienceGetFn_t());
- data[experience.asString()]=permission;
- LLHTTPClient::put(lookup_url, data, NULL);
- data["experience"]=experience;
- LLEventPumps::instance().obtain("experience_permission").post(data);
+ LLSD permission;
+ LLSD data;
+ permission["permission"] = "Block";
+ data[experience.asString()] = permission;
+ data["experience"] = experience;
+ LLEventPumps::instance().obtain("experience_permission").post(data);
}
}
return false;
@@ -6653,7 +6630,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
else if(experienceid.notNull())
{
payload["experience"]=experienceid;
- LLExperienceCache::get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
+ LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
return;
}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index ac3f07fcd8..190102ff0f 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4437,21 +4437,21 @@ S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid)
{
// Invalid host == get from the agent's sim
LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(
- uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid);
+ uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost());
return setTETextureCore(te,image);
}
S32 LLViewerObject::setTENormalMap(const U8 te, const LLUUID& uuid)
{
LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture(
- uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid);
+ uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost());
return setTENormalMapCore(te, image);
}
S32 LLViewerObject::setTESpecularMap(const U8 te, const LLUUID& uuid)
{
LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture(
- uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid);
+ uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost());
return setTESpecularMapCore(te, image);
}
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 75732a1e19..5f01cdbb6f 100755
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -78,6 +78,10 @@
#include "llappviewer.h"
#include "llfloaterperms.h"
#include "llvocache.h"
+#include "llcorehttputil.h"
+
+#include <algorithm>
+#include <iterator>
extern F32 gMinObjectDistance;
extern BOOL gAnimateTextures;
@@ -795,190 +799,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
LLVOAvatar::cullAvatarsByPixelArea();
}
-class LLObjectCostResponder : public LLCurl::Responder
-{
- LOG_CLASS(LLObjectCostResponder);
-public:
- LLObjectCostResponder(const LLSD& object_ids)
- : mObjectIDs(object_ids)
- {
- }
-
- // Clear's the global object list's pending
- // request list for all objects requested
- void clear_object_list_pending_requests()
- {
- // TODO*: No more hard coding
- for (
- LLSD::array_iterator iter = mObjectIDs.beginArray();
- iter != mObjectIDs.endArray();
- ++iter)
- {
- gObjectList.onObjectCostFetchFailure(iter->asUUID());
- }
- }
-
-private:
- /* virtual */ void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- // TODO*: Error message to user
- // For now just clear the request from the pending list
- clear_object_list_pending_requests();
- }
-
- /* virtual */ void httpSuccess()
- {
- const LLSD& content = getContent();
- if ( !content.isMap() || content.has("error") )
- {
- // Improper response or the request had an error,
- // show an error to the user?
- LL_WARNS()
- << "Application level error when fetching object "
- << "cost. Message: " << content["error"]["message"].asString()
- << ", identifier: " << content["error"]["identifier"].asString()
- << LL_ENDL;
-
- // TODO*: Adaptively adjust request size if the
- // service says we've requested too many and retry
-
- // TODO*: Error message if not retrying
- clear_object_list_pending_requests();
- return;
- }
-
- // Success, grab the resource cost and linked set costs
- // for an object if one was returned
- for (
- LLSD::array_iterator iter = mObjectIDs.beginArray();
- iter != mObjectIDs.endArray();
- ++iter)
- {
- LLUUID object_id = iter->asUUID();
-
- // Check to see if the request contains data for the object
- if ( content.has(iter->asString()) )
- {
- F32 link_cost =
- content[iter->asString()]["linked_set_resource_cost"].asReal();
- F32 object_cost =
- content[iter->asString()]["resource_cost"].asReal();
-
- F32 physics_cost = content[iter->asString()]["physics_cost"].asReal();
- F32 link_physics_cost = content[iter->asString()]["linked_set_physics_cost"].asReal();
-
- gObjectList.updateObjectCost(object_id, object_cost, link_cost, physics_cost, link_physics_cost);
- }
- else
- {
- // TODO*: Give user feedback about the missing data?
- gObjectList.onObjectCostFetchFailure(object_id);
- }
- }
- }
-
-private:
- LLSD mObjectIDs;
-};
-
-
-class LLPhysicsFlagsResponder : public LLCurl::Responder
-{
- LOG_CLASS(LLPhysicsFlagsResponder);
-public:
- LLPhysicsFlagsResponder(const LLSD& object_ids)
- : mObjectIDs(object_ids)
- {
- }
-
- // Clear's the global object list's pending
- // request list for all objects requested
- void clear_object_list_pending_requests()
- {
- // TODO*: No more hard coding
- for (
- LLSD::array_iterator iter = mObjectIDs.beginArray();
- iter != mObjectIDs.endArray();
- ++iter)
- {
- gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID());
- }
- }
-
-private:
- /* virtual */ void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
-
- // TODO*: Error message to user
- // For now just clear the request from the pending list
- clear_object_list_pending_requests();
- }
-
- /* virtual void */ void httpSuccess()
- {
- const LLSD& content = getContent();
- if ( !content.isMap() || content.has("error") )
- {
- // Improper response or the request had an error,
- // show an error to the user?
- LL_WARNS()
- << "Application level error when fetching object "
- << "physics flags. Message: " << content["error"]["message"].asString()
- << ", identifier: " << content["error"]["identifier"].asString()
- << LL_ENDL;
-
- // TODO*: Adaptively adjust request size if the
- // service says we've requested too many and retry
-
- // TODO*: Error message if not retrying
- clear_object_list_pending_requests();
- return;
- }
-
- // Success, grab the resource cost and linked set costs
- // for an object if one was returned
- for (
- LLSD::array_iterator iter = mObjectIDs.beginArray();
- iter != mObjectIDs.endArray();
- ++iter)
- {
- LLUUID object_id = iter->asUUID();
-
- // Check to see if the request contains data for the object
- if ( content.has(iter->asString()) )
- {
- const LLSD& data = content[iter->asString()];
-
- S32 shape_type = data["PhysicsShapeType"].asInteger();
-
- gObjectList.updatePhysicsShapeType(object_id, shape_type);
-
- if (data.has("Density"))
- {
- F32 density = data["Density"].asReal();
- F32 friction = data["Friction"].asReal();
- F32 restitution = data["Restitution"].asReal();
- F32 gravity_multiplier = data["GravityMultiplier"].asReal();
-
- gObjectList.updatePhysicsProperties(object_id,
- density, friction, restitution, gravity_multiplier);
- }
- }
- else
- {
- // TODO*: Give user feedback about the missing data?
- gObjectList.onPhysicsFlagsFetchFailure(object_id);
- }
- }
- }
-
-private:
- LLSD mObjectIDs;
-};
-
static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy");
void LLViewerObjectList::update(LLAgent &agent)
@@ -1174,41 +994,8 @@ void LLViewerObjectList::fetchObjectCosts()
if (!url.empty())
{
- LLSD id_list;
- U32 object_index = 0;
-
- for (
- std::set<LLUUID>::iterator iter = mStaleObjectCost.begin();
- iter != mStaleObjectCost.end();
- )
- {
- // Check to see if a request for this object
- // has already been made.
- if ( mPendingObjectCost.find(*iter) ==
- mPendingObjectCost.end() )
- {
- mPendingObjectCost.insert(*iter);
- id_list[object_index++] = *iter;
- }
-
- mStaleObjectCost.erase(iter++);
-
- if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS)
- {
- break;
- }
- }
-
- if ( id_list.size() > 0 )
- {
- LLSD post_data = LLSD::emptyMap();
-
- post_data["object_ids"] = id_list;
- LLHTTPClient::post(
- url,
- post_data,
- new LLObjectCostResponder(id_list));
- }
+ LLCoros::instance().launch("LLViewerObjectList::fetchObjectCostsCoro",
+ boost::bind(&LLViewerObjectList::fetchObjectCostsCoro, this, url));
}
else
{
@@ -1219,6 +1006,107 @@ void LLViewerObjectList::fetchObjectCosts()
}
}
+/*static*/
+void LLViewerObjectList::reportObjectCostFailure(LLSD &objectList)
+{
+ // TODO*: No more hard coding
+ for (LLSD::array_iterator it = objectList.beginArray(); it != objectList.endArray(); ++it)
+ {
+ gObjectList.onObjectCostFetchFailure(it->asUUID());
+ }
+}
+
+
+void LLViewerObjectList::fetchObjectCostsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+
+
+ uuid_set_t diff;
+
+ std::set_difference(mStaleObjectCost.begin(), mStaleObjectCost.end(),
+ mPendingObjectCost.begin(), mPendingObjectCost.end(),
+ std::inserter(diff, diff.begin()));
+
+ if (diff.empty())
+ {
+ LL_INFOS() << "No outstanding object IDs to request." << LL_ENDL;
+ return;
+ }
+
+ LLSD idList(LLSD::emptyArray());
+
+ for (uuid_set_t::iterator it = diff.begin(); it != diff.end(); ++it)
+ {
+ idList.append(*it);
+ mStaleObjectCost.erase(*it);
+ }
+
+ mPendingObjectCost.insert(diff.begin(), diff.end());
+
+ LLSD postData = LLSD::emptyMap();
+
+ postData["object_ids"] = idList;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status || result.has("error"))
+ {
+ if (result.has("error"))
+ {
+ LL_WARNS() << "Application level error when fetching object "
+ << "cost. Message: " << result["error"]["message"].asString()
+ << ", identifier: " << result["error"]["identifier"].asString()
+ << LL_ENDL;
+
+ // TODO*: Adaptively adjust request size if the
+ // service says we've requested too many and retry
+ }
+ reportObjectCostFailure(idList);
+
+ return;
+ }
+
+ // Success, grab the resource cost and linked set costs
+ // for an object if one was returned
+ for (LLSD::array_iterator it = idList.beginArray(); it != idList.endArray(); ++it)
+ {
+ LLUUID objectId = it->asUUID();
+
+ // If the object was added to the StaleObjectCost set after it had been
+ // added to mPendingObjectCost it would still be in the StaleObjectCost
+ // set when we got the response back.
+ mStaleObjectCost.erase(objectId);
+ mPendingObjectCost.erase(objectId);
+
+ // Check to see if the request contains data for the object
+ if (result.has(it->asString()))
+ {
+ LLSD objectData = result[it->asString()];
+
+ F32 linkCost = objectData["linked_set_resource_cost"].asReal();
+ F32 objectCost = objectData["resource_cost"].asReal();
+ F32 physicsCost = objectData["physics_cost"].asReal();
+ F32 linkPhysicsCost = objectData["linked_set_physics_cost"].asReal();
+
+ gObjectList.updateObjectCost(objectId, objectCost, linkCost, physicsCost, linkPhysicsCost);
+ }
+ else
+ {
+ // TODO*: Give user feedback about the missing data?
+ gObjectList.onObjectCostFetchFailure(objectId);
+ }
+ }
+
+}
+
void LLViewerObjectList::fetchPhysicsFlags()
{
// issue http request for stale object physics flags
@@ -1232,41 +1120,8 @@ void LLViewerObjectList::fetchPhysicsFlags()
if (!url.empty())
{
- LLSD id_list;
- U32 object_index = 0;
-
- for (
- std::set<LLUUID>::iterator iter = mStalePhysicsFlags.begin();
- iter != mStalePhysicsFlags.end();
- )
- {
- // Check to see if a request for this object
- // has already been made.
- if ( mPendingPhysicsFlags.find(*iter) ==
- mPendingPhysicsFlags.end() )
- {
- mPendingPhysicsFlags.insert(*iter);
- id_list[object_index++] = *iter;
- }
-
- mStalePhysicsFlags.erase(iter++);
-
- if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS)
- {
- break;
- }
- }
-
- if ( id_list.size() > 0 )
- {
- LLSD post_data = LLSD::emptyMap();
-
- post_data["object_ids"] = id_list;
- LLHTTPClient::post(
- url,
- post_data,
- new LLPhysicsFlagsResponder(id_list));
- }
+ LLCoros::instance().launch("LLViewerObjectList::fetchPhisicsFlagsCoro",
+ boost::bind(&LLViewerObjectList::fetchPhisicsFlagsCoro, this, url));
}
else
{
@@ -1277,6 +1132,109 @@ void LLViewerObjectList::fetchPhysicsFlags()
}
}
+/*static*/
+void LLViewerObjectList::reportPhysicsFlagFailure(LLSD &objectList)
+{
+ // TODO*: No more hard coding
+ for (LLSD::array_iterator it = objectList.beginArray(); it != objectList.endArray(); ++it)
+ {
+ gObjectList.onPhysicsFlagsFetchFailure(it->asUUID());
+ }
+}
+
+void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD idList;
+ U32 objectIndex = 0;
+
+ for (uuid_set_t::iterator it = mStalePhysicsFlags.begin(); it != mStalePhysicsFlags.end();)
+ {
+ // Check to see if a request for this object
+ // has already been made.
+ if (mPendingPhysicsFlags.find(*it) == mPendingPhysicsFlags.end())
+ {
+ mPendingPhysicsFlags.insert(*it);
+ idList[objectIndex++] = *it;
+ }
+
+ mStalePhysicsFlags.erase(it++);
+
+ if (objectIndex >= MAX_CONCURRENT_PHYSICS_REQUESTS)
+ {
+ break;
+ }
+ }
+
+ if (idList.size() < 1)
+ {
+ LL_INFOS() << "No outstanding object physics flags to request." << LL_ENDL;
+ return;
+ }
+
+ LLSD postData = LLSD::emptyMap();
+
+ postData["object_ids"] = idList;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status || result.has("error"))
+ {
+ if (result.has("error"))
+ {
+ LL_WARNS() << "Application level error when fetching object "
+ << "physics flags. Message: " << result["error"]["message"].asString()
+ << ", identifier: " << result["error"]["identifier"].asString()
+ << LL_ENDL;
+
+ // TODO*: Adaptively adjust request size if the
+ // service says we've requested too many and retry
+ }
+ reportPhysicsFlagFailure(idList);
+
+ return;
+ }
+
+ // Success, grab the resource cost and linked set costs
+ // for an object if one was returned
+ for (LLSD::array_iterator it = idList.beginArray(); it != idList.endArray(); ++it)
+ {
+ LLUUID objectId = it->asUUID();
+
+ // Check to see if the request contains data for the object
+ if (result.has(it->asString()))
+ {
+ const LLSD& data = result[it->asString()];
+
+ S32 shapeType = data["PhysicsShapeType"].asInteger();
+
+ gObjectList.updatePhysicsShapeType(objectId, shapeType);
+
+ if (data.has("Density"))
+ {
+ F32 density = data["Density"].asReal();
+ F32 friction = data["Friction"].asReal();
+ F32 restitution = data["Restitution"].asReal();
+ F32 gravityMult = data["GravityMultiplier"].asReal();
+
+ gObjectList.updatePhysicsProperties(objectId, density,
+ friction, restitution, gravityMult);
+ }
+ }
+ else
+ {
+ // TODO*: Give user feedback about the missing data?
+ gObjectList.onPhysicsFlagsFetchFailure(objectId);
+ }
+ }
+}
void LLViewerObjectList::clearDebugText()
{
@@ -1563,8 +1521,6 @@ void LLViewerObjectList::updateObjectCost(LLViewerObject* object)
void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost)
{
- mPendingObjectCost.erase(object_id);
-
LLViewerObject* object = findObject(object_id);
if (object)
{
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 594317cd9f..94c751acc6 100755
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -36,6 +36,8 @@
// project includes
#include "llviewerobject.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLCamera;
class LLNetMap;
@@ -203,17 +205,17 @@ protected:
vobj_list_t mMapObjects;
- std::set<LLUUID> mDeadObjects;
+ uuid_set_t mDeadObjects;
std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap;
//set of objects that need to update their cost
- std::set<LLUUID> mStaleObjectCost;
- std::set<LLUUID> mPendingObjectCost;
+ uuid_set_t mStaleObjectCost;
+ uuid_set_t mPendingObjectCost;
//set of objects that need to update their physics flags
- std::set<LLUUID> mStalePhysicsFlags;
- std::set<LLUUID> mPendingPhysicsFlags;
+ uuid_set_t mStalePhysicsFlags;
+ uuid_set_t mPendingPhysicsFlags;
std::vector<LLDebugBeacon> mDebugBeacons;
@@ -227,6 +229,14 @@ protected:
std::set<LLViewerObject *> mSelectPickList;
friend class LLViewerObject;
+
+private:
+ static void reportObjectCostFailure(LLSD &objectList);
+ void fetchObjectCostsCoro(std::string url);
+
+ static void reportPhysicsFlagFailure(LLSD &obejectList);
+ void fetchPhisicsFlagsCoro(std::string url);
+
};
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 37b249dddd..828271da7a 100755
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -43,6 +43,7 @@
//#include "llfirstuse.h"
#include "llpluginclassmedia.h"
#include "llviewertexture.h"
+#include "llcorehttputil.h"
// Static Variables
@@ -457,6 +458,7 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void *
}
// Static
/////////////////////////////////////////////////////////////////////////////////////////
+// *TODO: I can not find any active code where this method is called...
void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url)
{
std::string region_url = gAgent.getRegion()->getCapability("ParcelNavigateMedia");
@@ -467,7 +469,9 @@ void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url)
body["agent-id"] = gAgent.getID();
body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID();
body["url"] = url;
- LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder);
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(region_url, body,
+ "Media Navigation sent to sim.", "Media Navigation failed to send to sim.");
}
else
{
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 2a6b105cab..f8c13239a0 100755
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -67,6 +67,7 @@
#include "roles_constants.h"
#include "llweb.h"
#include "llvieweraudio.h"
+#include "llcorehttputil.h"
const F32 PARCEL_COLLISION_DRAW_SECS = 1.f;
@@ -1286,10 +1287,13 @@ const std::string& LLViewerParcelMgr::getAgentParcelName() const
void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region)
{
- if(!parcel) return;
+ if(!parcel)
+ return;
LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
- if (!region) return;
+ if (!region)
+ return;
+
//LL_INFOS() << "found region: " << region->getName() << LL_ENDL;
LLSD body;
@@ -1302,7 +1306,9 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag
parcel->packMessage(body);
LL_INFOS() << "Sending parcel properties update via capability to: "
<< url << LL_ENDL;
- LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
+
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+ "Parcel Properties sent to sim.", "Parcel Properties failed to send to sim.");
}
else
{
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 6af3e40f01..b0280ef3e0 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -34,7 +34,6 @@
#include "llavatarnamecache.h" // name lookup cap url
#include "llfloaterreg.h"
#include "llmath.h"
-#include "llhttpclient.h"
#include "llregionflags.h"
#include "llregionhandle.h"
#include "llsurface.h"
@@ -47,8 +46,6 @@
#include "llagentcamera.h"
#include "llavatarrenderinfoaccountant.h"
#include "llcallingcard.h"
-#include "llcaphttpsender.h"
-#include "llcapabilitylistener.h"
#include "llcommandhandler.h"
#include "lldir.h"
#include "lleventpoll.h"
@@ -78,6 +75,9 @@
#include "llviewerdisplay.h"
#include "llviewerwindow.h"
#include "llprogressview.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
#ifdef LL_WINDOWS
#pragma warning(disable:4355)
@@ -92,7 +92,6 @@
// We want to allow for seed cap retry, but its not useful after that 60 seconds.
// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up.
const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3;
-const F32 CAP_REQUEST_TIMEOUT = 18;
// Even though we gave up on login, keep trying for caps after we are logged in:
const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000;
@@ -105,31 +104,62 @@ typedef std::map<std::string, std::string> CapabilityMap;
static void log_capabilities(const CapabilityMap &capmap);
-class LLViewerRegionImpl {
+// support for secondlife:///app/region/{REGION} SLapps
+// N.B. this is defined to work exactly like the classic secondlife://{REGION}
+// However, the later syntax cannot support spaces in the region name because
+// spaces (and %20 chars) are illegal in the hostname of an http URL. Some
+// browsers let you get away with this, but some do not (such as Qt's Webkit).
+// Hence we introduced the newer secondlife:///app/region alternative.
+class LLRegionHandler : public LLCommandHandler
+{
+public:
+ // requests will be throttled from a non-trusted browser
+ LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {}
+
+ bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ // make sure that we at least have a region name
+ int num_params = params.size();
+ if (num_params < 1)
+ {
+ return false;
+ }
+
+ // build a secondlife://{PLACE} SLurl from this SLapp
+ std::string url = "secondlife://";
+ for (int i = 0; i < num_params; i++)
+ {
+ if (i > 0)
+ {
+ url += "/";
+ }
+ url += params[i].asString();
+ }
+
+ // Process the SLapp as if it was a secondlife://{PLACE} SLurl
+ LLURLDispatcher::dispatch(url, "clicked", web, true);
+ return true;
+ }
+
+};
+LLRegionHandler gRegionHandler;
+
+
+class LLViewerRegionImpl
+{
public:
- LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host)
- : mHost(host),
- mCompositionp(NULL),
- mEventPoll(NULL),
- mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS),
- mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN),
- mSeedCapAttempts(0),
- mHttpResponderID(0),
- mLastCameraUpdate(0),
- mLastCameraOrigin(),
- mVOCachePartition(NULL),
- mLandp(NULL),
- // I'd prefer to set the LLCapabilityListener name to match the region
- // name -- it's disappointing that's not available at construction time.
- // We could instead store an LLCapabilityListener*, making
- // setRegionNameAndZone() replace the instance. Would that pose
- // consistency problems? Can we even request a capability before calling
- // setRegionNameAndZone()?
- // For testability -- the new Michael Feathers paradigm --
- // LLCapabilityListener binds all the globals it expects to need at
- // construction time.
- mCapabilityListener(host.getString(), gMessageSystem, *region,
- gAgent.getID(), gAgent.getSessionID())
+ LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host):
+ mHost(host),
+ mCompositionp(NULL),
+ mEventPoll(NULL),
+ mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS),
+ mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN),
+ mSeedCapAttempts(0),
+ mHttpResponderID(0),
+ mLastCameraUpdate(0),
+ mLastCameraOrigin(),
+ mVOCachePartition(NULL),
+ mLandp(NULL)
{}
void buildCapabilityNames(LLSD& capabilityNames);
@@ -181,220 +211,292 @@ public:
S32 mHttpResponderID;
- /// Post an event to this LLCapabilityListener to invoke a capability message on
- /// this LLViewerRegion's server
- /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
- LLCapabilityListener mCapabilityListener;
-
//spatial partitions for objects in this region
std::vector<LLViewerOctreePartition*> mObjectPartition;
- LLVector3 mLastCameraOrigin;
- U32 mLastCameraUpdate;
-};
-
-// support for secondlife:///app/region/{REGION} SLapps
-// N.B. this is defined to work exactly like the classic secondlife://{REGION}
-// However, the later syntax cannot support spaces in the region name because
-// spaces (and %20 chars) are illegal in the hostname of an http URL. Some
-// browsers let you get away with this, but some do not (such as Qt's Webkit).
-// Hence we introduced the newer secondlife:///app/region alternative.
-class LLRegionHandler : public LLCommandHandler
-{
-public:
- // requests will be throttled from a non-trusted browser
- LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {}
-
- bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
- {
- // make sure that we at least have a region name
- int num_params = params.size();
- if (num_params < 1)
- {
- return false;
- }
-
- // build a secondlife://{PLACE} SLurl from this SLapp
- std::string url = "secondlife://";
- for (int i = 0; i < num_params; i++)
- {
- if (i > 0)
- {
- url += "/";
- }
- url += params[i].asString();
- }
+ LLVector3 mLastCameraOrigin;
+ U32 mLastCameraUpdate;
- // Process the SLapp as if it was a secondlife://{PLACE} SLurl
- LLURLDispatcher::dispatch(url, "clicked", web, true);
- return true;
- }
+ void requestBaseCapabilitiesCoro(U64 regionHandle);
+ void requestBaseCapabilitiesCompleteCoro(U64 regionHandle);
+ void requestSimulatorFeatureCoro(std::string url, U64 regionHandle);
};
-LLRegionHandler gRegionHandler;
-class BaseCapabilitiesComplete : public LLHTTPClient::Responder
+void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)
{
- LOG_CLASS(BaseCapabilitiesComplete);
-public:
- BaseCapabilitiesComplete(U64 region_handle, S32 id)
- : mRegionHandle(region_handle), mID(id)
- { }
- virtual ~BaseCapabilitiesComplete()
- { }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- static BaseCapabilitiesComplete* build( U64 region_handle, S32 id )
- {
- return new BaseCapabilitiesComplete(region_handle, id);
- }
+ LLSD result;
+ LLViewerRegion *regionp = NULL;
-private:
- /* virtual */void httpFailure()
- {
- LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL;
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if (regionp)
- {
- regionp->failedSeedCapability();
- }
- }
+ // This loop is used for retrying a capabilities request.
+ do
+ {
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ std::string url = regionp->getCapability("Seed");
+ if (url.empty())
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ // After a few attempts, continue login. But keep trying to get the caps:
+ if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin &&
+ STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
+ {
+ LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+ }
+
+ if (mSeedCapAttempts > mSeedCapMaxAttempts)
+ {
+ // *TODO: Give a user pop-up about this error?
+ LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ S32 id = ++mHttpResponderID;
+ ++mSeedCapAttempts;
+
+ LLSD capabilityNames = LLSD::emptyArray();
+ buildCapabilityNames(capabilityNames);
+
+ LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url
+ << " (attempt #" << mSeedCapAttempts << ")" << LL_ENDL;
+
+ regionp = NULL;
+ result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
+ return; // this error condition is not recoverable.
+ }
+
+ if (id != mHttpResponderID) // region is no longer referring to this request
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL;
+ // setup for retry.
+ continue;
+ }
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL;
+ // setup for retry.
+ continue;
+ }
+
+ // remove the http_result from the llsd
+ result.erase("http_result");
+
+ LLSD::map_const_iterator iter;
+ for (iter = result.beginMap(); iter != result.endMap(); ++iter)
+ {
+ regionp->setCapability(iter->first, iter->second);
+
+ LL_DEBUGS("AppInit", "Capabilities")
+ << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;
+ }
- /* virtual */ void httpSuccess()
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if(!regionp) //region was removed
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;
- return ;
- }
- if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL;
- regionp->failedSeedCapability();
- return ;
- }
+#if 0
+ log_capabilities(mCapabilities);
+#endif
- 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);
+ regionp->setCapabilitiesReceived(true);
- LL_DEBUGS("AppInit", "Capabilities")
- << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;
+ if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
+ {
+ LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED);
+ }
- /* HACK we're waiting for the ServerReleaseNotes */
- if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested())
- {
- regionp->showReleaseNotes();
- }
- }
+ break;
+ }
+ while (true);
- regionp->setCapabilitiesReceived(true);
+ if (regionp && regionp->isCapabilityAvailable("ServerReleaseNotes") &&
+ regionp->getReleaseNotesRequested())
+ { // *HACK: we're waiting for the ServerReleaseNotes
+ regionp->showReleaseNotes();
+ }
- if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
- {
- LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
- }
- }
+}
-private:
- U64 mRegionHandle;
- S32 mID;
-};
-class BaseCapabilitiesCompleteTracker : public LLHTTPClient::Responder
+void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)
{
- LOG_CLASS(BaseCapabilitiesCompleteTracker);
-public:
- BaseCapabilitiesCompleteTracker( U64 region_handle)
- : mRegionHandle(region_handle)
- { }
-
- virtual ~BaseCapabilitiesCompleteTracker()
- { }
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- static BaseCapabilitiesCompleteTracker* build( U64 region_handle )
- {
- return new BaseCapabilitiesCompleteTracker( region_handle );
- }
+ LLSD result;
+ LLViewerRegion *regionp = NULL;
-private:
- /* virtual */ void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
+ // This loop is used for retrying a capabilities request.
+ do
+ {
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ std::string url = regionp->getCapabilityDebug("Seed");
+ if (url.empty())
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ LLSD capabilityNames = LLSD::emptyArray();
+ buildCapabilityNames(capabilityNames);
+
+ LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << LL_ENDL;
+
+ regionp = NULL;
+ result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames);
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL;
+ break; // no retry
+ }
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ // remove the http_result from the llsd
+ result.erase("http_result");
+
+ LLSD::map_const_iterator iter;
+ for (iter = result.beginMap(); iter != result.endMap(); ++iter)
+ {
+ regionp->setCapabilityDebug(iter->first, iter->second);
+ //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL;
+ }
- /* virtual */ void httpSuccess()
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if( !regionp )
- {
- LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL;
- return ;
- }
+#if 0
+ log_capabilities(mCapabilities);
+#endif
- 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->setCapabilityDebug(iter->first, iter->second);
- //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL;
- }
-
- if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )
- {
- LL_WARNS("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;
+ if (mCapabilities.size() != mSecondCapabilitiesTracker.size())
+ {
+ LL_WARNS("AppInit", "Capabilities")
+ << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. "
+ << "mCapabilities == " << mCapabilities.size()
+ << " mSecondCapabilitiesTracker == " << mSecondCapabilitiesTracker.size()
+ << LL_ENDL;
#ifdef DEBUG_CAPS_GRANTS
- LL_WARNS("AppInit", "Capabilities")
- << "Initial Base capabilities: " << LL_ENDL;
+ LL_WARNS("AppInit", "Capabilities")
+ << "Initial Base capabilities: " << LL_ENDL;
- log_capabilities(regionp->getRegionImpl()->mCapabilities);
+ log_capabilities(mCapabilities);
- LL_WARNS("AppInit", "Capabilities")
- << "Latest base capabilities: " << LL_ENDL;
+ LL_WARNS("AppInit", "Capabilities")
+ << "Latest base capabilities: " << LL_ENDL;
- log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker);
+ log_capabilities(mSecondCapabilitiesTracker);
#endif
- if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() )
- {
- // *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;
- }
- }
- else
- {
- LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL;
- }
- regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear();
- }
+ if (mSecondCapabilitiesTracker.size() > mCapabilities.size())
+ {
+ // *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.
+ mCapabilities.clear();
+ mCapabilities = mSecondCapabilitiesTracker;
+ }
+ }
+ else
+ {
+ LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL;
+ }
+ mSecondCapabilitiesTracker.clear();
+ }
+ while (false);
-private:
- U64 mRegionHandle;
-};
+}
+
+void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 regionHandle)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLViewerRegion *regionp = NULL;
+ S32 attemptNumber = 0;
+ // This loop is used for retrying a capabilities request.
+ do
+ {
+ ++attemptNumber;
+
+ if (attemptNumber > MAX_CAP_REQUEST_ATTEMPTS)
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "Retries count exceeded attempting to get Simulator feature from "
+ << url << LL_ENDL;
+ break;
+ }
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ regionp = NULL;
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "HttpStatus error retrying" << LL_ENDL;
+ continue;
+ }
+
+ // remove the http_result from the llsd
+ result.erase("http_result");
+
+ regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle);
+ if (!regionp) //region was removed
+ {
+ LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL;
+ break; // this error condition is not recoverable.
+ }
+
+ regionp->setSimulatorFeatures(result);
+
+ break;
+ }
+ while (true);
+
+}
LLViewerRegion::LLViewerRegion(const U64 &handle,
const LLHost &host,
@@ -515,8 +617,9 @@ LLViewerRegion::~LLViewerRegion()
delete mParcelOverlay;
delete mImpl->mLandp;
delete mImpl->mEventPoll;
+#if 0
LLHTTPSender::clearSender(mImpl->mHost);
-
+#endif
std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer());
saveObjectCache();
@@ -525,11 +628,6 @@ LLViewerRegion::~LLViewerRegion()
mImpl = NULL;
}
-LLEventPump& LLViewerRegion::getCapAPI() const
-{
- return mImpl->mCapabilityListener.getCapAPI();
-}
-
/*virtual*/
const LLHost& LLViewerRegion::getHost() const
{
@@ -2730,7 +2828,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("FetchInventory2");
capabilityNames.append("FetchInventoryDescendents2");
capabilityNames.append("IncrementCOFVersion");
- AISCommand::getCapabilityNames(capabilityNames);
+ AISAPI::getCapNames(capabilityNames);
capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetExperiences");
@@ -2810,15 +2908,14 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
if (getCapability("Seed") == url)
{
setCapabilityDebug("Seed", url);
- LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " <<
+ LL_WARNS("CrossingCaps") << "Received duplicate seed capability, posting to seed " <<
url << LL_ENDL;
//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();
- mImpl->buildCapabilityNames( capabilityNames );
- LLHTTPClient::post( url, capabilityNames, BaseCapabilitiesCompleteTracker::build(getHandle() ),
- LLSD(), CAP_REQUEST_TIMEOUT );
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro",
+ boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, mImpl, getHandle()));
return;
}
@@ -2828,15 +2925,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
mImpl->mCapabilities.clear();
setCapability("Seed", url);
- LLSD capabilityNames = LLSD::emptyArray();
- mImpl->buildCapabilityNames(capabilityNames);
-
- LL_INFOS() << "posting to seed " << url << LL_ENDL;
+ std::string coroname =
+ LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro",
+ boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, mImpl, getHandle()));
- S32 id = ++mImpl->mHttpResponderID;
- LLHTTPClient::post(url, capabilityNames,
- BaseCapabilitiesComplete::build(getHandle(), id),
- LLSD(), CAP_REQUEST_TIMEOUT);
+ LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << LL_ENDL;
}
S32 LLViewerRegion::getNumSeedCapRetries()
@@ -2844,94 +2937,6 @@ S32 LLViewerRegion::getNumSeedCapRetries()
return mImpl->mSeedCapAttempts;
}
-void LLViewerRegion::failedSeedCapability()
-{
- // Should we retry asking for caps?
- mImpl->mSeedCapAttempts++;
- std::string url = getCapability("Seed");
- if ( url.empty() )
- {
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL;
- return;
- }
- // After a few attempts, continue login. We will keep trying once in-world:
- if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin &&
- STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() )
- {
- LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
- }
-
- if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts)
- {
- LLSD capabilityNames = LLSD::emptyArray();
- mImpl->buildCapabilityNames(capabilityNames);
-
- LL_INFOS() << "posting to seed " << url << " (retry "
- << mImpl->mSeedCapAttempts << ")" << LL_ENDL;
-
- S32 id = ++mImpl->mHttpResponderID;
- LLHTTPClient::post(url, capabilityNames,
- BaseCapabilitiesComplete::build(getHandle(), id),
- LLSD(), CAP_REQUEST_TIMEOUT);
- }
- else
- {
- // *TODO: Give a user pop-up about this error?
- LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL;
- }
-}
-
-class SimulatorFeaturesReceived : public LLHTTPClient::Responder
-{
- LOG_CLASS(SimulatorFeaturesReceived);
-public:
- 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)
- { }
-
- /* virtual */ void httpFailure()
- {
- LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL;
- retry();
- }
-
- /* virtual */ void httpSuccess()
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
- if(!regionp) //region is removed or responder is not created.
- {
- LL_WARNS("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);
- }
-
- void retry()
- {
- if (mAttempt < mMaxAttempts)
- {
- mAttempt++;
- LL_WARNS("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL;
- LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);
- }
- }
-
- std::string mRetryURL;
- U64 mRegionHandle;
- S32 mAttempt;
- S32 mMaxAttempts;
-};
-
-
void LLViewerRegion::setCapability(const std::string& name, const std::string& url)
{
if(name == "EventQueueGet")
@@ -2942,12 +2947,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u
}
else if(name == "UntrustedSimulatorMessage")
{
- LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url));
+ mImpl->mHost.setUntrustedSimulatorCap(url);
}
else if (name == "SimulatorFeatures")
{
// kick off a request for simulator features
- LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT);
+ std::string coroname =
+ LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro",
+ boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle()));
+
+ LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL;
}
else
{
@@ -2970,9 +2979,20 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri
mHttpUrl = url ;
}
}
+}
+std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const
+{
+ CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name);
+ if (iter == mImpl->mSecondCapabilitiesTracker.end())
+ {
+ return "";
+ }
+
+ return iter->second;
}
+
bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
{
return name == "EventQueueGet" || name == "UntrustedSimulatorMessage";
@@ -3025,7 +3045,7 @@ void LLViewerRegion::setCapabilitiesReceived(bool received)
{
mCapabilitiesReceivedSignal(getRegionID());
- LLFloaterPermsDefault::sendInitialPerms();
+ //LLFloaterPermsDefault::sendInitialPerms();
// This is a single-shot signal. Forget callbacks to save resources.
mCapabilitiesReceivedSignal.disconnect_all_slots();
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index c14fa5aee8..8c4966369c 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -40,7 +40,6 @@
#include "llweb.h"
#include "llcapabilityprovider.h"
#include "m4math.h" // LLMatrix4
-#include "llhttpclient.h"
#include "llframetimer.h"
// Surface id's
@@ -62,7 +61,6 @@ class LLVOCache;
class LLVOCacheEntry;
class LLSpatialPartition;
class LLEventPump;
-class LLCapabilityListener;
class LLDataPacker;
class LLDataPackerBinaryBuffer;
class LLHost;
@@ -253,13 +251,14 @@ public:
// Get/set named capability URLs for this region.
void setSeedCapability(const std::string& url);
- void failedSeedCapability();
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;
+ std::string getCapabilityDebug(const std::string& name) const;
+
// has region received its final (not seed) capability list?
bool capabilitiesReceived() const;
@@ -269,10 +268,6 @@ public:
static bool isSpecialCapabilityName(const std::string &name);
void logActiveCapabilities() const;
- /// Get LLEventPump on which we listen for capability requests
- /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities)
- LLEventPump& getCapAPI() const;
-
/// implements LLCapabilityProvider
/*virtual*/ const LLHost& getHost() const;
const U64 &getHandle() const { return mHandle; }
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index f60829e9e8..2c3067cd3a 100755
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -60,6 +60,7 @@
#include "llfeaturemanager.h"
#include "llviewernetwork.h"
#include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
+#include "llcorehttputil.h"
namespace LLStatViewer
{
@@ -410,24 +411,6 @@ void update_statistics()
}
}
-class ViewerStatsResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(ViewerStatsResponder);
-public:
- ViewerStatsResponder() { }
-
-private:
- /* virtual */ void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
-
- /* virtual */ void httpSuccess()
- {
- LL_INFOS() << "OK" << LL_ENDL;
- }
-};
-
/*
* The sim-side LLSD is in newsim/llagentinfo.cpp:forwardViewerStats.
*
@@ -618,8 +601,8 @@ void send_stats()
body["MinimalSkin"] = false;
LLViewerStats::getInstance()->addToMessage(body);
- LLHTTPClient::post(url, body, new ViewerStatsResponder());
-
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
+ "Statistics posted to sim", "Failed to post statistics to sim");
LLViewerStats::instance().getRecording().resume();
}
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index aed7e94945..e496cb9f78 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -266,7 +266,7 @@ class LLViewerFetchedTexture : public LLViewerTexture
protected:
/*virtual*/ ~LLViewerFetchedTexture();
public:
- LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
+ LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps);
LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
@@ -498,7 +498,7 @@ protected:
S32 mCachedRawDiscardLevel;
BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.
- LLHost mTargetHost; // if LLHost::invalid, just request from agent's simulator
+ LLHost mTargetHost; // if invalid, just request from agent's simulator
// Timers
LLFrameTimer mLastPacketTimer; // Time since last packet.
@@ -528,7 +528,7 @@ protected:
/*virtual*/ ~LLViewerLODTexture(){}
public:
- LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
+ LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE);
LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE);
/*virtual*/ S8 getType() const;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 926c40307b..2fbd9f0acb 100755
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -236,7 +236,7 @@ void LLViewerTextureList::shutdown()
if (!image->hasGLTexture() ||
!image->getUseDiscard() ||
image->needsAux() ||
- image->getTargetHost() != LLHost::invalid ||
+ !image->getTargetHost().isInvalid() ||
!image->getUrl().empty()
)
{
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f753448770..db949437a7 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -8095,7 +8095,7 @@ LLHost LLVOAvatar::getObjectHost() const
}
else
{
- return LLHost::invalid;
+ return LLHost();
}
}
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index c1ca0aed69..e7dee14387 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -65,6 +65,7 @@
#include "llsdutil.h"
#include "llstartup.h"
#include "llsdserialize.h"
+#include "llcorehttputil.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@@ -106,6 +107,9 @@ void selfClearPhases()
using namespace LLAvatarAppearanceDefines;
+
+LLSD summarize_by_buckets(std::vector<LLSD> in_records, std::vector<std::string> by_fields, std::string val_field);
+
/*********************************************************************************
** **
** Begin private LLVOAvatarSelf Support classes
@@ -128,25 +132,6 @@ struct LocalTextureData
LLTextureEntry *mTexEntry;
};
-// TODO - this class doesn't really do anything, could just use a base
-// class responder if nothing else gets added.
-class LLHoverHeightResponder: public LLHTTPClient::Responder
-{
-public:
- LLHoverHeightResponder(): LLHTTPClient::Responder() {}
-
-private:
- void httpFailure()
- {
- LL_WARNS() << dumpResponse() << LL_ENDL;
- }
-
- void httpSuccess()
- {
- LL_INFOS() << dumpResponse() << LL_ENDL;
- }
-};
-
//-----------------------------------------------------------------------------
// Callback data
//-----------------------------------------------------------------------------
@@ -181,7 +166,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
mRegionCrossingCount(0),
// Value outside legal range, so will always be a mismatch the
// first time through.
- mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f))
+ mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)),
+ mInitialMetric(true),
+ mMetricSequence(0)
{
mMotionController.mIsSelf = TRUE;
@@ -2164,43 +2151,76 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const
return text;
}
-class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder
-{
- LOG_CLASS(ViewerAppearanceChangeMetricsResponder);
-public:
- ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,
- volatile const S32 & live_sequence,
- volatile bool & reporting_started):
- mExpectedSequence(expected_sequence),
- mLiveSequence(live_sequence),
- mReportingStarted(reporting_started)
- {
- }
-
-private:
- /* virtual */ void httpSuccess()
- {
- LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
-
- 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;
- volatile bool & mReportingStarted;
-};
+void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("appearanceChangeMetrics", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+ S32 currentSequence = mMetricSequence;
+ if (S32_MAX == ++mMetricSequence)
+ mMetricSequence = 0;
+
+ LLSD msg;
+ msg["message"] = "ViewerAppearanceChangeMetrics";
+ msg["session_id"] = gAgentSessionID;
+ msg["agent_id"] = gAgentID;
+ msg["sequence"] = currentSequence;
+ msg["initial"] = mInitialMetric;
+ msg["break"] = false;
+ msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32();
+
+ // Status of our own rezzing.
+ msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
+
+ // Status of all nearby avs including ourself.
+ msg["nearby"] = LLSD::emptyArray();
+ std::vector<S32> rez_counts;
+ LLVOAvatar::getNearbyRezzedStats(rez_counts);
+ for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat)
+ {
+ std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat);
+ msg["nearby"][rez_status_name] = rez_counts[rez_stat];
+ }
+
+ // std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake");
+ std::vector<std::string> by_fields;
+ by_fields.push_back("timer_name");
+ by_fields.push_back("completed");
+ by_fields.push_back("grid_x");
+ by_fields.push_back("grid_y");
+ by_fields.push_back("is_using_server_bakes");
+ by_fields.push_back("is_self");
+ by_fields.push_back("central_bake_version");
+ LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed"));
+ msg["timers"] = summary;
+
+ mPendingTimerRecords.clear();
+
+ LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL;
+
+ gPendingMetricsUploads++;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, msg);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ gPendingMetricsUploads--;
+
+ if (!status)
+ {
+ LL_WARNS("Avatar") << "Unable to upload statistics" << LL_ENDL;
+ return;
+ }
+ else
+ {
+ LL_INFOS("Avatar") << "Statistics upload OK" << LL_ENDL;
+ mInitialMetric = false;
+ }
+}
bool LLVOAvatarSelf::updateAvatarRezMetrics(bool force_send)
{
@@ -2278,51 +2298,7 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,
void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
{
- static volatile bool reporting_started(false);
- static volatile S32 report_sequence(0);
-
- LLSD msg;
- msg["message"] = "ViewerAppearanceChangeMetrics";
- msg["session_id"] = gAgentSessionID;
- msg["agent_id"] = gAgentID;
- msg["sequence"] = report_sequence;
- msg["initial"] = !reporting_started;
- msg["break"] = false;
- msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32();
-
- // Status of our own rezzing.
- msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
-
- // Status of all nearby avs including ourself.
- msg["nearby"] = LLSD::emptyArray();
- std::vector<S32> rez_counts;
- LLVOAvatar::getNearbyRezzedStats(rez_counts);
- for (S32 rez_stat=0; rez_stat < rez_counts.size(); ++rez_stat)
- {
- std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat);
- msg["nearby"][rez_status_name] = rez_counts[rez_stat];
- }
-
- // std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake");
- std::vector<std::string> by_fields;
- by_fields.push_back("timer_name");
- by_fields.push_back("completed");
- by_fields.push_back("grid_x");
- by_fields.push_back("grid_y");
- by_fields.push_back("is_using_server_bakes");
- by_fields.push_back("is_self");
- by_fields.push_back("central_bake_version");
- LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed"));
- msg["timers"] = summary;
-
- mPendingTimerRecords.clear();
-
- // Update sequence number
- if (S32_MAX == ++report_sequence)
- report_sequence = 0;
-
- LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL;
- std::string caps_url;
+ std::string caps_url;
if (getRegion())
{
// runway - change here to activate.
@@ -2330,13 +2306,9 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
}
if (!caps_url.empty())
{
- gPendingMetricsUploads++;
- LLCurlRequest::headers_t headers;
- LLHTTPClient::post(caps_url,
- msg,
- new ViewerAppearanceChangeMetricsResponder(report_sequence,
- report_sequence,
- reporting_started));
+
+ LLCoros::instance().launch("LLVOAvatarSelf::appearanceChangeMetricsCoro",
+ boost::bind(&LLVOAvatarSelf::appearanceChangeMetricsCoro, this, caps_url));
mTimeSinceLastRezMessage.reset();
}
}
@@ -2759,8 +2731,12 @@ void LLVOAvatarSelf::sendHoverHeight() const
update["hover_height"] = hover_offset[2];
LL_DEBUGS("Avatar") << avString() << "sending hover height value " << hover_offset[2] << LL_ENDL;
- LLHTTPClient::post(url, update, new LLHoverHeightResponder);
+ // *TODO: - this class doesn't really do anything, could just use a base
+ // class responder if nothing else gets added.
+ // (comment from removed Responder)
+ LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, update,
+ "Hover hight sent to sim", "Hover hight not sent to sim");
mLastHoverOffsetSent = hover_offset;
}
}
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 257a760eeb..cdd82a8a44 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -31,6 +31,8 @@
#include "llviewertexture.h"
#include "llvoavatar.h"
#include <map>
+#include "lleventcoro.h"
+#include "llcoros.h"
struct LocalTextureData;
class LLInventoryCallback;
@@ -394,6 +396,9 @@ private:
F32 mDebugBakedTextureTimes[LLAvatarAppearanceDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture
void debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+ void appearanceChangeMetricsCoro(std::string url);
+ bool mInitialMetric;
+ S32 mMetricSequence;
/** Diagnostics
** **
*******************************************************************************/
diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp
index 426ca332e4..3abb716593 100755
--- a/indra/newview/llvoicechannel.cpp
+++ b/indra/newview/llvoicechannel.cpp
@@ -28,7 +28,6 @@
#include "llagent.h"
#include "llfloaterreg.h"
-#include "llhttpclient.h"
#include "llimview.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
@@ -37,7 +36,7 @@
#include "llviewercontrol.h"
#include "llviewerregion.h"
#include "llvoicechannel.h"
-
+#include "llcorehttputil.h"
LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
@@ -52,71 +51,6 @@ BOOL LLVoiceChannel::sSuspended = FALSE;
//
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 httpFailure();
- virtual void httpSuccess();
-
-private:
- LLUUID mSessionID;
-};
-
-
-void LLVoiceCallCapResponder::httpFailure()
-{
- LL_WARNS("Voice") << dumpResponse() << LL_ENDL;
- LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
- if ( channelp )
- {
- if ( HTTP_FORBIDDEN == getStatus() )
- {
- //403 == no ability
- LLNotificationsUtil::add(
- "VoiceNotAllowed",
- channelp->getNotifyArgs());
- }
- else
- {
- LLNotificationsUtil::add(
- "VoiceCallGenericError",
- channelp->getNotifyArgs());
- }
- channelp->deactivate();
- }
-}
-
-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)
- {
- LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "
- << iter->first << LL_ENDL;
- }
-
- channelp->setChannelInfo(
- content["voice_credentials"]["channel_uri"].asString(),
- content["voice_credentials"]["channel_credentials"].asString());
- }
-}
-
//
// LLVoiceChannel
//
@@ -545,12 +479,9 @@ void LLVoiceChannelGroup::getChannelInfo()
if (region)
{
std::string url = region->getCapability("ChatSessionRequest");
- LLSD data;
- data["method"] = "call";
- data["session-id"] = mSessionID;
- LLHTTPClient::post(url,
- data,
- new LLVoiceCallCapResponder(mSessionID));
+
+ LLCoros::instance().launch("LLVoiceChannelGroup::voiceCallCapCoro",
+ boost::bind(&LLVoiceChannelGroup::voiceCallCapCoro, this, url));
}
}
@@ -673,6 +604,66 @@ void LLVoiceChannelGroup::setState(EState state)
}
}
+void LLVoiceChannelGroup::voiceCallCapCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceCallCapCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD postData;
+ postData["method"] = "call";
+ postData["session-id"] = mSessionID;
+
+ LL_INFOS("Voice", "voiceCallCapCoro") << "Generic POST for " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
+ if (!channelp)
+ {
+ LL_WARNS("Voice") << "Unable to retrieve channel with Id = " << mSessionID << LL_ENDL;
+ return;
+ }
+
+ if (!status)
+ {
+ if (status == LLCore::HttpStatus(HTTP_FORBIDDEN))
+ {
+ //403 == no ability
+ LLNotificationsUtil::add(
+ "VoiceNotAllowed",
+ channelp->getNotifyArgs());
+ }
+ else
+ {
+ LLNotificationsUtil::add(
+ "VoiceCallGenericError",
+ channelp->getNotifyArgs());
+ }
+ channelp->deactivate();
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+
+ LLSD::map_const_iterator iter;
+ for (iter = result.beginMap(); iter != result.endMap(); ++iter)
+ {
+ LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "
+ << iter->first << LL_ENDL;
+ }
+
+ channelp->setChannelInfo(
+ result["voice_credentials"]["channel_uri"].asString(),
+ result["voice_credentials"]["channel_credentials"].asString());
+
+}
+
+
//
// LLVoiceChannelProximal
//
diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h
index fed44974fd..ef15b2c79e 100755
--- a/indra/newview/llvoicechannel.h
+++ b/indra/newview/llvoicechannel.h
@@ -29,6 +29,8 @@
#include "llhandle.h"
#include "llvoiceclient.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
class LLPanel;
@@ -157,6 +159,8 @@ protected:
virtual void setState(EState state);
private:
+ void voiceCallCapCoro(std::string url);
+
U32 mRetries;
BOOL mIsRetrying;
};
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index a6a7a35b03..d14fac5fb8 100755
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -64,6 +64,8 @@
#include "llviewernetwork.h"
#include "llnotificationsutil.h"
+#include "llcorehttputil.h"
+
#include "stringize.h"
// for base64 decoding
@@ -122,66 +124,6 @@ static int scale_speaker_volume(float volume)
}
-class LLVivoxVoiceAccountProvisionResponder :
- public LLHTTPClient::Responder
-{
- LOG_CLASS(LLVivoxVoiceAccountProvisionResponder);
-public:
- LLVivoxVoiceAccountProvisionResponder(int retries)
- {
- mRetries = retries;
- }
-
-private:
- /* virtual */ void httpFailure()
- {
- LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, "
- << ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" )
- << " " << dumpResponse() << LL_ENDL;
-
- if ( mRetries > 0 )
- {
- LLVivoxVoiceClient::getInstance()->requestVoiceAccountProvision(mRetries - 1);
- }
- else
- {
- LLVivoxVoiceClient::getInstance()->giveUp();
- }
- }
-
- /* virtual */ void httpSuccess()
- {
- std::string voice_sip_uri_hostname;
- std::string voice_account_server_uri;
-
- 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();
-
- // this key is actually misnamed -- it will be an entire URI, not just a hostname.
- if(content.has("voice_account_server_name"))
- voice_account_server_uri = content["voice_account_server_name"].asString();
-
- LLVivoxVoiceClient::getInstance()->login(
- content["username"].asString(),
- content["password"].asString(),
- voice_sip_uri_hostname,
- voice_account_server_uri);
- }
-
-private:
- int mRetries;
-};
-
-
-
///////////////////////////////////////////////////////////////////////////////////////////////
class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver
@@ -194,59 +136,6 @@ static LLVivoxVoiceClientMuteListObserver mutelist_listener;
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 httpFailure();
- /* virtual */ void httpSuccess();
-
- LLVivoxVoiceClient::state mRequestingState; // state
-};
-
-void LLVivoxVoiceClientCapResponder::httpFailure()
-{
- LL_WARNS("Voice") << dumpResponse() << LL_ENDL;
- LLVivoxVoiceClient::getInstance()->sessionTerminate();
-}
-
-void LLVivoxVoiceClientCapResponder::httpSuccess()
-{
- LLSD::map_const_iterator iter;
-
- 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"];
- if ( voice_credentials.has("channel_uri") )
- {
- uri = voice_credentials["channel_uri"].asString();
- }
- if ( voice_credentials.has("channel_credentials") )
- {
- credentials =
- voice_credentials["channel_credentials"].asString();
- }
- }
-
- // set the spatial channel. If no voice credentials or uri are
- // available, then we simply drop out of voice spatially.
- if(LLVivoxVoiceClient::getInstance()->parcelVoiceInfoReceived(mRequestingState))
- {
- LLVivoxVoiceClient::getInstance()->setSpatialChannel(uri, credentials);
- }
-}
-
static LLProcessPtr sGatewayPtr;
static bool isGatewayRunning()
@@ -556,16 +445,51 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries)
if ( !url.empty() )
{
- LLHTTPClient::post(
- url,
- LLSD(),
- new LLVivoxVoiceAccountProvisionResponder(retries));
-
+ LLCoros::instance().launch("LLVivoxVoiceClient::voiceAccountProvisionCoro",
+ boost::bind(&LLVivoxVoiceClient::voiceAccountProvisionCoro, this, url, retries));
setState(stateConnectorStart);
}
}
}
+void LLVivoxVoiceClient::voiceAccountProvisionCoro(std::string url, S32 retries)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
+
+ httpOpts->setRetries(retries);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL;
+ giveUp();
+ return;
+ }
+
+ std::string voice_sip_uri_hostname;
+ std::string voice_account_server_uri;
+
+ //LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL;
+
+ if (result.has("voice_sip_uri_hostname"))
+ voice_sip_uri_hostname = result["voice_sip_uri_hostname"].asString();
+
+ // this key is actually misnamed -- it will be an entire URI, not just a hostname.
+ if (result.has("voice_account_server_name"))
+ voice_account_server_uri = result["voice_account_server_name"].asString();
+
+ login(result["username"].asString(), result["password"].asString(),
+ voice_sip_uri_hostname, voice_account_server_uri);
+}
+
void LLVivoxVoiceClient::login(
const std::string& account_name,
const std::string& password,
@@ -4003,14 +3927,60 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo()
LLSD data;
LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
- LLHTTPClient::post(
- url,
- data,
- new LLVivoxVoiceClientCapResponder(getState()));
+ LLCoros::instance().launch("LLVivoxVoiceClient::parcelVoiceInfoRequestCoro",
+ boost::bind(&LLVivoxVoiceClient::parcelVoiceInfoRequestCoro, this, url));
return true;
}
}
+void LLVivoxVoiceClient::parcelVoiceInfoRequestCoro(std::string url)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("parcelVoiceInfoRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ state requestingState = getState();
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD());
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (!status)
+ {
+ LL_WARNS("Voice") << "No voice on parcel" << LL_ENDL;
+ sessionTerminate();
+ return;
+ }
+
+ std::string uri;
+ std::string credentials;
+
+ if (result.has("voice_credentials"))
+ {
+ LLSD voice_credentials = result["voice_credentials"];
+ if (voice_credentials.has("channel_uri"))
+ {
+ uri = voice_credentials["channel_uri"].asString();
+ }
+ if (voice_credentials.has("channel_credentials"))
+ {
+ credentials =
+ voice_credentials["channel_credentials"].asString();
+ }
+ }
+
+ LL_INFOS("Voice") << "Voice URI is " << uri << LL_ENDL;
+
+ // set the spatial channel. If no voice credentials or uri are
+ // available, then we simply drop out of voice spatially.
+ if (parcelVoiceInfoReceived(requestingState))
+ {
+ setSpatialChannel(uri, credentials);
+ }
+
+}
+
void LLVivoxVoiceClient::switchChannel(
std::string uri,
bool spatial,
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index a4ec9f2a69..b12ed80e41 100755
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -37,6 +37,9 @@ class LLVivoxProtocolParser;
#include "llframetimer.h"
#include "llviewerregion.h"
#include "llcallingcard.h" // for LLFriendObserver
+#include "lleventcoro.h"
+#include "llcoros.h"
+#include <queue>
#ifdef LL_USESYSTEMLIBS
# include "expat.h"
@@ -46,7 +49,6 @@ class LLVivoxProtocolParser;
#include "llvoiceclient.h"
class LLAvatarName;
-class LLVivoxVoiceAccountProvisionResponder;
class LLVivoxVoiceClientMuteListObserver;
@@ -251,7 +253,6 @@ protected:
//////////////////////
// Vivox Specific definitions
- friend class LLVivoxVoiceAccountProvisionResponder;
friend class LLVivoxVoiceClientMuteListObserver;
friend class LLVivoxVoiceClientFriendsObserver;
@@ -635,6 +636,10 @@ protected:
void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString);
private:
+
+ void voiceAccountProvisionCoro(std::string url, S32 retries);
+ void parcelVoiceInfoRequestCoro(std::string url);
+
LLVoiceVersionInfo mVoiceVersion;
/// Clean up objects created during a voice session.
diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp
index ddb7f7bfce..06ce497510 100755
--- a/indra/newview/llwebprofile.cpp
+++ b/indra/newview/llwebprofile.cpp
@@ -30,14 +30,17 @@
// libs
#include "llbufferstream.h"
-#include "llhttpclient.h"
#include "llimagepng.h"
#include "llplugincookiestore.h"
+#include "llsdserialize.h"
+
// newview
#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions
#include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals
+#include "llcorehttputil.h"
+
// third-party
#include "reader.h" // JSON
@@ -55,139 +58,6 @@
*/
///////////////////////////////////////////////////////////////////////////////
-// LLWebProfileResponders::ConfigResponder
-
-class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLWebProfileResponders::ConfigResponder);
-
-public:
- ConfigResponder(LLPointer<LLImageFormatted> imagep)
- : mImagep(imagep)
- {
- }
-
- // *TODO: Check for 'application/json' content type, and parse json at the base class.
- /*virtual*/ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
-
- if (getStatus() != HTTP_OK)
- {
- LL_WARNS() << "Failed to get upload config " << dumpResponse() << LL_ENDL;
- LLWebProfile::reportImageUploadStatus(false);
- return;
- }
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(body, root))
- {
- LL_WARNS() << "Failed to parse upload config: " << reader.getFormatedErrorMessages() << LL_ENDL;
- LLWebProfile::reportImageUploadStatus(false);
- return;
- }
-
- // *TODO: 404 = not supported by the grid
- // *TODO: increase timeout or handle 499 Expired
-
- // Convert config to LLSD.
- const Json::Value data = root["data"];
- const std::string upload_url = root["url"].asString();
- LLSD config;
- config["acl"] = data["acl"].asString();
- config["AWSAccessKeyId"] = data["AWSAccessKeyId"].asString();
- config["Content-Type"] = data["Content-Type"].asString();
- config["key"] = data["key"].asString();
- config["policy"] = data["policy"].asString();
- config["success_action_redirect"] = data["success_action_redirect"].asString();
- config["signature"] = data["signature"].asString();
- config["add_loc"] = data.get("add_loc", "0").asString();
- config["caption"] = data.get("caption", "").asString();
-
- // Do the actual image upload using the configuration.
- LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL;
- LLWebProfile::post(mImagep, config, upload_url);
- }
-
-private:
- LLPointer<LLImageFormatted> mImagep;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// LLWebProfilePostImageRedirectResponder
-class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLWebProfileResponders::PostImageRedirectResponder);
-
-public:
- /*virtual*/ void completedRaw(
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- if (getStatus() != HTTP_OK)
- {
- LL_WARNS() << "Failed to upload image " << dumpResponse() << LL_ENDL;
- LLWebProfile::reportImageUploadStatus(false);
- return;
- }
-
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string body = strstrm.str();
- LL_INFOS() << "Image uploaded." << LL_ENDL;
- LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL;
- LLWebProfile::reportImageUploadStatus(true);
- }
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// LLWebProfileResponders::PostImageResponder
-class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responder
-{
- LOG_CLASS(LLWebProfileResponders::PostImageResponder);
-
-public:
- /*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 (getStatus() == HTTP_SEE_OTHER)
- {
- LLSD headers = LLViewerMedia::getHeaders();
- headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie();
- const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION);
- if (redir_url.empty())
- {
- LL_WARNS() << "Received empty redirection URL " << dumpResponse() << LL_ENDL;
- LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- LLWebProfile::reportImageUploadStatus(false);
- }
- else
- {
- LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL;
- LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers);
- }
- }
- else
- {
- LL_WARNS() << "Unexpected POST response " << dumpResponse() << LL_ENDL;
- LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL;
- LLWebProfile::reportImageUploadStatus(false);
- }
- }
-};
-
-///////////////////////////////////////////////////////////////////////////////
// LLWebProfile
std::string LLWebProfile::sAuthCookie;
@@ -196,15 +66,9 @@ LLWebProfile::status_callback_t LLWebProfile::mStatusCallback;
// static
void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::string& caption, bool add_location)
{
- // Get upload configuration data.
- std::string config_url(getProfileURL(LLStringUtil::null) + "snapshots/s3_upload_config");
- config_url += "?caption=" + LLURI::escape(caption);
- config_url += "&add_loc=" + std::string(add_location ? "1" : "0");
-
- LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL;
- LLSD headers = LLViewerMedia::getHeaders();
- headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();
- LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers);
+ LLCoros::instance().launch("LLWebProfile::uploadImageCoro",
+ boost::bind(&LLWebProfile::uploadImageCoro, image, caption, add_location));
+
}
// static
@@ -214,74 +78,178 @@ void LLWebProfile::setAuthCookie(const std::string& cookie)
sAuthCookie = cookie;
}
-// static
-void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url)
+
+/*static*/
+LLCore::HttpHeaders::ptr_t LLWebProfile::buildDefaultHeaders()
{
- if (dynamic_cast<LLImagePNG*>(image.get()) == 0)
- {
- LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL;
- llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0);
- return;
- }
+ LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders);
+ LLSD headers = LLViewerMedia::getHeaders();
- const std::string boundary = "----------------------------0123abcdefab";
+ for (LLSD::map_iterator it = headers.beginMap(); it != headers.endMap(); ++it)
+ {
+ httpHeaders->append((*it).first, (*it).second.asStringRef());
+ }
- LLSD headers = LLViewerMedia::getHeaders();
- headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();
- headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary;
+ return httpHeaders;
+}
- std::ostringstream body;
- // *NOTE: The order seems to matter.
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"key\"\r\n\r\n"
- << config["key"].asString() << "\r\n";
+/*static*/
+void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::string caption, bool addLocation)
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders;
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n"
- << config["AWSAccessKeyId"].asString() << "\r\n";
+ if (dynamic_cast<LLImagePNG*>(image.get()) == 0)
+ {
+ LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL;
+ llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0);
+ return;
+ }
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"acl\"\r\n\r\n"
- << config["acl"].asString() << "\r\n";
+ httpOpts->setWantHeaders(true);
+ httpOpts->setFollowRedirects(false);
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n"
- << config["Content-Type"].asString() << "\r\n";
+ // Get upload configuration data.
+ std::string configUrl(getProfileURL(std::string()) + "snapshots/s3_upload_config");
+ configUrl += "?caption=" + LLURI::escape(caption);
+ configUrl += "&add_loc=" + std::string(addLocation ? "1" : "0");
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"policy\"\r\n\r\n"
- << config["policy"].asString() << "\r\n";
+ LL_DEBUGS("Snapshots") << "Requesting " << configUrl << LL_ENDL;
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"signature\"\r\n\r\n"
- << config["signature"].asString() << "\r\n";
+ httpHeaders = buildDefaultHeaders();
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie());
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n"
- << config["success_action_redirect"].asString() << "\r\n";
+ LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, configUrl, httpOpts, httpHeaders);
- body << "--" << boundary << "\r\n"
- << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n"
- << "Content-Type: image/png\r\n\r\n";
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- // Insert the image data.
- // *FIX: Treating this as a string will probably screw it up ...
- U8* image_data = image->getData();
- for (S32 i = 0; i < image->getDataSize(); ++i)
- {
- body << image_data[i];
- }
+ if (!status)
+ {
+ LL_WARNS("Snapshots") << "Failed to get image upload config" << LL_ENDL;
+ LLWebProfile::reportImageUploadStatus(false);
+ return;
+ }
+
+ // Ready to build our image post body.
+
+ const LLSD &data = result["data"];
+ const std::string &uploadUrl = result["url"].asStringRef();
+ const std::string boundary = "----------------------------0123abcdefab";
+
+ // a new set of headers.
+ httpHeaders = LLWebProfile::buildDefaultHeaders();
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie());
+ httpHeaders->remove(HTTP_OUT_HEADER_CONTENT_TYPE);
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
+
+ LLCore::BufferArray::ptr_t body = LLWebProfile::buildPostData(data, image, boundary);
+
+ result = httpAdapter->postAndSuspend(httpRequest, uploadUrl, body, httpOpts, httpHeaders);
+
+ body.reset();
+ httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
- body << "\r\n--" << boundary << "--\r\n";
+ if (!status && (status != LLCore::HttpStatus(HTTP_SEE_OTHER)))
+ {
+ LL_WARNS("Snapshots") << "Failed to upload image data." << LL_ENDL;
+ LLWebProfile::reportImageUploadStatus(false);
+ return;
+ }
- // postRaw() takes ownership of the buffer and releases it later.
- size_t size = body.str().size();
- U8 *data = new U8[size];
- memcpy(data, body.str().data(), size);
+ LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS];
- // Send request, successful upload will trigger posting metadata.
- LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers);
+ httpHeaders = LLWebProfile::buildDefaultHeaders();
+ httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie());
+
+ const std::string& redirUrl = resultHeaders[HTTP_IN_HEADER_LOCATION].asStringRef();
+
+ if (redirUrl.empty())
+ {
+ LL_WARNS("Snapshots") << "Received empty redirection URL in post image." << LL_ENDL;
+ LLWebProfile::reportImageUploadStatus(false);
+ }
+
+ LL_DEBUGS("Snapshots") << "Got redirection URL: " << redirUrl << LL_ENDL;
+
+ result = httpAdapter->getRawAndSuspend(httpRequest, redirUrl, httpOpts, httpHeaders);
+
+ httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ if (status != LLCore::HttpStatus(HTTP_OK))
+ {
+ LL_WARNS("Snapshots") << "Failed to upload image." << LL_ENDL;
+ LLWebProfile::reportImageUploadStatus(false);
+ return;
+ }
+
+ //LLSD raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW];
+
+ LL_INFOS("Snapshots") << "Image uploaded." << LL_ENDL;
+ //LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << raw.asString() << "]" << LL_ENDL;
+ LLWebProfile::reportImageUploadStatus(true);
+
+
+}
+
+/*static*/
+LLCore::BufferArray::ptr_t LLWebProfile::buildPostData(const LLSD &data, LLPointer<LLImageFormatted> &image, const std::string &boundary)
+{
+ LLCore::BufferArray::ptr_t body(new LLCore::BufferArray);
+ LLCore::BufferArrayStream bas(body.get());
+
+ // *NOTE: The order seems to matter.
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"key\"\r\n\r\n"
+ << data["key"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n"
+ << data["AWSAccessKeyId"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"acl\"\r\n\r\n"
+ << data["acl"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n"
+ << data["Content-Type"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"policy\"\r\n\r\n"
+ << data["policy"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"signature\"\r\n\r\n"
+ << data["signature"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n"
+ << data["success_action_redirect"].asString() << "\r\n";
+
+ bas << "--" << boundary << "\r\n"
+ << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n"
+ << "Content-Type: image/png\r\n\r\n";
+
+ // Insert the image data.
+ //char *datap = (char *)(image->getData());
+ //bas.write(datap, image->getDataSize());
+ U8* image_data = image->getData();
+ for (S32 i = 0; i < image->getDataSize(); ++i)
+ {
+ bas << image_data[i];
+ }
+
+ bas << "\r\n--" << boundary << "--\r\n";
+
+ return body;
}
// static
diff --git a/indra/newview/llwebprofile.h b/indra/newview/llwebprofile.h
index 10279bffac..6227e00afe 100755
--- a/indra/newview/llwebprofile.h
+++ b/indra/newview/llwebprofile.h
@@ -28,6 +28,10 @@
#define LL_LLWEBPROFILE_H
#include "llimage.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
+#include "httpheaders.h"
+#include "bufferarray.h"
namespace LLWebProfileResponders
{
@@ -54,11 +58,11 @@ public:
static void setImageUploadResultCallback(status_callback_t cb) { mStatusCallback = cb; }
private:
- friend class LLWebProfileResponders::ConfigResponder;
- friend class LLWebProfileResponders::PostImageResponder;
- friend class LLWebProfileResponders::PostImageRedirectResponder;
+ static LLCore::HttpHeaders::ptr_t buildDefaultHeaders();
+
+ static void uploadImageCoro(LLPointer<LLImageFormatted> image, std::string caption, bool add_location);
+ static LLCore::BufferArray::ptr_t buildPostData(const LLSD &data, LLPointer<LLImageFormatted> &image, const std::string &boundary);
- static void post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url);
static void reportImageUploadStatus(bool ok);
static std::string getAuthCookie();
diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp
index 3bedfbe502..87e8c3008e 100755
--- a/indra/newview/llwlhandlers.cpp
+++ b/indra/newview/llwlhandlers.cpp
@@ -32,6 +32,7 @@
#include "llviewerregion.h"
#include "llenvmanager.h"
#include "llnotificationsutil.h"
+#include "llcorehttputil.h"
/****
* LLEnvironmentRequest
@@ -81,55 +82,62 @@ bool LLEnvironmentRequest::doRequest()
return false;
}
- LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL;
- LLHTTPClient::get(url, new LLEnvironmentRequestResponder());
- return true;
-}
-
-/****
- * LLEnvironmentRequestResponder
- ****/
-int LLEnvironmentRequestResponder::sCount = 0; // init to 0
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro",
+ boost::bind(&LLEnvironmentRequest::environmentRequestCoro, url));
-LLEnvironmentRequestResponder::LLEnvironmentRequestResponder()
-{
- mID = ++sCount;
+ LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL;
+ return true;
}
-/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess()
-{
- const LLSD& unvalidated_content = getContent();
- LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;
- if (mID != sCount)
- {
- LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL;
- return;
- }
-
- LLUUID regionId;
- if( gAgent.getRegion() )
- {
- regionId = gAgent.getRegion()->getRegionID();
- }
-
- if (unvalidated_content[0]["regionID"].asUUID() != regionId )
- {
- LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting "
- << regionId << " but got " << unvalidated_content[0]["regionID"].asUUID()
- << ") - ignoring..." << LL_ENDL;
- return;
- }
+S32 LLEnvironmentRequest::sLastRequest = 0;
- LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content);
-}
-/*virtual*/
-void LLEnvironmentRequestResponder::httpFailure()
+//static
+void LLEnvironmentRequest::environmentRequestCoro(std::string url)
{
- LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... "
- << dumpResponse() << LL_ENDL;
- LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ S32 requestId = ++LLEnvironmentRequest::sLastRequest;
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ if (requestId != LLEnvironmentRequest::sLastRequest)
+ {
+ LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL;
+ return;
+ }
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " << LL_ENDL;
+ LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD());
+ return;
+ }
+ result = result["content"];
+ LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL;
+
+ LLUUID regionId;
+ if (gAgent.getRegion())
+ {
+ regionId = gAgent.getRegion()->getRegionID();
+ }
+
+ if ((result[0]["regionID"].asUUID() != regionId) && regionId.notNull())
+ {
+ LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting "
+ << regionId << " but got " << result[0]["regionID"].asUUID()
+ << ") - ignoring..." << LL_ENDL;
+ return;
+ }
+
+ LLEnvManagerNew::getInstance()->onRegionSettingsResponse(result);
}
+
/****
* LLEnvironmentApply
****/
@@ -161,53 +169,86 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)
return false;
}
- LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL;
- LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL;
- LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder());
+ LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL;
+ LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL;
+
+ std::string coroname =
+ LLCoros::instance().launch("LLEnvironmentApply::environmentApplyCoro",
+ boost::bind(&LLEnvironmentApply::environmentApplyCoro, url, content));
return true;
}
-/****
- * LLEnvironmentApplyResponder
- ****/
-/*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 "
- << gAgent.getRegion()->getRegionID() << ", reply is from " << content["regionID"].asUUID()
- << "); ignoring..." << LL_ENDL;
- return;
- }
- else if (content["success"].asBoolean())
- {
- LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << content["regionID"].asUUID() << LL_ENDL;
- LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true);
- }
- else
- {
- 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);
- LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false);
- }
-}
-/*virtual*/
-void LLEnvironmentApplyResponder::httpFailure()
+void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content)
{
- LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! "
- << dumpResponse() << LL_ENDL;
-
- LLSD args(LLSD::emptyMap());
- std::stringstream msg;
- msg << getReason() << " (Code " << getStatus() << ")";
- args["FAIL_REASON"] = msg.str();
- LLNotificationsUtil::add("WLRegionApplyFail", args);
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentApply", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, url, content);
+
+ LLSD notify; // for error reporting. If there is something to report to user this will be defined.
+ /*
+ * Expecting reply from sim in form of:
+ * {
+ * regionID : uuid,
+ * messageID: uuid,
+ * success : true
+ * }
+ * or
+ * {
+ * regionID : uuid,
+ * success : false,
+ * fail_reason : string
+ * }
+ */
+
+ do // while false.
+ { // Breaks from loop in the case of an error.
+
+ LLSD httpResults = result["http_result"];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+ if (!status)
+ {
+ LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " << LL_ENDL;
+
+ std::stringstream msg;
+ msg << status.toString() << " (Code " << status.toTerseString() << ")";
+ notify = LLSD::emptyMap();
+ notify["FAIL_REASON"] = msg.str();
+ break;
+ }
+
+ if (!result.has("regionID"))
+ {
+ notify = LLSD::emptyMap();
+ notify["FAIL_REASON"] = "Missing regionID, malformed response";
+ break;
+ }
+ else if (result["regionID"].asUUID() != gAgent.getRegion()->getRegionID())
+ {
+ // note that there is no report to the user in this failure case.
+ LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently "
+ << gAgent.getRegion()->getRegionID() << ", reply is from " << result["regionID"].asUUID()
+ << "); ignoring..." << LL_ENDL;
+ break;
+ }
+ else if (!result["success"].asBoolean())
+ {
+ LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << LL_ENDL;
+ notify = LLSD::emptyMap();
+ notify["FAIL_REASON"] = result["fail_reason"].asString();
+ break;
+ }
+
+ LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << result["regionID"].asUUID() << LL_ENDL;
+ LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true);
+
+ } while (false);
+
+ if (!notify.isUndefined())
+ {
+ LLNotificationsUtil::add("WLRegionApplyFail", notify);
+ LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false);
+ }
}
diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h
index 089c799da7..eb2bbf9553 100755
--- a/indra/newview/llwlhandlers.h
+++ b/indra/newview/llwlhandlers.h
@@ -28,7 +28,7 @@
#define LL_LLWLHANDLERS_H
#include "llviewerprecompiledheaders.h"
-#include "llhttpclient.h"
+#include "llcoros.h"
class LLEnvironmentRequest
{
@@ -40,21 +40,10 @@ public:
private:
static void onRegionCapsReceived(const LLUUID& region_id);
static bool doRequest();
-};
-
-class LLEnvironmentRequestResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(LLEnvironmentRequestResponder);
-private:
- /* virtual */ void httpSuccess();
- /* virtual */ void httpFailure();
-private:
- friend class LLEnvironmentRequest;
+ static void environmentRequestCoro(std::string url);
- LLEnvironmentRequestResponder();
- static int sCount;
- int mID;
+ static S32 sLastRequest;
};
class LLEnvironmentApply
@@ -67,35 +56,8 @@ public:
private:
static clock_t sLastUpdate;
static clock_t UPDATE_WAIT_SECONDS;
-};
-class LLEnvironmentApplyResponder: public LLHTTPClient::Responder
-{
- LOG_CLASS(LLEnvironmentApplyResponder);
-private:
- /*
- * Expecting reply from sim in form of:
- * {
- * regionID : uuid,
- * messageID: uuid,
- * success : true
- * }
- * or
- * {
- * regionID : uuid,
- * success : false,
- * fail_reason : string
- * }
- */
- /* virtual */ void httpSuccess();
-
- // non-2xx errors only
- /* virtual */ void httpFailure();
-
-private:
- friend class LLEnvironmentApply;
-
- LLEnvironmentApplyResponder() {}
+ static void environmentApplyCoro(std::string url, LLSD content);
};
#endif // LL_LLWLHANDLERS_H
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index c12c2cc24c..442ed73c2d 100755
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -34,7 +34,12 @@
#include "llxmlrpctransaction.h"
#include "llxmlrpclistener.h"
-#include "llcurl.h"
+#include "httpcommon.h"
+#include "llhttpconstants.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+#include "httpheaders.h"
+#include "bufferarray.h"
#include "llviewercontrol.h"
// Have to include these last to avoid queue redefinition!
@@ -43,6 +48,13 @@
#include "llappviewer.h"
#include "lltrans.h"
+#include "boost/move/unique_ptr.hpp"
+
+namespace boost
+{
+ using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace.
+}
+
// Static instance of LLXMLRPCListener declared here so that every time we
// bring in this code, we instantiate a listener. If we put the static
// instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would
@@ -155,55 +167,158 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const
}
+class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
+{
+public:
+ Handler(LLCore::HttpRequest::ptr_t &request, LLXMLRPCTransaction::Impl *impl);
+ virtual ~Handler();
+
+ virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+ typedef boost::unique_ptr<LLXMLRPCTransaction::Handler> ptr_t;
+
+private:
+
+ LLXMLRPCTransaction::Impl *mImpl;
+ LLCore::HttpRequest::ptr_t mRequest;
+};
+
class LLXMLRPCTransaction::Impl
{
public:
typedef LLXMLRPCTransaction::EStatus EStatus;
- LLCurlEasyRequest* mCurlRequest;
+ LLCore::HttpRequest::ptr_t mHttpRequest;
+
+
+ EStatus mStatus;
+ CURLcode mCurlCode;
+ std::string mStatusMessage;
+ std::string mStatusURI;
+ LLCore::HttpResponse::TransferStats::ptr_t mTransferStats;
+ Handler::ptr_t mHandler;
+ LLCore::HttpHandle mPostH;
- EStatus mStatus;
- CURLcode mCurlCode;
- std::string mStatusMessage;
- std::string mStatusURI;
- LLCurl::TransferInfo mTransferInfo;
-
std::string mURI;
- char* mRequestText;
- int mRequestTextSize;
-
+
std::string mProxyAddress;
std::string mResponseText;
XMLRPC_REQUEST mResponse;
std::string mCertStore;
LLPointer<LLCertificate> mErrorCert;
-
+
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);
Impl(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip);
+ const std::string& method, LLXMLRPCValue params, bool useGzip);
~Impl();
-
+
bool process();
-
- void setStatus(EStatus code,
- const std::string& message = "", const std::string& uri = "");
- void setCurlStatus(CURLcode);
+
+ void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
+ void setHttpStatus(const LLCore::HttpStatus &status);
private:
void init(XMLRPC_REQUEST request, bool useGzip);
- static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
- static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param);
- static size_t curlDownloadCallback(
- char* data, size_t size, size_t nmemb, void* user_data);
};
+LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
+ LLXMLRPCTransaction::Impl *impl) :
+ mImpl(impl),
+ mRequest(request)
+{
+}
+
+LLXMLRPCTransaction::Handler::~Handler()
+{
+}
+
+void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
+ LLCore::HttpResponse * response)
+{
+ LLCore::HttpStatus status = response->getStatus();
+
+ if (!status)
+ {
+ if ((status.toULong() != CURLE_SSL_PEER_CERTIFICATE) &&
+ (status.toULong() != CURLE_SSL_CACERT))
+ {
+ // if we have a curl error that's not already been handled
+ // (a non cert error), then generate the error message as
+ // appropriate
+ mImpl->setHttpStatus(status);
+ LLCertificate *errordata = static_cast<LLCertificate *>(status.getErrorData());
+
+ if (errordata)
+ {
+ mImpl->mErrorCert = LLPointer<LLCertificate>(errordata);
+ status.setErrorData(NULL);
+ errordata->unref();
+ }
+
+ LL_WARNS() << "LLXMLRPCTransaction error "
+ << status.toHex() << ": " << status.toString() << LL_ENDL;
+ LL_WARNS() << "LLXMLRPCTransaction request URI: "
+ << mImpl->mURI << LL_ENDL;
+ }
+
+ return;
+ }
+
+ mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
+ mImpl->mTransferStats = response->getTransferStats();
+
+ // the contents of a buffer array are potentially noncontiguous, so we
+ // will need to copy them into an contiguous block of memory for XMLRPC.
+ LLCore::BufferArray *body = response->getBody();
+ char * bodydata = new char[body->size()];
+
+ body->read(0, bodydata, body->size());
+
+ mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, body->size(), 0);
+
+ delete[] bodydata;
+
+ bool hasError = false;
+ bool hasFault = false;
+ int faultCode = 0;
+ std::string faultString;
+
+ LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
+ if (error.isValid())
+ {
+ hasError = true;
+ faultCode = error["faultCode"].asInt();
+ faultString = error["faultString"].asString();
+ }
+ else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
+ {
+ hasFault = true;
+ faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
+ faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
+ }
+
+ if (hasError || hasFault)
+ {
+ mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
+
+ LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
+ << (hasError ? "error " : "fault ")
+ << faultCode << ": "
+ << faultString << LL_ENDL;
+ LL_WARNS() << "LLXMLRPCTransaction request URI: "
+ << mImpl->mURI << LL_ENDL;
+ }
+
+}
+
+//=========================================================================
+
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
XMLRPC_REQUEST request, bool useGzip)
- : mCurlRequest(0),
+ : mHttpRequest(),
mStatus(LLXMLRPCTransaction::StatusNotStarted),
mURI(uri),
- mRequestText(0),
mResponse(0)
{
init(request, useGzip);
@@ -212,10 +327,9 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip)
- : mCurlRequest(0),
+ : mHttpRequest(),
mStatus(LLXMLRPCTransaction::StatusNotStarted),
mURI(uri),
- mRequestText(0),
mResponse(0)
{
XMLRPC_REQUEST request = XMLRPC_RequestNew();
@@ -231,127 +345,53 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
XMLRPC_RequestFree(request, 1);
}
-// _sslCertVerifyCallback
-// callback called when a cert verification is requested.
-// calls SECAPI to validate the context
-int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
{
- LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param;
- LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore);
- LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
- LLSD validation_params = LLSD::emptyMap();
- LLURI uri(transaction->mURI);
- validation_params[CERT_HOSTNAME] = uri.hostName();
- try
- {
- // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects
- store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
- }
- catch (LLCertValidationTrustException& cert_exception)
- {
- // this exception is is handled differently than the general cert
- // exceptions, as we allow the user to actually add the certificate
- // for trust.
- // therefore we pass back a different error code
- // NOTE: We're currently 'wired' to pass around CURL error codes. This is
- // somewhat clumsy, as we may run into errors that do not map directly to curl
- // error codes. Should be refactored with login refactoring, perhaps.
- transaction->mCurlCode = CURLE_SSL_CACERT;
- // set the status directly. set curl status generates error messages and we want
- // to use the fixed ones from the exceptions
- transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
- // We should probably have a more generic way of passing information
- // back to the error handlers.
- transaction->mErrorCert = cert_exception.getCert();
- return 0;
- }
- catch (LLCertException& cert_exception)
- {
- transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE;
- // set the status directly. set curl status generates error messages and we want
- // to use the fixed ones from the exceptions
- transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
- transaction->mErrorCert = cert_exception.getCert();
- return 0;
- }
- catch (...)
- {
- // any other odd error, we just handle as a connect error.
- transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR;
- transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR);
- return 0;
- }
- return 1;
-}
+ LLCore::HttpOptions::ptr_t httpOpts;
+ LLCore::HttpHeaders::ptr_t httpHeaders;
-// _sslCtxFunction
-// Callback function called when an SSL Context is created via CURL
-// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion
-// based on SECAPI
-
-CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param)
-{
- SSL_CTX * ctx = (SSL_CTX *) sslctx;
- // disable any default verification for server certs
- SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
- // set the verification callback.
- SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param);
- // the calls are void
- return CURLE_OK;
-
-}
-void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
-{
- if (!mCurlRequest)
+ if (!mHttpRequest)
{
- mCurlRequest = new LLCurlEasyRequest();
+ mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
}
- if(!mCurlRequest->isValid())
- {
- LL_WARNS() << "mCurlRequest is invalid." << LL_ENDL ;
- delete mCurlRequest ;
- mCurlRequest = NULL ;
- return ;
- }
+ // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
+ httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
- mErrorCert = NULL;
+ httpOpts->setTimeout(40L);
-// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging
- mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
- mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
- BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
+ bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
mCertStore = gSavedSettings.getString("CertStore");
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
- mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
- // Be a little impatient about establishing connections.
- mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
- mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this);
- /* Setting the DNS cache timeout to -1 disables it completely.
- This might help with bug #503 */
- mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
+ httpOpts->setSSLVerifyPeer( vefifySSLCert );
+ httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0);
- mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
+ // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
+ httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
- if (useGzip)
- {
- mCurlRequest->setoptString(CURLOPT_ENCODING, "");
- }
+ httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
+
+ ///* Setting the DNS cache timeout to -1 disables it completely.
+ //This might help with bug #503 */
+ //httpOpts->setDNSCacheTimeout(-1);
+
+ LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray());
+
+ // TODO: See if there is a way to serialize to a preallocated buffer I'm
+ // not fond of the copy here.
+ int requestSize(0);
+ char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
+
+ body->append(requestText, requestSize);
- mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize);
- if (mRequestText)
- {
- mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText);
- mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize);
- }
- else
- {
- setStatus(StatusOtherError);
- }
+ XMLRPC_Free(requestText);
+
+ mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this ));
+
+ mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,
+ mURI, body.get(), httpOpts, httpHeaders, mHandler.get());
- mCurlRequest->sendRequest(mURI);
}
@@ -361,28 +401,17 @@ LLXMLRPCTransaction::Impl::~Impl()
{
XMLRPC_RequestFree(mResponse, 1);
}
-
- if (mRequestText)
- {
- XMLRPC_Free(mRequestText);
- }
-
- delete mCurlRequest;
- mCurlRequest = NULL ;
}
bool LLXMLRPCTransaction::Impl::process()
{
- if(!mCurlRequest || !mCurlRequest->isValid())
+ if (!mPostH || !mHttpRequest)
{
- LL_WARNS() << "transaction failed." << LL_ENDL ;
-
- delete mCurlRequest ;
- mCurlRequest = NULL ;
- return true ; //failed, quit.
+ LL_WARNS() << "transaction failed." << LL_ENDL;
+ return true; //failed, quit.
}
- switch(mStatus)
+ switch (mStatus)
{
case LLXMLRPCTransaction::StatusComplete:
case LLXMLRPCTransaction::StatusCURLError:
@@ -391,93 +420,25 @@ bool LLXMLRPCTransaction::Impl::process()
{
return true;
}
-
+
case LLXMLRPCTransaction::StatusNotStarted:
{
setStatus(LLXMLRPCTransaction::StatusStarted);
break;
}
-
+
default:
- {
- // continue onward
- }
- }
-
- if(!mCurlRequest->wait())
- {
- return false ;
+ break;
}
- while(1)
- {
- CURLcode result;
- bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
- if (newmsg)
- {
- if (result != CURLE_OK)
- {
- if ((result != CURLE_SSL_PEER_CERTIFICATE) &&
- (result != CURLE_SSL_CACERT))
- {
- // if we have a curl error that's not already been handled
- // (a non cert error), then generate the error message as
- // appropriate
- setCurlStatus(result);
-
- LL_WARNS() << "LLXMLRPCTransaction CURL error "
- << mCurlCode << ": " << mCurlRequest->getErrorString() << LL_ENDL;
- LL_WARNS() << "LLXMLRPCTransaction request URI: "
- << mURI << LL_ENDL;
- }
-
- return true;
- }
-
- setStatus(LLXMLRPCTransaction::StatusComplete);
+ LLCore::HttpStatus status = mHttpRequest->update(0);
- mResponse = XMLRPC_REQUEST_FromXML(
- mResponseText.data(), mResponseText.size(), NULL);
-
- bool hasError = false;
- bool hasFault = false;
- int faultCode = 0;
- std::string faultString;
-
- LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
- if (error.isValid())
- {
- hasError = true;
- faultCode = error["faultCode"].asInt();
- faultString = error["faultString"].asString();
- }
- else if (XMLRPC_ResponseIsFault(mResponse))
- {
- hasFault = true;
- faultCode = XMLRPC_GetResponseFaultCode(mResponse);
- faultString = XMLRPC_GetResponseFaultString(mResponse);
- }
-
- if (hasError || hasFault)
- {
- setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
-
- LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
- << (hasError ? "error " : "fault ")
- << faultCode << ": "
- << faultString << LL_ENDL;
- LL_WARNS() << "LLXMLRPCTransaction request URI: "
- << mURI << LL_ENDL;
- }
-
- return true;
- }
- else
- {
- break; // done
- }
+ status = mHttpRequest->getStatus();
+ if (!status)
+ {
+ return false;
}
-
+
return false;
}
@@ -516,64 +477,51 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status,
}
}
-void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
+void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
{
+ CURLcode code = static_cast<CURLcode>(status.toULong());
std::string message;
std::string uri = "http://secondlife.com/community/support.php";
-
+ LLURI failuri(mURI);
+
+
switch (code)
{
- case CURLE_COULDNT_RESOLVE_HOST:
- message =
- "DNS could not resolve the host name.\n"
- "Please verify that you can connect to the www.secondlife.com\n"
- "web site. If you can, but continue to receive this error,\n"
- "please go to the support section and report this problem.";
- break;
-
- case CURLE_SSL_PEER_CERTIFICATE:
- message =
- "The login server couldn't verify itself via SSL.\n"
- "If you continue to receive this error, please go\n"
- "to the Support section of the SecondLife.com web site\n"
- "and report the problem.";
- break;
-
- case CURLE_SSL_CACERT:
- case CURLE_SSL_CONNECT_ERROR:
- message =
- "Often this means that your computer\'s clock is set incorrectly.\n"
- "Please go to Control Panels and make sure the time and date\n"
- "are set correctly.\n"
- "Also check that your network and firewall are set up correctly.\n"
- "If you continue to receive this error, please go\n"
- "to the Support section of the SecondLife.com web site\n"
- "and report the problem.";
- break;
-
- default:
- break;
+ case CURLE_COULDNT_RESOLVE_HOST:
+ message =
+ std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\n"
+ "Please verify that you can connect to the www.secondlife.com\n"
+ "web site. If you can, but continue to receive this error,\n"
+ "please go to the support section and report this problem.";
+ break;
+
+ case CURLE_SSL_PEER_CERTIFICATE:
+ message =
+ "The login server couldn't verify itself via SSL.\n"
+ "If you continue to receive this error, please go\n"
+ "to the Support section of the SecondLife.com web site\n"
+ "and report the problem.";
+ break;
+
+ case CURLE_SSL_CACERT:
+ case CURLE_SSL_CONNECT_ERROR:
+ message =
+ "Often this means that your computer\'s clock is set incorrectly.\n"
+ "Please go to Control Panels and make sure the time and date\n"
+ "are set correctly.\n"
+ "Also check that your network and firewall are set up correctly.\n"
+ "If you continue to receive this error, please go\n"
+ "to the Support section of the SecondLife.com web site\n"
+ "and report the problem.";
+ break;
+
+ default:
+ break;
}
-
+
mCurlCode = code;
setStatus(StatusCURLError, message, uri);
-}
-
-size_t LLXMLRPCTransaction::Impl::curlDownloadCallback(
- char* data, size_t size, size_t nmemb, void* user_data)
-{
- Impl& impl(*(Impl*)user_data);
-
- size_t n = size * nmemb;
- impl.mResponseText.append(data, n);
-
- if (impl.mStatus == LLXMLRPCTransaction::StatusStarted)
- {
- impl.setStatus(LLXMLRPCTransaction::StatusDownloading);
- }
-
- return n;
}
@@ -645,11 +593,11 @@ F64 LLXMLRPCTransaction::transferRate()
return 0.0L;
}
- double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0;
+ double rate_bits_per_sec = impl.mTransferStats->mSpeedDownload * 8.0;
LL_INFOS("AppInit") << "Buffer size: " << impl.mResponseText.size() << " B" << LL_ENDL;
- LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL;
- LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL;
+ LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferStats->mSizeDownload << " B" << LL_ENDL;
+ LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferStats->mTotalTime << " s" << LL_ENDL;
LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL;
return rate_bits_per_sec;
diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h
index f2589c7f41..3a1c9c82b7 100755
--- a/indra/newview/llxmlrpctransaction.h
+++ b/indra/newview/llxmlrpctransaction.h
@@ -81,7 +81,7 @@ private:
class LLXMLRPCTransaction
- // an asynchronous request and respones via XML-RPC
+ // an asynchronous request and responses via XML-RPC
{
public:
LLXMLRPCTransaction(const std::string& uri,
@@ -127,7 +127,9 @@ public:
// only valid if StsatusComplete, otherwise 0.0
private:
+ class Handler;
class Impl;
+
Impl& impl;
};
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 03712c1065..57e2faca5b 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -105,7 +105,6 @@
#include "llspatialpartition.h"
#include "llmutelist.h"
#include "lltoolpie.h"
-#include "llcurl.h"
#include "llnotifications.h"
#include "llpathinglib.h"
#include "llfloaterpathfindingconsole.h"
diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml
index 91adec0789..3deb8f7233 100755
--- a/indra/newview/skins/default/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory.xml
@@ -785,14 +785,6 @@
layout="topleft"
name="Marketplace Separator" />
<menu_item_call
- label="Copy to Merchant Outbox"
- layout="topleft"
- name="Merchant Copy">
- <menu_item_call.on_click
- function="Inventory.DoToSelected"
- parameter="copy_to_outbox" />
- </menu_item_call>
- <menu_item_call
label="Copy to Marketplace Listings"
layout="topleft"
name="Marketplace Copy">
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2463c5f43b..52fcfba79d 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -173,13 +173,6 @@
<menu_item_call.on_click
function="BuyCurrency" />
</menu_item_call>
- <menu_item_call
- label="Merchant Outbox..."
- name="MerchantOutbox">
- <menu_item_call.on_click
- function="Floater.ToggleOrBringToFront"
- parameter="outbox" />
- </menu_item_call>
<menu_item_call
label="Marketplace listings..."
name="MarketplaceListings">
diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
deleted file mode 100755
index bde991a01e..0000000000
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * @file llcapabilitylistener_test.cpp
- * @author Nat Goodspeed
- * @date 2008-12-31
- * @brief Test for llcapabilitylistener.cpp.
- *
- * $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$
- */
-
-// Precompiled header
-#include "../llviewerprecompiledheaders.h"
-// Own header
-#include "../llcapabilitylistener.h"
-// STL headers
-#include <stdexcept>
-#include <map>
-#include <vector>
-// std headers
-// external library headers
-#include "boost/bind.hpp"
-// other Linden headers
-#include "../test/lltut.h"
-#include "../llcapabilityprovider.h"
-#include "lluuid.h"
-#include "tests/networkio.h"
-#include "tests/commtest.h"
-#include "tests/wrapllerrs.h"
-#include "message.h"
-#include "stringize.h"
-
-#if defined(LL_WINDOWS)
-#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr
-#endif
-
-/*****************************************************************************
-* TestCapabilityProvider
-*****************************************************************************/
-struct TestCapabilityProvider: public LLCapabilityProvider
-{
- TestCapabilityProvider(const LLHost& host):
- mHost(host)
- {}
-
- std::string getCapability(const std::string& cap) const
- {
- CapMap::const_iterator found = mCaps.find(cap);
- if (found != mCaps.end())
- return found->second;
- // normal LLViewerRegion lookup failure mode
- return "";
- }
- void setCapability(const std::string& cap, const std::string& url)
- {
- mCaps[cap] = url;
- }
- const LLHost& getHost() const { return mHost; }
- std::string getDescription() const { return "TestCapabilityProvider"; }
-
- LLHost mHost;
- typedef std::map<std::string, std::string> CapMap;
- CapMap mCaps;
-};
-
-/*****************************************************************************
-* Dummy LLMessageSystem methods
-*****************************************************************************/
-/*==========================================================================*|
-// This doesn't work because we're already linking in llmessage.a, and we get
-// duplicate-symbol errors from the linker. Perhaps if I wanted to go through
-// the exercise of providing dummy versions of every single symbol defined in
-// message.o -- maybe some day.
-typedef std::vector< std::pair<std::string, std::string> > StringPairVector;
-StringPairVector call_history;
-
-S32 LLMessageSystem::sendReliable(const LLHost& host)
-{
- call_history.push_back(StringPairVector::value_type("sendReliable", stringize(host)));
- return 0;
-}
-|*==========================================================================*/
-
-/*****************************************************************************
-* TUT
-*****************************************************************************/
-namespace tut
-{
- struct llcapears_data: public commtest_data
- {
- TestCapabilityProvider provider;
- LLCapabilityListener regionListener;
- LLEventPump& regionPump;
-
- llcapears_data():
- provider(host),
- regionListener("testCapabilityListener", NULL, provider, LLUUID(), LLUUID()),
- regionPump(regionListener.getCapAPI())
- {
- LLCurl::initClass();
- provider.setCapability("good", server + "capability-test");
- provider.setCapability("fail", server + "fail");
- }
- };
- typedef test_group<llcapears_data> llcapears_group;
- typedef llcapears_group::object llcapears_object;
- llcapears_group llsdmgr("llcapabilitylistener");
-
- template<> template<>
- void llcapears_object::test<1>()
- {
- LLSD request, body;
- body["data"] = "yes";
- request["payload"] = body;
- request["reply"] = replyPump.getName();
- request["error"] = errorPump.getName();
- std::string threw;
- try
- {
- WrapLLErrs capture;
- regionPump.post(request);
- }
- catch (const WrapLLErrs::FatalException& e)
- {
- threw = e.what();
- }
- ensure_contains("missing capability name", threw, "without 'message' key");
- }
-
- template<> template<>
- void llcapears_object::test<2>()
- {
- LLSD request, body;
- body["data"] = "yes";
- request["message"] = "good";
- request["payload"] = body;
- request["reply"] = replyPump.getName();
- request["error"] = errorPump.getName();
- regionPump.post(request);
- ensure("got response", netio.pump());
- ensure("success response", success);
- ensure_equals(result["reply"].asString(), "success");
-
- body["status"] = 499;
- body["reason"] = "custom error message";
- request["message"] = "fail";
- request["payload"] = body;
- regionPump.post(request);
- ensure("got response", netio.pump());
- ensure("failure response", ! success);
- ensure_equals(result["status"].asInteger(), body["status"].asInteger());
- ensure_equals(result["reason"].asString(), body["reason"].asString());
- }
-
- template<> template<>
- void llcapears_object::test<3>()
- {
- LLSD request, body;
- body["data"] = "yes";
- request["message"] = "unknown";
- request["payload"] = body;
- request["reply"] = replyPump.getName();
- request["error"] = errorPump.getName();
- std::string threw;
- try
- {
- WrapLLErrs capture;
- regionPump.post(request);
- }
- catch (const WrapLLErrs::FatalException& e)
- {
- threw = e.what();
- }
- ensure_contains("bad capability name", threw, "unsupported capability");
- }
-
- struct TestMapper: public LLCapabilityListener::CapabilityMapper
- {
- // Instantiator gets to specify whether mapper expects a reply.
- // I'd really like to be able to test CapabilityMapper::buildMessage()
- // functionality, too, but -- even though LLCapabilityListener accepts
- // the LLMessageSystem* that it passes to CapabilityMapper --
- // LLMessageSystem::sendReliable(const LLHost&) isn't virtual, so it's
- // not helpful to pass a subclass instance. I suspect that making any
- // LLMessageSystem methods virtual would provoke howls of outrage,
- // given how heavily it's used. Nor can I just provide a local
- // definition of LLMessageSystem::sendReliable(const LLHost&) because
- // we're already linking in the rest of message.o via llmessage.a, and
- // that produces duplicate-symbol link errors.
- TestMapper(const std::string& replyMessage = std::string()):
- LLCapabilityListener::CapabilityMapper("test", replyMessage)
- {}
- virtual void buildMessage(LLMessageSystem* msg,
- const LLUUID& agentID,
- const LLUUID& sessionID,
- const std::string& capabilityName,
- const LLSD& payload) const
- {
- msg->newMessageFast(_PREHASH_SetStartLocationRequest);
- msg->nextBlockFast( _PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, agentID);
- msg->addUUIDFast(_PREHASH_SessionID, sessionID);
- msg->nextBlockFast( _PREHASH_StartLocationData);
- // corrected by sim
- msg->addStringFast(_PREHASH_SimName, "");
- msg->addU32Fast(_PREHASH_LocationID, payload["HomeLocation"]["LocationId"].asInteger());
-/*==========================================================================*|
- msg->addVector3Fast(_PREHASH_LocationPos,
- ll_vector3_from_sdmap(payload["HomeLocation"]["LocationPos"]));
- msg->addVector3Fast(_PREHASH_LocationLookAt,
- ll_vector3_from_sdmap(payload["HomeLocation"]["LocationLookAt"]));
-|*==========================================================================*/
- }
- };
-
- template<> template<>
- void llcapears_object::test<4>()
- {
- TestMapper testMapper("WantReply");
- LLSD request, body;
- body["data"] = "yes";
- request["message"] = "test";
- request["payload"] = body;
- request["reply"] = replyPump.getName();
- request["error"] = errorPump.getName();
- std::string threw;
- try
- {
- WrapLLErrs capture;
- regionPump.post(request);
- }
- catch (const WrapLLErrs::FatalException& e)
- {
- threw = e.what();
- }
- ensure_contains("capability mapper wants reply", threw, "unimplemented support for reply message");
- }
-
- template<> template<>
- void llcapears_object::test<5>()
- {
- TestMapper testMapper;
- std::string threw;
- try
- {
- TestMapper testMapper2;
- }
- catch (const std::runtime_error& e)
- {
- threw = e.what();
- }
- ensure_contains("no dup cap mapper", threw, "DupCapMapper");
- }
-}
diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp
index 25e6de46d9..21c83184dc 100755
--- a/indra/newview/tests/llhttpretrypolicy_test.cpp
+++ b/indra/newview/tests/llhttpretrypolicy_test.cpp
@@ -234,13 +234,13 @@ void RetryPolicyTestObject::test<6>()
std::string str1("0");
seconds_to_wait = F32_MAX;
- success = getSecondsUntilRetryAfter(str1, seconds_to_wait);
+ success = LLAdaptiveRetryPolicy::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);
+ success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str2, seconds_to_wait);
ensure("parse 2", success);
ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8);
@@ -248,7 +248,7 @@ void RetryPolicyTestObject::test<6>()
time(&nowseconds);
std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123();
seconds_to_wait = F32_MAX;
- success = getSecondsUntilRetryAfter(str3, seconds_to_wait);
+ success = LLAdaptiveRetryPolicy::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);
@@ -285,10 +285,10 @@ void RetryPolicyTestObject::test<7>()
ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F);
LLCore::HttpResponse *response;
- LLCore::HttpHeaders *headers;
+ LLCore::HttpHeaders::ptr_t headers;
response = new LLCore::HttpResponse();
- headers = new LLCore::HttpHeaders();
+ headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
response->setStatus(503);
response->setHeaders(headers);
headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600"));
@@ -299,7 +299,7 @@ void RetryPolicyTestObject::test<7>()
response->release();
response = new LLCore::HttpResponse();
- headers = new LLCore::HttpHeaders();
+ headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
response->setStatus(503);
response->setHeaders(headers);
time(&nowseconds);
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index 6f57daf151..61120686e4 100755
--- a/indra/newview/tests/llmediadataclient_test.cpp
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -106,7 +106,7 @@ const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","true");
LLSD *gPostRecords = NULL;
F64 gMinimumInterestLevel = (F64)0.0;
-
+#if 0
// stubs:
void LLHTTPClient::post(
const std::string& url,
@@ -140,6 +140,7 @@ void LLHTTPClient::post(
}
responder->successResult(result);
}
+#endif
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 c49b0350e9..ea5014a59c 100755
--- a/indra/newview/tests/llremoteparcelrequest_test.cpp
+++ b/indra/newview/tests/llremoteparcelrequest_test.cpp
@@ -27,6 +27,7 @@
#include "linden_common.h"
#include "../test/lltut.h"
+#if 0
#include "../llremoteparcelrequest.h"
@@ -134,3 +135,4 @@ namespace tut
processor.processParcelInfoReply(gMessageSystem, NULL);
}
}
+#endif
diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp
deleted file mode 100755
index 5e73dbb981..0000000000
--- a/indra/newview/tests/lltranslate_test.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/**
- * @file lltranslate_test.cpp
- *
- * $LicenseInfo:firstyear=2011&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2011, 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 "../lltranslate.h"
-#include "../llversioninfo.h"
-#include "../llviewercontrol.h"
-
-#include "llbufferstream.h"
-#include "lltrans.h"
-#include "llui.h"
-
-#include "../../llmessage/llhttpconstants.cpp"
-
-static const std::string GOOGLE_VALID_RESPONSE1 =
-"{\
- \"data\": {\
- \"translations\": [\
- {\
- \"translatedText\": \"привет\",\
- \"detectedSourceLanguage\": \"es\"\
- }\
- ]\
- }\
-}";
-
-static const std::string GOOGLE_VALID_RESPONSE2 =
-"{\
- \"data\": {\
- \"translations\": [\
- {\
- \"translatedText\": \"привет\"\
- }\
- ]\
- }\
-}\
-";
-
-static const std::string GOOGLE_VALID_RESPONSE3 =
-"{\
- \"error\": {\
- \"errors\": [\
- {\
- \"domain\": \"global\",\
- \"reason\": \"invalid\",\
- \"message\": \"Invalid Value\"\
- }\
- ],\
- \"code\": 400,\
- \"message\": \"Invalid Value\"\
- }\
-}";
-
-static const std::string BING_VALID_RESPONSE1 =
-"<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Привет</string>";
-
-static const std::string BING_VALID_RESPONSE2 =
-"<html><body><h1>Argument Exception</h1><p>Method: Translate()</p><p>Parameter: </p>\
-<p>Message: 'from' must be a valid language</p><code></code>\
-<p>message id=3743.V2_Rest.Translate.58E8454F</p></body></html>";
-
-static const std::string BING_VALID_RESPONSE3 =
-"<html><body><h1>Argument Exception</h1><p>Method: Translate()</p>\
-<p>Parameter: appId</p><p>Message: Invalid appId&#xD;\nParameter name: appId</p>\
-<code></code><p>message id=3737.V2_Rest.Translate.56016759</p></body></html>";
-
-namespace tut
-{
- class translate_test
- {
- protected:
- void test_translation(
- LLTranslationAPIHandler& handler,
- int status, const std::string& resp,
- const std::string& exp_trans, const std::string& exp_lang, const std::string& exp_err)
- {
- std::string translation, detected_lang, err_msg;
- bool rc = handler.parseResponse(status, resp, translation, detected_lang, err_msg);
- ensure_equals("rc", rc, (status == 200));
- ensure_equals("err_msg", err_msg, exp_err);
- ensure_equals("translation", translation, exp_trans);
- ensure_equals("detected_lang", detected_lang, exp_lang);
- }
-
- LLGoogleTranslationHandler mGoogle;
- LLBingTranslationHandler mBing;
- };
-
- typedef test_group<translate_test> translate_test_group_t;
- typedef translate_test_group_t::object translate_test_object_t;
- tut::translate_test_group_t tut_translate("LLTranslate");
-
- template<> template<>
- void translate_test_object_t::test<1>()
- {
- test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE1, "привет", "es", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<2>()
- {
- test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE2, "привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<3>()
- {
- test_translation(mGoogle, 400, GOOGLE_VALID_RESPONSE3, "", "", "Invalid Value");
- }
-
- template<> template<>
- void translate_test_object_t::test<4>()
- {
- test_translation(mGoogle, 400,
- "",
- "", "", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n");
- }
-
- template<> template<>
- void translate_test_object_t::test<5>()
- {
- test_translation(mGoogle, 400,
- "[]",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<6>()
- {
- test_translation(mGoogle, 400,
- "{\"oops\": \"invalid\"}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<7>()
- {
- test_translation(mGoogle, 400,
- "{\"data\": {}}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<8>()
- {
- test_translation(mGoogle, 400,
- "{\"data\": { \"translations\": [ {} ] }}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<9>()
- {
- test_translation(mGoogle, 400,
- "{\"data\": { \"translations\": [ { \"translatedTextZZZ\": \"привет\", \"detectedSourceLanguageZZZ\": \"es\" } ] }}",
- "", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<10>()
- {
- test_translation(mBing, 200, BING_VALID_RESPONSE1, "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<11>()
- {
- test_translation(mBing, 400, BING_VALID_RESPONSE2, "", "", "'from' must be a valid language");
- }
-
- template<> template<>
- void translate_test_object_t::test<12>()
- {
- test_translation(mBing, 400, BING_VALID_RESPONSE3, "", "", "Invalid appId\nParameter name: appId");
- }
-
- template<> template<>
- void translate_test_object_t::test<13>()
- {
- test_translation(mBing, 200,
- "Привет</string>",
- "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<14>()
- {
- test_translation(mBing, 200,
- "<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Привет",
- "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<15>()
- {
- test_translation(mBing, 200,
- "Привет",
- "Привет", "", "");
- }
-
- template<> template<>
- void translate_test_object_t::test<16>()
- {
- test_translation(mBing, 400,
- "Message: some error</p>",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<17>()
- {
- test_translation(mBing, 400,
- "Message: some error",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<18>()
- {
- test_translation(mBing, 400,
- "some error</p>",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<19>()
- {
- test_translation(mBing, 400,
- "some error",
- "", "", "some error");
- }
-
- template<> template<>
- void translate_test_object_t::test<20>()
- {
- std::string url;
- mBing.getTranslateURL(url, "en", "es", "hi");
- ensure_equals("bing URL", url,
- "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es&from=en");
- }
-
- template<> template<>
- void translate_test_object_t::test<21>()
- {
- std::string url;
- mBing.getTranslateURL(url, "", "es", "hi");
- ensure_equals("bing URL", url,
- "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es");
- }
-
- template<> template<>
- void translate_test_object_t::test<22>()
- {
- std::string url;
- mGoogle.getTranslateURL(url, "en", "es", "hi");
- ensure_equals("google URL", url,
- "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es&source=en");
- }
-
- template<> template<>
- void translate_test_object_t::test<23>()
- {
- std::string url;
- mGoogle.getTranslateURL(url, "", "es", "hi");
- ensure_equals("google URL", url,
- "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es");
- }
-}
-
-//== Misc stubs ===============================================================
-LLControlGroup gSavedSettings("test");
-
-std::string LLUI::getLanguage() { return "en"; }
-std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) { return "dummy"; }
-
-LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name) {}
-std::string LLControlGroup::getString(const std::string& name) { return "dummy"; }
-LLControlGroup::~LLControlGroup() {}
-
-LLCurl::Responder::Responder() {}
-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) {}
-void LLHTTPClient::get(const std::string&, LLPointer<LLCurl::Responder>, const LLSD&, const F32, bool) {}
-
-LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer)
-: std::iostream(&mStreamBuf), mStreamBuf(channels, buffer) {}
-LLBufferStream::~LLBufferStream() {}
-
-LLBufferStreamBuf::LLBufferStreamBuf(const LLChannelDescriptors&, LLBufferArray*) {}
-#if( LL_WINDOWS || __GNUC__ > 2)
-LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff(
- off_type off,
- std::ios::seekdir way,
- std::ios::openmode which)
-#else
-streampos LLBufferStreamBuf::seekoff(
- streamoff off,
- std::ios::seekdir way,
- std::ios::openmode which)
-#endif
-{ return 0; }
-int LLBufferStreamBuf::sync() {return 0;}
-int LLBufferStreamBuf::underflow() {return 0;}
-int LLBufferStreamBuf::overflow(int) {return 0;}
-LLBufferStreamBuf::~LLBufferStreamBuf() {}
-
-S32 LLVersionInfo::getBuild() { return 0; }
-const std::string& LLVersionInfo::getChannel() {static std::string dummy; return dummy;}
-S32 LLVersionInfo::getMajor() { return 0; }
-S32 LLVersionInfo::getMinor() { return 0; }
-S32 LLVersionInfo::getPatch() { return 0; }
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 01d1d830a2..229cb8e5a0 100755
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -4,6 +4,7 @@ project (lltest)
include(00-Common)
include(LLCommon)
+include(LLCoreHttp)
include(LLInventory)
include(LLMath)
include(LLMessage)
@@ -18,6 +19,7 @@ include(GoogleMock)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLDATABASE_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
@@ -91,12 +93,16 @@ target_link_libraries(lltest
${LLXML_LIBRARIES}
${LSCRIPT_LIBRARIES}
${LLCOMMON_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${EXPAT_LIBRARIES}
${GOOGLEMOCK_LIBRARIES}
${PTHREAD_LIBRARY}
${WINDOWS_LIBRARIES}
${BOOST_PROGRAM_OPTIONS_LIBRARY}
${BOOST_REGEX_LIBRARY}
+ ${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
${DL_LIBRARY}
${GOOGLE_PERFTOOLS_LIBRARIES}
)
diff --git a/indra/test/io.cpp b/indra/test/io.cpp
index 97726c2b92..ff900ab96b 100755
--- a/indra/test/io.cpp
+++ b/indra/test/io.cpp
@@ -41,8 +41,6 @@
#include "llpipeutil.h"
#include "llpumpio.h"
#include "llsd.h"
-#include "llsdrpcclient.h"
-#include "llsdrpcserver.h"
#include "llsdserialize.h"
#include "llcommon.h"
#include "lluuid.h"
@@ -1177,425 +1175,6 @@ namespace tut
}
}
-namespace tut
-{
- struct rpc_server_data
- {
- class LLSimpleRPCResponse : public LLSDRPCResponse
- {
- public:
- LLSimpleRPCResponse(LLSD* response) :
- mResponsePtr(response)
- {
- }
- ~LLSimpleRPCResponse()
- {
- }
- virtual bool response(LLPumpIO* pump)
- {
- *mResponsePtr = mReturnValue;
- return true;
- }
- virtual bool fault(LLPumpIO* pump)
- {
- *mResponsePtr = mReturnValue;
- return false;
- }
- virtual bool error(LLPumpIO* pump)
- {
- ensure("LLSimpleRPCResponse::error()", false);
- return false;
- }
- public:
- LLSD* mResponsePtr;
- };
-
- class LLSimpleRPCClient : public LLSDRPCClient
- {
- public:
- LLSimpleRPCClient(LLSD* response) :
- mResponsePtr(response)
- {
- }
- ~LLSimpleRPCClient() {}
- void echo(const LLSD& parameter)
- {
- LLSimpleRPCResponse* resp;
- resp = new LLSimpleRPCResponse(mResponsePtr);
- static const std::string URI_NONE;
- static const std::string METHOD_ECHO("echo");
- call(URI_NONE, METHOD_ECHO, parameter, resp, EPBQ_CALLBACK);
- }
- public:
- LLSD* mResponsePtr;
- };
-
- class LLSimpleRPCServer : public LLSDRPCServer
- {
- public:
- LLSimpleRPCServer()
- {
- mMethods["echo"] = new mem_fn_t(
- this,
- &LLSimpleRPCServer::rpc_Echo);
- }
- ~LLSimpleRPCServer() {}
- protected:
- typedef LLSDRPCMethodCall<LLSimpleRPCServer> mem_fn_t;
- ESDRPCSStatus rpc_Echo(
- const LLSD& parameter,
- const LLChannelDescriptors& channels,
- LLBufferArray* data)
- {
- buildResponse(channels, data, parameter);
- return ESDRPCS_DONE;
- }
- };
-
- apr_pool_t* mPool;
- LLPumpIO* mPump;
- LLPumpIO::chain_t mChain;
- LLSimpleRPCClient* mClient;
- LLSD mResponse;
-
- rpc_server_data() :
- mPool(NULL),
- mPump(NULL),
- mClient(NULL)
- {
- apr_pool_create(&mPool, NULL);
- mPump = new LLPumpIO(mPool);
- mClient = new LLSimpleRPCClient(&mResponse);
- mChain.push_back(LLIOPipe::ptr_t(mClient));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
- mChain.push_back(LLIOPipe::ptr_t(new LLSimpleRPCServer));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
- mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD));
- mChain.push_back(LLIOPipe::ptr_t(mClient));
- }
- ~rpc_server_data()
- {
- mChain.clear();
- delete mPump;
- mPump = NULL;
- apr_pool_destroy(mPool);
- mPool = NULL;
- }
- void pump_loop(const LLSD& request)
- {
- LLTimer timer;
- timer.setTimerExpirySec(1.0f);
- mClient->echo(request);
- mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS);
- while(mResponse.isUndefined() && !timer.hasExpired())
- {
- mPump->pump();
- mPump->callback();
- }
- }
- };
- typedef test_group<rpc_server_data> rpc_server_test;
- typedef rpc_server_test::object rpc_server_object;
- tut::rpc_server_test rpc("rpc_server");
-
- template<> template<>
- void rpc_server_object::test<1>()
- {
- LLSD request;
- request = 1;
- pump_loop(request);
- //LL_INFOS() << "request: " << *request << LL_ENDL;
- //LL_INFOS() << "response: " << *mResponse << LL_ENDL;
- ensure_equals("integer request response", mResponse.asInteger(), 1);
- }
-
- template<> template<>
- void rpc_server_object::test<2>()
- {
-//#if LL_WINDOWS && _MSC_VER >= 1400
-// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser.");
-//#endif
- std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0");
- std::stringstream stream;
- stream << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}";
- std::vector<U8> expected_binary;
- expected_binary.resize(stream.str().size());
- memcpy(&expected_binary[0], stream.str().c_str(), stream.str().size()); /* Flawfinder: ignore */
- stream.str("");
- stream << "[{'uri':'" << uri << "'}, {'version':i1}, "
- << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], "
- << "'attachment_data':["
- << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},"
- << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << expected_binary.size() << ")\"";
- stream.write((const char*)&expected_binary[0], expected_binary.size());
- stream << "\"}"
- << "]"
- << "}]";
-
- LLSD request;
- S32 count = LLSDSerialize::fromNotation(
- request,
- stream,
- stream.str().size());
- ensure("parsed something", (count > 0));
-
- pump_loop(request);
- ensure_equals("return type", mResponse.type(), LLSD::TypeArray);
- ensure_equals("return size", mResponse.size(), 3);
-
- ensure_equals(
- "uri parameter type",
- mResponse[0].type(),
- LLSD::TypeMap);
- ensure_equals(
- "uri type",
- mResponse[0]["uri"].type(),
- LLSD::TypeString);
- ensure_equals("uri value", mResponse[0]["uri"].asString(), uri);
-
- ensure_equals(
- "version parameter type",
- mResponse[1].type(),
- LLSD::TypeMap);
- ensure_equals(
- "version type",
- mResponse[1]["version"].type(),
- LLSD::TypeInteger);
- ensure_equals(
- "version value",
- mResponse[1]["version"].asInteger(),
- 1);
-
- ensure_equals("agent params type", mResponse[2].type(), LLSD::TypeMap);
- LLSD attachment_data = mResponse[2]["attachment_data"];
- ensure("attachment data exists", attachment_data.isDefined());
- ensure_equals(
- "attachment type",
- attachment_data.type(),
- LLSD::TypeArray);
- ensure_equals(
- "attachment type 0",
- attachment_data[0].type(),
- LLSD::TypeMap);
- ensure_equals(
- "attachment type 1",
- attachment_data[1].type(),
- LLSD::TypeMap);
- ensure_equals("attachment size 1", attachment_data[1].size(), 3);
- ensure_equals(
- "asset data type",
- attachment_data[1]["asset_data"].type(),
- LLSD::TypeBinary);
- std::vector<U8> actual_binary;
- actual_binary = attachment_data[1]["asset_data"].asBinary();
- ensure_equals(
- "binary data size",
- actual_binary.size(),
- expected_binary.size());
- ensure(
- "binary data",
- (0 == memcmp(
- &actual_binary[0],
- &expected_binary[0],
- expected_binary.size())));
- }
-
- template<> template<>
- void rpc_server_object::test<3>()
- {
-//#if LL_WINDOWS && _MSC_VER >= 1400
-// skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser.");
-//#endif
- std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0");
-
- LLBufferArray buffer;
- LLChannelDescriptors buffer_channels = buffer.nextChannel();
- LLBufferStream stream(buffer_channels, &buffer);
- stream << "[{'uri':'" << uri << "'}, {'version':i1}, "
- << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], "
- << "'attachment_data':["
- << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},";
-
- std::stringstream tmp_str;
- tmp_str << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}";
- std::vector<U8> expected_binary;
- expected_binary.resize(tmp_str.str().size());
- memcpy( /* Flawfinder: ignore */
- &expected_binary[0],
- tmp_str.str().c_str(),
- tmp_str.str().size());
-
- LLBufferArray attachment_buffer;
- LLChannelDescriptors attach_channels = attachment_buffer.nextChannel();
- LLBufferStream attach_stream(attach_channels, &attachment_buffer);
- attach_stream.write((const char*)&expected_binary[0], expected_binary.size());
- attach_stream.flush();
- S32 len = attachment_buffer.countAfter(attach_channels.out(), NULL);
- stream << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << len << ")\"";
- stream.flush();
- buffer.takeContents(attachment_buffer);
- stream << "\"}]}]";
- stream.flush();
-
- LLChannelDescriptors read_channel = buffer.nextChannel();
- LLBufferStream read_stream(read_channel, &buffer);
- LLSD request;
- S32 count = LLSDSerialize::fromNotation(
- request,
- read_stream,
- buffer.count(read_channel.in()));
- ensure("parsed something", (count > 0));
- ensure("deserialized", request.isDefined());
-
- // do the rpc round trip
- pump_loop(request);
-
- ensure_equals("return type", mResponse.type(), LLSD::TypeArray);
- ensure_equals("return size", mResponse.size(), 3);
-
- LLSD child = mResponse[0];
- ensure("uri map exists", child.isDefined());
- ensure_equals("uri parameter type", child.type(), LLSD::TypeMap);
- ensure("uri string exists", child.has("uri"));
- ensure_equals("uri type", child["uri"].type(), LLSD::TypeString);
- ensure_equals("uri value", child["uri"].asString(), uri);
-
- child = mResponse[1];
- ensure("version map exists", child.isDefined());
- ensure_equals("version param type", child.type(), LLSD::TypeMap);
- ensure_equals(
- "version type",
- child["version"].type(),
- LLSD::TypeInteger);
- ensure_equals("version value", child["version"].asInteger(), 1);
-
- child = mResponse[2];
- ensure("agent params map exists", child.isDefined());
- ensure_equals("agent params type", child.type(), LLSD::TypeMap);
- child = child["attachment_data"];
- ensure("attachment data exists", child.isDefined());
- ensure_equals("attachment type", child.type(), LLSD::TypeArray);
- LLSD attachment = child[0];
- ensure_equals("attachment type 0", attachment.type(), LLSD::TypeMap);
- attachment = child[1];
- ensure_equals("attachment type 1", attachment.type(), LLSD::TypeMap);
- ensure_equals("attachment size 1", attachment.size(), 3);
- ensure_equals(
- "asset data type",
- attachment["asset_data"].type(),
- LLSD::TypeBinary);
- std::vector<U8> actual_binary = attachment["asset_data"].asBinary();
- ensure_equals(
- "binary data size",
- actual_binary.size(),
- expected_binary.size());
- ensure(
- "binary data",
- (0 == memcmp(
- &actual_binary[0],
- &expected_binary[0],
- expected_binary.size())));
- }
-
- template<> template<>
- void rpc_server_object::test<4>()
- {
- std::string message("parcel '' is naughty.");
- std::stringstream str;
- str << "{'message':'" << LLSDNotationFormatter::escapeString(message)
- << "'}";
- LLSD request;
- S32 count = LLSDSerialize::fromNotation(
- request,
- str,
- str.str().size());
- ensure_equals("parse count", count, 2);
- ensure_equals("request type", request.type(), LLSD::TypeMap);
- pump_loop(request);
- ensure("valid response", mResponse.isDefined());
- ensure_equals("response type", mResponse.type(), LLSD::TypeMap);
- std::string actual = mResponse["message"].asString();
- ensure_equals("message contents", actual, message);
- }
-
- template<> template<>
- void rpc_server_object::test<5>()
- {
- // test some of the problem cases with llsdrpc over xmlrpc -
- // for example:
- // * arrays are auto-converted to parameter lists, thus, this
- // becomes one parameter.
- // * undef goes over the wire as false (this might not be a good idea)
- // * uuids are converted to string.
- std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]";
- std::istringstream istr;
- istr.str(val);
- LLSD sd;
- LLSDSerialize::fromNotation(sd, istr, val.size());
- pump_loop(sd);
- ensure("valid response", mResponse.isDefined());
- ensure_equals("parsed type", mResponse.type(), LLSD::TypeMap);
- ensure_equals("parsed size", mResponse.size(), 2);
- LLSD failures = mResponse["failures"];
- ensure_equals("no failures.", failures.asBoolean(), false);
- LLSD success = mResponse["successfuls"];
- ensure_equals("success type", success.type(), LLSD::TypeArray);
- ensure_equals("success size", success.size(), 1);
- ensure_equals(
- "success instance type",
- success[0].type(),
- LLSD::TypeString);
- }
-
-/*
- template<> template<>
- void rpc_server_object::test<5>()
- {
- std::string expected("\xf3");//\xffsomething");
- LLSD* request = LLSD::createString(expected);
- pump_loop(request);
- std::string actual;
- mResponse->getString(actual);
- if(actual != expected)
- {
- //LL_WARNS() << "iteration " << i << LL_ENDL;
- std::ostringstream e_str;
- std::string::iterator iter = expected.begin();
- std::string::iterator end = expected.end();
- for(; iter != end; ++iter)
- {
- e_str << (S32)((U8)(*iter)) << " ";
- }
- e_str << std::endl;
- llsd_serialize_string(e_str, expected);
- LL_WARNS() << "expected size: " << expected.size() << LL_ENDL;
- LL_WARNS() << "expected: " << e_str.str() << LL_ENDL;
-
- std::ostringstream a_str;
- iter = actual.begin();
- end = actual.end();
- for(; iter != end; ++iter)
- {
- a_str << (S32)((U8)(*iter)) << " ";
- }
- a_str << std::endl;
- llsd_serialize_string(a_str, actual);
- LL_WARNS() << "actual size: " << actual.size() << LL_ENDL;
- LL_WARNS() << "actual: " << a_str.str() << LL_ENDL;
- }
- ensure_equals("binary string request response", actual, expected);
- delete request;
- }
-
- template<> template<>
- void rpc_server_object::test<5>()
- {
- }
-*/
-}
-
-
/*
'asset_data':b(12100)"{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemID STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"
*/
diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp
index aa23699de0..8718360f0c 100755
--- a/indra/test/message_tut.cpp
+++ b/indra/test/message_tut.cpp
@@ -28,7 +28,7 @@
#include <tut/tut.hpp>
#include "linden_common.h"
#include "lltut.h"
-
+#include "llhttpconstants.h"
#include "llapr.h"
#include "llmessageconfig.h"
#include "llsdserialize.h"
diff --git a/indra/viewer_components/login/CMakeLists.txt b/indra/viewer_components/login/CMakeLists.txt
index c152f7c0a6..3bedeb7292 100755
--- a/indra/viewer_components/login/CMakeLists.txt
+++ b/indra/viewer_components/login/CMakeLists.txt
@@ -10,6 +10,8 @@ include(LLCommon)
include(LLMath)
include(LLXML)
include(Boost)
+include(LLCoreHttp)
+include(LLMessage)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
@@ -42,12 +44,14 @@ add_library(lllogin
)
target_link_libraries(lllogin
+ ${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLCOMMON_LIBRARIES}
${LLMATH_LIBRARIES}
${LLXML_LIBRARIES}
- ${BOOST_CONTEXT_LIBRARY}
${BOOST_THREAD_LIBRARY}
${BOOST_COROUTINE_LIBRARY}
+ ${BOOST_CONTEXT_LIBRARY}
${BOOST_SYSTEM_LIBRARY}
)
@@ -58,7 +62,7 @@ if(LL_TESTS)
set_source_files_properties(
lllogin.cpp
PROPERTIES
- LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_COROUTINE_LIBRARY};${BOOST_CONTEXT_LIBRARY};${BOOST_THREAD_LIBRARY};${BOOST_SYSTEM_LIBRARY}"
+ LL_TEST_ADDITIONAL_LIBRARIES "${LLMESSAGE_LIBRARIES};${LLCOREHTTP_LIBRARIES};${LLCOMMON_LIBRARIES};${BOOST_COROUTINE_LIBRARY};${BOOST_CONTEXT_LIBRARY};${BOOST_THREAD_LIBRARY};${BOOST_SYSTEM_LIBRARY}"
)
LL_ADD_PROJECT_UNIT_TESTS(lllogin "${lllogin_TEST_SOURCE_FILES}")
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index b8408a6fb4..53d4acc9e0 100755
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -107,9 +107,8 @@ private:
}
// In a coroutine's top-level function args, do NOT NOT NOT accept
- // references (const or otherwise) to anything but the self argument! Pass
- // by value only!
- void login_(LLCoros::self& self, std::string uri, LLSD credentials);
+ // references (const or otherwise) to anything! Pass by value only!
+ void loginCoro(std::string uri, LLSD credentials);
LLEventStream mPump;
LLSD mAuthResponse, mValidAuthResponse;
@@ -123,11 +122,11 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
// its first wait; at that point, return here.
std::string coroname =
LLCoros::instance().launch("LLLogin::Impl::login_",
- boost::bind(&Impl::login_, this, _1, uri, login_params));
+ boost::bind(&Impl::loginCoro, this, uri, login_params));
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
-void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_params)
+void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{
try
{
@@ -137,50 +136,13 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
//{
// printable_params["params"]["passwd"] = "*******";
//}
- LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
+ LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName()
<< " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;
// Arriving in SRVRequest state
LLEventStream replyPump("SRVreply", true);
// Should be an array of one or more uri strings.
- LLSD rewrittenURIs;
- {
- LLEventTimeout filter(replyPump);
- sendProgressEvent("offline", "srvrequest");
-
- // Request SRV record.
- LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
-
- // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
- F32 seconds_to_timeout = 5.0f;
- if(login_params.has("cfg_srv_timeout"))
- {
- seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
- }
-
- // If the SRV request times out (e.g. EXT-3934), simulate response: an
- // array containing our original URI.
- LLSD fakeResponse(LLSD::emptyArray());
- fakeResponse.append(uri);
- filter.eventAfter(seconds_to_timeout, fakeResponse);
-
- std::string srv_pump_name = "LLAres";
- if(login_params.has("cfg_srv_pump"))
- {
- srv_pump_name = login_params["cfg_srv_pump"].asString();
- }
-
- // Make request
- LLSD request;
- request["op"] = "rewriteURI";
- request["uri"] = uri;
- request["reply"] = replyPump.getName();
- rewrittenURIs = postAndWait(self, request, srv_pump_name, filter);
- // EXP-772: If rewrittenURIs fail, try original URI as a fallback.
- rewrittenURIs.append(uri);
- } // we no longer need the filter
-
LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
// EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used
// to share them -- but the EXT-3934 fix made it possible for an abandoned
@@ -191,107 +153,103 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
// Because of possible redirect responses, we may make more than one
// attempt per rewrittenURIs entry.
LLSD::Integer attempts = 0;
- for (LLSD::array_const_iterator urit(rewrittenURIs.beginArray()),
- urend(rewrittenURIs.endArray());
- urit != urend; ++urit)
+
+ LLSD request(login_params);
+ request["reply"] = loginReplyPump.getName();
+ request["uri"] = uri;
+ std::string status;
+
+ // Loop back to here if login attempt redirects to a different
+ // request["uri"]
+ for (;;)
{
- LLSD request(login_params);
- request["reply"] = loginReplyPump.getName();
- request["uri"] = *urit;
- std::string status;
-
- // Loop back to here if login attempt redirects to a different
- // request["uri"]
- for (;;)
+ ++attempts;
+ LLSD progress_data;
+ progress_data["attempt"] = attempts;
+ progress_data["request"] = request;
+ if(progress_data["request"].has("params")
+ && progress_data["request"]["params"].has("passwd"))
+ {
+ progress_data["request"]["params"]["passwd"] = "*******";
+ }
+ sendProgressEvent("offline", "authenticating", progress_data);
+
+ // We expect zero or more "Downloading" status events, followed by
+ // exactly one event with some other status. Use postAndSuspend() the
+ // first time, because -- at least in unit-test land -- it's
+ // possible for the reply to arrive before the post() call
+ // returns. Subsequent responses, of course, must be awaited
+ // without posting again.
+ for (mAuthResponse = validateResponse(loginReplyPump.getName(),
+ llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply"));
+ mAuthResponse["status"].asString() == "Downloading";
+ mAuthResponse = validateResponse(loginReplyPump.getName(),
+ llcoro::suspendUntilEventOn(loginReplyPump)))
{
- ++attempts;
- LLSD progress_data;
- progress_data["attempt"] = attempts;
- progress_data["request"] = request;
- if(progress_data["request"].has("params")
- && progress_data["request"]["params"].has("passwd"))
- {
- progress_data["request"]["params"]["passwd"] = "*******";
- }
- sendProgressEvent("offline", "authenticating", progress_data);
-
- // We expect zero or more "Downloading" status events, followed by
- // exactly one event with some other status. Use postAndWait() the
- // first time, because -- at least in unit-test land -- it's
- // possible for the reply to arrive before the post() call
- // returns. Subsequent responses, of course, must be awaited
- // without posting again.
- for (mAuthResponse = validateResponse(loginReplyPump.getName(),
- postAndWait(self, request, xmlrpcPump, loginReplyPump, "reply"));
- mAuthResponse["status"].asString() == "Downloading";
- mAuthResponse = validateResponse(loginReplyPump.getName(),
- waitForEventOn(self, loginReplyPump)))
- {
- // Still Downloading -- send progress update.
- sendProgressEvent("offline", "downloading");
- }
+ // Still Downloading -- send progress update.
+ sendProgressEvent("offline", "downloading");
+ }
- LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
- status = mAuthResponse["status"].asString();
-
- // Okay, we've received our final status event for this
- // request. Unless we got a redirect response, break the retry
- // loop for the current rewrittenURIs entry.
- if (!(status == "Complete" &&
- mAuthResponse["responses"]["login"].asString() == "indeterminate"))
- {
- break;
- }
-
- sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
-
- // Here the login service at the current URI is redirecting us
- // to some other URI ("indeterminate" -- why not "redirect"?).
- // The response should contain another uri to try, with its
- // own auth method.
- request["uri"] = mAuthResponse["responses"]["next_url"].asString();
- request["method"] = mAuthResponse["responses"]["next_method"].asString();
- } // loop back to try the redirected URI
-
- // Here we're done with redirects for the current rewrittenURIs
- // entry.
- if (status == "Complete")
+ LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
+ status = mAuthResponse["status"].asString();
+
+ // Okay, we've received our final status event for this
+ // request. Unless we got a redirect response, break the retry
+ // loop for the current rewrittenURIs entry.
+ if (!(status == "Complete" &&
+ mAuthResponse["responses"]["login"].asString() == "indeterminate"))
{
- // StatusComplete does not imply auth success. Check the
- // actual outcome of the request. We've already handled the
- // "indeterminate" case in the loop above.
- if (mAuthResponse["responses"]["login"].asString() == "true")
- {
- sendProgressEvent("online", "connect", mAuthResponse["responses"]);
- }
- else
- {
- sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
- }
- return; // Done!
+ break;
}
- /* Sometimes we end with "Started" here. Slightly slow server?
- * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
- */
- if( status == "Started")
- {
- LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
- continue;
- }
+ sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
- // If we don't recognize status at all, trouble
- if (! (status == "CURLError"
- || status == "XMLRPCError"
- || status == "OtherError"))
+ // Here the login service at the current URI is redirecting us
+ // to some other URI ("indeterminate" -- why not "redirect"?).
+ // The response should contain another uri to try, with its
+ // own auth method.
+ request["uri"] = mAuthResponse["responses"]["next_url"].asString();
+ request["method"] = mAuthResponse["responses"]["next_method"].asString();
+ } // loop back to try the redirected URI
+
+ // Here we're done with redirects for the current rewrittenURIs
+ // entry.
+ if (status == "Complete")
+ {
+ // StatusComplete does not imply auth success. Check the
+ // actual outcome of the request. We've already handled the
+ // "indeterminate" case in the loop above.
+ if (mAuthResponse["responses"]["login"].asString() == "true")
+ {
+ sendProgressEvent("online", "connect", mAuthResponse["responses"]);
+ }
+ else
{
- LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
- << mAuthResponse << LL_ENDL;
- return;
+ sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
}
+ return; // Done!
+ }
- // Here status IS one of the errors tested above.
- } // Retry if there are any more rewrittenURIs.
+// /* Sometimes we end with "Started" here. Slightly slow server?
+// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
+// */
+// if( status == "Started")
+// {
+// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
+// continue;
+// }
+
+ // If we don't recognize status at all, trouble
+ if (! (status == "CURLError"
+ || status == "XMLRPCError"
+ || status == "OtherError"))
+ {
+ LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
+ << mAuthResponse << LL_ENDL;
+ return;
+ }
+
+ // Here status IS one of the errors tested above.
// Here we got through all the rewrittenURIs without succeeding. Tell
// caller this didn't work out so well. Of course, the only failure data
@@ -352,29 +310,8 @@ LLEventPump& LLLogin::getEventPump()
// The list associates to event with the original idle_startup() 'STATE'.
-// Rewrite URIs
- // State_LOGIN_AUTH_INIT
-// Given a vector of login uris (usually just one), perform a dns lookup for the
-// SRV record from each URI. I think this is used to distribute login requests to
-// a single URI to multiple hosts.
-// This is currently a synchronous action. (See LLSRV::rewriteURI() implementation)
-// On dns lookup error the output uris == the input uris.
-//
-// Input: A vector of login uris
-// Output: A vector of login uris
-//
-// Code:
-// std::vector<std::string> uris;
-// LLViewerLogin::getInstance()->getLoginURIs(uris);
-// std::vector<std::string>::const_iterator iter, end;
-// for (iter = uris.begin(), end = uris.end(); iter != end; ++iter)
-// {
-// std::vector<std::string> rewritten;
-// rewritten = LLSRV::rewriteURI(*iter);
-// sAuthUris.insert(sAuthUris.end(),
-// rewritten.begin(), rewritten.end());
-// }
-// sAuthUriNum = 0;
+// Setup login
+// State_LOGIN_AUTH_INIT
// Authenticate
// STATE_LOGIN_AUTHENTICATE
diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp
index 58bf371a04..e96c495446 100755
--- a/indra/viewer_components/login/tests/lllogin_test.cpp
+++ b/indra/viewer_components/login/tests/lllogin_test.cpp
@@ -96,61 +96,6 @@ public:
}
};
-class LLAresListener: public LLEventTrackable
-{
- std::string mName;
- LLSD mEvent;
- bool mImmediateResponse;
- bool mMultipleURIResponse;
- Debug mDebug;
-
-public:
- LLAresListener(const std::string& name,
- bool i = false,
- bool m = false
- ) :
- mName(name),
- mImmediateResponse(i),
- mMultipleURIResponse(m),
- mDebug(stringize(*this))
- {}
-
- bool handle_event(const LLSD& event)
- {
- mDebug(STRINGIZE("LLAresListener called!: " << event));
- mEvent = event;
- if(mImmediateResponse)
- {
- sendReply();
- }
- return false;
- }
-
- void sendReply()
- {
- if(mEvent["op"].asString() == "rewriteURI")
- {
- LLSD result;
- if(mMultipleURIResponse)
- {
- result.append(LLSD("login.foo.com"));
- }
- result.append(mEvent["uri"]);
- LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
- }
- }
-
- LLBoundListener listenTo(LLEventPump& pump)
- {
- return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
- }
-
- friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
- {
- return out << "LLAresListener(" << listener.mName << ')';
- }
-};
-
class LLXMLRPCListener: public LLEventTrackable
{
std::string mName;
@@ -232,16 +177,12 @@ namespace tut
void llviewerlogin_object::test<1>()
{
DEBUG;
- // Testing login with immediate responses from Ares and XMLPRC
- // The response from both requests will come before the post request exits.
+ // Testing login with an immediate response from XMLPRC
+ // The response will come before the post request exits.
// This tests an edge case of the login state handling.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
bool respond_immediately = true;
- // Have 'dummy ares' respond immediately.
- LLAresListener dummyLLAres("dummy_llares", respond_immediately);
- dummyLLAres.listenTo(llaresPump);
// Have dummy XMLRPC respond immediately.
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
@@ -266,109 +207,12 @@ namespace tut
void llviewerlogin_object::test<2>()
{
DEBUG;
- // Tests a successful login in with delayed responses.
- // Also includes 'failure' that cause the login module
- // to re-attempt connection, once from a basic failure
- // and once from the 'indeterminate' response.
-
- set_test_name("LLLogin multiple srv uris w/ success");
-
- // Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
-
- bool respond_immediately = false;
- bool multiple_addresses = true;
- LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
- dummyLLAres.listenTo(llaresPump);
-
- LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
- dummyXMLRPC.listenTo(xmlrpcPump);
-
- LLLogin login;
-
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
-
- LLSD credentials;
- credentials["first"] = "foo";
- credentials["last"] = "bar";
- credentials["passwd"] = "secret";
-
- login.connect("login.bar.com", credentials);
-
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
-
- dummyLLAres.sendReply();
-
- // Test Authenticating State prior to first response.
- ensure_equals("Auth state 1", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
- ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com");
-
- // First send emulated LLXMLRPCListener failure,
- // this should return login to the authenticating step and increase the attempt
- // count.
- LLSD data;
- data["status"] = "OtherError";
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
-
- ensure_equals("Fail back to authenticate 1", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2);
- ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
-
- // Now send the 'indeterminate' response.
- data.clear();
- data["status"] = "Complete"; // StatusComplete
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "indeterminate";
- data["responses"]["next_url"] = "login.indeterminate.com";
- data["responses"]["next_method"] = "test_login_method";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
-
- ensure_equals("Fail back to authenticate 2", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
- ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");
- ensure_equals("Method 3", listener.lastEvent()["data"]["request"]["method"].asString(), "test_login_method");
-
- // Finally let the auth succeed.
- data.clear();
- data["status"] = "Complete"; // StatusComplete
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "true";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
-
- ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");
-
- login.disconnect();
-
- ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
- }
-
- template<> template<>
- void llviewerlogin_object::test<3>()
- {
- DEBUG;
// Test completed response, that fails to login.
set_test_name("LLLogin valid response, failure (eg. bad credentials)");
// Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
-
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
dummyXMLRPC.listenTo(xmlrpcPump);
@@ -383,10 +227,6 @@ namespace tut
login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
-
- dummyLLAres.sendReply();
-
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
// Send the failed auth request reponse
@@ -403,19 +243,15 @@ namespace tut
}
template<> template<>
- void llviewerlogin_object::test<4>()
+ void llviewerlogin_object::test<3>()
{
DEBUG;
// Test incomplete response, that end the attempt.
set_test_name("LLLogin valid response, failure (eg. bad credentials)");
// Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
-
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
dummyXMLRPC.listenTo(xmlrpcPump);
@@ -430,10 +266,6 @@ namespace tut
login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
-
- dummyLLAres.sendReply();
-
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
// Send the failed auth request reponse
@@ -449,17 +281,13 @@ namespace tut
}
template<> template<>
- void llviewerlogin_object::test<5>()
+ void llviewerlogin_object::test<4>()
{
DEBUG;
// Test SRV request timeout.
set_test_name("LLLogin SRV timeout testing");
// Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
-
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
LLLogin login;
LoginListener listener("test_ear");
@@ -473,26 +301,15 @@ namespace tut
login.connect("login.bar.com", credentials);
- ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest");
-
// Get the mainloop eventpump, which needs a pinging in order to drive the
// SRV timeout.
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
LLSD frame_event;
mainloop.post(frame_event);
- // In this state we have NOT sent a reply from LLAresListener -- in
- // fact there's no such object. Nonetheless, we expect the timeout to
- // have stepped the login module forward to try to authenticate with
- // the original URI.
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
ensure_equals("Attempt", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
ensure_equals("URI", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
- // EXT-4193: if the SRV reply isn't lost but merely late, and if it
- // arrives just at the moment we're expecting the XMLRPC reply, the
- // original code got confused and crashed. Drive that case here. We
- // observe that without the fix, this call DOES repro.
- dummyLLAres.sendReply();
}
}
diff --git a/indra/viewer_components/updater/CMakeLists.txt b/indra/viewer_components/updater/CMakeLists.txt
index 61fd4220e0..48c065c2ed 100755
--- a/indra/viewer_components/updater/CMakeLists.txt
+++ b/indra/viewer_components/updater/CMakeLists.txt
@@ -6,15 +6,18 @@ include(00-Common)
if(LL_TESTS)
include(LLAddBuildTest)
endif(LL_TESTS)
+include(Boost)
include(CMakeCopyIfDifferent)
include(CURL)
include(LLCommon)
+include(LLCoreHttp)
include(LLMessage)
include(LLPlugin)
include(LLVFS)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLMESSAGE_INCLUDE_DIRS}
${LLPLUGIN_INCLUDE_DIRS}
${LLVFS_INCLUDE_DIRS}
@@ -60,6 +63,7 @@ add_library(llupdaterservice
target_link_libraries(llupdaterservice
${LLCOMMON_LIBRARIES}
${LLMESSAGE_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLPLUGIN_LIBRARIES}
${LLVFS_LIBRARIES}
)
@@ -69,14 +73,16 @@ if(LL_TESTS)
llupdaterservice.cpp
)
+
+set_source_files_properties(
+ llupdaterservice.cpp
+ PROPERTIES
+ LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}"
# *NOTE:Mani - I was trying to use the preprocessor seam to mock out
-# llifstream (and other) llcommon classes. I didn't work
+# llifstream (and other) llcommon classes. It didn't work
# because of the windows declspec(dllimport)attribute.
-#set_source_files_properties(
-# llupdaterservice.cpp
-# PROPERTIES
-# LL_TEST_ADDITIONAL_CFLAGS "-Dllifstream=llus_mock_llifstream"
-# )
+# LL_TEST_ADDITIONAL_CFLAGS "-Dllifstream=llus_mock_llifstream"
+ )
LL_ADD_PROJECT_UNIT_TESTS(llupdaterservice "${llupdater_service_TEST_SOURCE_FILES}")
endif(LL_TESTS)
diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
index 8da4f88905..1bb5e95740 100755
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -26,10 +26,10 @@
#include "linden_common.h"
#include <stdexcept>
#include <boost/format.hpp>
-#include "llhttpclient.h"
#include "llsd.h"
#include "llupdatechecker.h"
#include "lluri.h"
+#include "llcorehttputil.h"
#if LL_DARWIN
#include <CoreServices/CoreServices.h>
#endif
@@ -53,15 +53,12 @@ public:
// LLUpdateChecker
//-----------------------------------------------------------------------------
-
-
LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client):
mImplementation(new LLUpdateChecker::Implementation(client))
{
; // No op.
}
-
void LLUpdateChecker::checkVersion(std::string const & urlBase,
std::string const & channel,
std::string const & version,
@@ -74,11 +71,8 @@ void LLUpdateChecker::checkVersion(std::string const & urlBase,
}
-
// LLUpdateChecker::Implementation
//-----------------------------------------------------------------------------
-
-
const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.1";
@@ -121,57 +115,58 @@ void LLUpdateChecker::Implementation::checkVersion(std::string const & urlBase,
std::string checkUrl = buildUrl(urlBase, channel, version, platform, platform_version, uniqueid, willing_to_test);
LL_INFOS("UpdaterService") << "checking for updates at " << checkUrl << LL_ENDL;
-
- mHttpClient.get(checkUrl, this);
- }
- else
- {
- LL_WARNS("UpdaterService") << "attempting to restart a check when one is in progress; ignored" << LL_ENDL;
- }
-}
-void LLUpdateChecker::Implementation::httpCompleted()
-{
- mInProgress = false;
+ LLCoros::instance().launch("LLUpdateChecker::Implementation::checkVersionCoro",
+ boost::bind(&Implementation::checkVersionCoro, this, checkUrl));
- S32 status = getStatus();
- const LLSD& content = getContent();
- const std::string& reason = getReason();
- if(status != 200)
- {
- std::string server_error;
- if ( content.has("error_code") )
- {
- server_error += content["error_code"].asString();
- }
- if ( content.has("error_text") )
- {
- server_error += server_error.empty() ? "" : ": ";
- server_error += content["error_text"].asString();
- }
-
- LL_WARNS("UpdaterService") << "response error " << status
- << " " << reason
- << " (" << server_error << ")"
- << LL_ENDL;
- mClient.error(reason);
}
else
{
- mClient.response(content);
+ LL_WARNS("UpdaterService") << "attempting to restart a check when one is in progress; ignored" << LL_ENDL;
}
}
-
-void LLUpdateChecker::Implementation::httpFailure()
+void LLUpdateChecker::Implementation::checkVersionCoro(std::string url)
{
- const std::string& reason = getReason();
- mInProgress = false;
- LL_WARNS("UpdaterService") << "update check failed; " << reason << LL_ENDL;
- mClient.error(reason);
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("checkVersionCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+
+ LL_INFOS("checkVersionCoro") << "Getting update information from " << url << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ mInProgress = false;
+
+ if (status != LLCore::HttpStatus(HTTP_OK))
+ {
+ std::string server_error;
+ if (result.has("error_code"))
+ {
+ server_error += result["error_code"].asString();
+ }
+ if (result.has("error_text"))
+ {
+ server_error += server_error.empty() ? "" : ": ";
+ server_error += result["error_text"].asString();
+ }
+
+ LL_WARNS("UpdaterService") << "response error " << status.getStatus()
+ << " " << status.toString()
+ << " (" << server_error << ")"
+ << LL_ENDL;
+ mClient.error(status.toString());
+ return;
+ }
+
+ result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
+ mClient.response(result);
}
-
std::string LLUpdateChecker::Implementation::buildUrl(std::string const & urlBase,
std::string const & channel,
std::string const & version,
diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h
index 3163a6d53c..d10ea4cf42 100755
--- a/indra/viewer_components/updater/llupdatechecker.h
+++ b/indra/viewer_components/updater/llupdatechecker.h
@@ -30,61 +30,27 @@
#include <boost/shared_ptr.hpp>
#include "llmd5.h"
-#include "llhttpclient.h"
+#include "lleventcoro.h"
+#include "llcoros.h"
//
// Implements asynchronous checking for updates.
//
class LLUpdateChecker {
public:
- class Client;
- class Implementation: public LLHTTPClient::Responder
- {
- public:
- Implementation(Client & client);
- ~Implementation();
- void checkVersion(std::string const & urlBase,
- std::string const & channel,
- std::string const & version,
- std::string const & platform,
- std::string const & platform_version,
- unsigned char uniqueid[MD5HEX_STR_SIZE],
- bool willing_to_test
- );
-
- protected:
- // Responder:
- virtual void httpCompleted();
- virtual void httpFailure();
-
- private:
- static const char * sLegacyProtocolVersion;
- static const char * sProtocolVersion;
- const char* mProtocol;
-
- Client & mClient;
- LLHTTPClient mHttpClient;
- bool mInProgress;
- std::string mVersion;
- std::string mUrlBase;
- std::string mChannel;
- std::string mPlatform;
- std::string mPlatformVersion;
- unsigned char mUniqueId[MD5HEX_STR_SIZE];
- bool mWillingToTest;
-
- std::string buildUrl(std::string const & urlBase,
- std::string const & channel,
- std::string const & version,
- std::string const & platform,
- std::string const & platform_version,
- unsigned char uniqueid[MD5HEX_STR_SIZE],
- bool willing_to_test);
-
- LOG_CLASS(LLUpdateChecker::Implementation);
- };
+ //
+ // The client interface implemented by a requestor checking for an update.
+ //
+ class Client
+ {
+ public:
+ // An error occurred while checking for an update.
+ virtual void error(std::string const & message) = 0;
+
+ // A successful response was received from the viewer version manager
+ virtual void response(LLSD const & content) = 0;
+ };
-
// An exception that may be raised on check errors.
class CheckError;
@@ -100,25 +66,54 @@ public:
bool willing_to_test);
private:
- LLPointer<Implementation> mImplementation;
-};
+ class Implementation
+ {
+ public:
+ typedef boost::shared_ptr<Implementation> ptr_t;
+ Implementation(Client & client);
+ ~Implementation();
+ void checkVersion(std::string const & urlBase,
+ std::string const & channel,
+ std::string const & version,
+ std::string const & platform,
+ std::string const & platform_version,
+ unsigned char uniqueid[MD5HEX_STR_SIZE],
+ bool willing_to_test
+ );
-class LLURI; // From lluri.h
+ private:
+ static const char * sLegacyProtocolVersion;
+ static const char * sProtocolVersion;
+ const char* mProtocol;
-//
-// The client interface implemented by a requestor checking for an update.
-//
-class LLUpdateChecker::Client
-{
-public:
- // An error occurred while checking for an update.
- virtual void error(std::string const & message) = 0;
-
- // A successful response was received from the viewer version manager
- virtual void response(LLSD const & content) = 0;
-};
+ Client & mClient;
+ bool mInProgress;
+ std::string mVersion;
+ std::string mUrlBase;
+ std::string mChannel;
+ std::string mPlatform;
+ std::string mPlatformVersion;
+ unsigned char mUniqueId[MD5HEX_STR_SIZE];
+ bool mWillingToTest;
+
+ std::string buildUrl(std::string const & urlBase,
+ std::string const & channel,
+ std::string const & version,
+ std::string const & platform,
+ std::string const & platform_version,
+ unsigned char uniqueid[MD5HEX_STR_SIZE],
+ bool willing_to_test);
+
+ void checkVersionCoro(std::string url);
+ LOG_CLASS(LLUpdateChecker::Implementation);
+ };
+
+
+ Implementation::ptr_t mImplementation;
+ //LLPointer<Implementation> mImplementation;
+};
#endif
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
index f868e5cc2c..53c729469b 100755
--- a/indra/viewer_components/updater/llupdatedownloader.cpp
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -26,7 +26,7 @@
#include "linden_common.h"
#include "llupdatedownloader.h"
-
+#include "httpcommon.h"
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
@@ -39,7 +39,6 @@
#include "llsdserialize.h"
#include "llthread.h"
#include "llupdaterservice.h"
-#include "llcurl.h"
class LLUpdateDownloader::Implementation:
public LLThread
@@ -65,7 +64,7 @@ private:
curl_off_t mBandwidthLimit;
bool mCancelled;
LLUpdateDownloader::Client & mClient;
- CURL * mCurl;
+ LLCore::LLHttp::CURL_ptr mCurl;
LLSD mDownloadData;
llofstream mDownloadStream;
unsigned char mDownloadPercent;
@@ -192,7 +191,7 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client &
mBandwidthLimit(0),
mCancelled(false),
mClient(client),
- mCurl(0),
+ mCurl(),
mDownloadPercent(0),
mHeaderList(0)
{
@@ -212,10 +211,7 @@ LLUpdateDownloader::Implementation::~Implementation()
{
; // No op.
}
- if(mCurl)
- {
- LLCurl::deleteEasyHandle(mCurl);
- }
+ mCurl.reset();
}
@@ -331,9 +327,9 @@ void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond)
{
if((mBandwidthLimit != bytesPerSecond) && isDownloading() && !mDownloadData["required"].asBoolean())
{
- llassert(mCurl != 0);
+ llassert(static_cast<bool>(mCurl));
mBandwidthLimit = bytesPerSecond;
- CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
+ CURLcode code = curl_easy_setopt(mCurl.get(), CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
if(code != CURLE_OK)
{
LL_WARNS("UpdaterService") << "unable to change dowload bandwidth" << LL_ENDL;
@@ -416,7 +412,7 @@ int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double b
void LLUpdateDownloader::Implementation::run(void)
{
- CURLcode code = curl_easy_perform(mCurl);
+ CURLcode code = curl_easy_perform(mCurl.get());
mDownloadStream.close();
if(code == CURLE_OK)
{
@@ -460,36 +456,36 @@ void LLUpdateDownloader::Implementation::run(void)
void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)
{
- if(mCurl == 0)
+ if(!mCurl)
{
- mCurl = LLCurl::newEasyHandle();
+ mCurl = LLCore::LLHttp::createEasyHandle();
}
else
{
- curl_easy_reset(mCurl);
+ curl_easy_reset(mCurl.get());
}
- if(mCurl == 0)
+ if(!mCurl)
{
throw DownloadError("failed to initialize curl");
}
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOSIGNAL, true));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_FOLLOWLOCATION, true));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_WRITEFUNCTION, &write_function));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_WRITEDATA, this));
if(processHeader)
{
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this));
- }
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this));
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HEADERFUNCTION, &header_function));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HEADERDATA, this));
+ }
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPGET, true));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_URL, url.c_str()));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_PROGRESSFUNCTION, &progress_callback));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_PROGRESSDATA, this));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOPROGRESS, false));
// if it's a required update set the bandwidth limit to 0 (unlimited)
curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit;
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_MAX_RECV_SPEED_LARGE, limit));
mDownloadPercent = 0;
}
@@ -511,7 +507,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
{
throw DownloadError("cannot add Range header");
}
- throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList));
+ throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPHEADER, mHeaderList));
mDownloadStream.open(mDownloadData["path"].asString().c_str(),
std::ios_base::out | std::ios_base::binary | std::ios_base::app);
diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt
index c6070020db..144d037a31 100755
--- a/indra/win_crash_logger/CMakeLists.txt
+++ b/indra/win_crash_logger/CMakeLists.txt
@@ -4,6 +4,7 @@ project(win_crash_logger)
include(00-Common)
include(LLCommon)
+include(LLCoreHttp)
include(LLCrashLogger)
include(LLMath)
include(LLMessage)
@@ -13,8 +14,10 @@ include(LLXML)
include(Linking)
include(LLSharedLibs)
include(GoogleBreakpad)
+include(Boost)
include_directories(
+ ${LLCOREHTTP_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLCRASHLOGGER_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
@@ -77,7 +80,10 @@ target_link_libraries(windows-crash-logger
${LLXML_LIBRARIES}
${LLMESSAGE_LIBRARIES}
${LLMATH_LIBRARIES}
+ ${LLCOREHTTP_LIBRARIES}
${LLCOMMON_LIBRARIES}
+ ${BOOST_CONTEXT_LIBRARY}
+ ${BOOST_COROUTINE_LIBRARY}
${WINDOWS_LIBRARIES}
${DXGUID_LIBRARY}
${GOOGLE_PERFTOOLS_LIBRARIES}