From cd93aba002bb3248e3e099d80ce68242531035c0 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 25 Jul 2012 03:27:02 +0200 Subject: [PATCH 01/64] Created aistatemachine library and moved files. --- indra/CMakeLists.txt | 1 + indra/aistatemachine/CMakeLists.txt | 46 +++++++++++++++++++ .../{llmessage => aistatemachine}/aicurl.cpp | 0 indra/{llmessage => aistatemachine}/aicurl.h | 0 .../aicurleasyrequeststatemachine.cpp | 0 .../aicurleasyrequeststatemachine.h | 0 .../aicurlprivate.h | 0 .../aicurlthread.cpp | 0 .../aicurlthread.h | 0 .../aistatemachine.cpp | 0 .../aistatemachine.h | 0 .../aitimer.cpp | 0 .../statemachine => aistatemachine}/aitimer.h | 0 indra/cmake/AIStateMachine.cmake | 4 +- indra/cmake/LLMessage.cmake | 4 +- indra/cmake/StateMachine.cmake | 4 ++ indra/llmessage/CMakeLists.txt | 9 ++-- .../{newview => llmessage}/llcurlrequest.cpp | 2 +- indra/{newview => llmessage}/llcurlrequest.h | 0 indra/newview/CMakeLists.txt | 7 ++- indra/newview/llviewercontrol.cpp | 2 +- indra/newview/llxmlrpctransaction.cpp | 2 +- indra/newview/statemachine/CMakeLists.txt | 6 --- 23 files changed, 66 insertions(+), 21 deletions(-) create mode 100644 indra/aistatemachine/CMakeLists.txt rename indra/{llmessage => aistatemachine}/aicurl.cpp (100%) rename indra/{llmessage => aistatemachine}/aicurl.h (100%) rename indra/{newview/statemachine => aistatemachine}/aicurleasyrequeststatemachine.cpp (100%) rename indra/{newview/statemachine => aistatemachine}/aicurleasyrequeststatemachine.h (100%) rename indra/{llmessage => aistatemachine}/aicurlprivate.h (100%) rename indra/{llmessage => aistatemachine}/aicurlthread.cpp (100%) rename indra/{llmessage => aistatemachine}/aicurlthread.h (100%) rename indra/{newview/statemachine => aistatemachine}/aistatemachine.cpp (100%) rename indra/{newview/statemachine => aistatemachine}/aistatemachine.h (100%) rename indra/{newview/statemachine => aistatemachine}/aitimer.cpp (100%) rename indra/{newview/statemachine => aistatemachine}/aitimer.h (100%) create mode 100644 indra/cmake/StateMachine.cmake rename indra/{newview => llmessage}/llcurlrequest.cpp (98%) rename indra/{newview => llmessage}/llcurlrequest.h (100%) diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index e81965cc6..0e7e1b472 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -46,6 +46,7 @@ endif(NOT STANDALONE) add_custom_target(prepare DEPENDS ${prepare_depends}) add_subdirectory(cmake) +add_subdirectory(${LIBS_OPEN_PREFIX}aistatemachine) add_subdirectory(${LIBS_OPEN_PREFIX}cwdebug) add_subdirectory(${LIBS_OPEN_PREFIX}llaudio) add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter) diff --git a/indra/aistatemachine/CMakeLists.txt b/indra/aistatemachine/CMakeLists.txt new file mode 100644 index 000000000..b8dc762a7 --- /dev/null +++ b/indra/aistatemachine/CMakeLists.txt @@ -0,0 +1,46 @@ +# -*- cmake -*- + +project(aistatemachine) + +include(00-Common) +include(LLCommon) +include(LLMessage) +include(LLMath) +include(LLXML) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ) + +set(aistatemachine_SOURCE_FILES + aistatemachine.cpp + aitimer.cpp + aicurl.cpp + aicurlthread.cpp + aicurleasyrequeststatemachine.cpp + ) + +set(aistatemachine_HEADER_FILES + CMakeLists.txt + + aistatemachine.h + aitimer.h + aicurlprivate.h + aicurl.h + aicurlthread.h + aicurleasyrequeststatemachine.h + ) + +set_source_files_properties(${aistatemachine_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND aistatemachine_SOURCE_FILES ${aistatemachine_HEADER_FILES}) + +add_library (aistatemachine ${aistatemachine_SOURCE_FILES}) +add_dependencies(aistatemachine prepare) + diff --git a/indra/llmessage/aicurl.cpp b/indra/aistatemachine/aicurl.cpp similarity index 100% rename from indra/llmessage/aicurl.cpp rename to indra/aistatemachine/aicurl.cpp diff --git a/indra/llmessage/aicurl.h b/indra/aistatemachine/aicurl.h similarity index 100% rename from indra/llmessage/aicurl.h rename to indra/aistatemachine/aicurl.h diff --git a/indra/newview/statemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp similarity index 100% rename from indra/newview/statemachine/aicurleasyrequeststatemachine.cpp rename to indra/aistatemachine/aicurleasyrequeststatemachine.cpp diff --git a/indra/newview/statemachine/aicurleasyrequeststatemachine.h b/indra/aistatemachine/aicurleasyrequeststatemachine.h similarity index 100% rename from indra/newview/statemachine/aicurleasyrequeststatemachine.h rename to indra/aistatemachine/aicurleasyrequeststatemachine.h diff --git a/indra/llmessage/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h similarity index 100% rename from indra/llmessage/aicurlprivate.h rename to indra/aistatemachine/aicurlprivate.h diff --git a/indra/llmessage/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp similarity index 100% rename from indra/llmessage/aicurlthread.cpp rename to indra/aistatemachine/aicurlthread.cpp diff --git a/indra/llmessage/aicurlthread.h b/indra/aistatemachine/aicurlthread.h similarity index 100% rename from indra/llmessage/aicurlthread.h rename to indra/aistatemachine/aicurlthread.h diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/aistatemachine/aistatemachine.cpp similarity index 100% rename from indra/newview/statemachine/aistatemachine.cpp rename to indra/aistatemachine/aistatemachine.cpp diff --git a/indra/newview/statemachine/aistatemachine.h b/indra/aistatemachine/aistatemachine.h similarity index 100% rename from indra/newview/statemachine/aistatemachine.h rename to indra/aistatemachine/aistatemachine.h diff --git a/indra/newview/statemachine/aitimer.cpp b/indra/aistatemachine/aitimer.cpp similarity index 100% rename from indra/newview/statemachine/aitimer.cpp rename to indra/aistatemachine/aitimer.cpp diff --git a/indra/newview/statemachine/aitimer.h b/indra/aistatemachine/aitimer.h similarity index 100% rename from indra/newview/statemachine/aitimer.h rename to indra/aistatemachine/aitimer.h diff --git a/indra/cmake/AIStateMachine.cmake b/indra/cmake/AIStateMachine.cmake index c1bda40c4..5a0aba0d7 100644 --- a/indra/cmake/AIStateMachine.cmake +++ b/indra/cmake/AIStateMachine.cmake @@ -1,4 +1,4 @@ # -*- cmake -*- -set(AISTATEMACHINE_INCLUDE_DIRS statemachine) -set(AISTATEMACHINE_LIBRARIES statemachine) +set(AISTATEMACHINE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/aistatemachine) +set(AISTATEMACHINE_LIBRARIES aistatemachine) diff --git a/indra/cmake/LLMessage.cmake b/indra/cmake/LLMessage.cmake index 0143d04fd..da2bbc43b 100644 --- a/indra/cmake/LLMessage.cmake +++ b/indra/cmake/LLMessage.cmake @@ -4,12 +4,14 @@ include(CARes) include(CURL) include(OpenSSL) include(XmlRpcEpi) +include(AIStateMachine) set(LLMESSAGE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llmessage ${CARES_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} + ${AISTATEMACHINE_INCLUDE_DIRS} ) -set(LLMESSAGE_LIBRARIES llmessage) +set(LLMESSAGE_LIBRARIES llmessage aistatemachine) diff --git a/indra/cmake/StateMachine.cmake b/indra/cmake/StateMachine.cmake new file mode 100644 index 000000000..8a478c647 --- /dev/null +++ b/indra/cmake/StateMachine.cmake @@ -0,0 +1,4 @@ +# -*- cmake -*- + +set(STATEMACHINE_INCLUDE_DIRS statemachine) +set(STATEMACHINE_LIBRARIES statemachine) diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index b2b8eb4ec..90eed3756 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -4,6 +4,7 @@ project(llmessage) include(00-Common) include(LLCommon) +include(AIStateMachine) include(LLMath) include(LLMessage) include(LLVFS) @@ -12,6 +13,7 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}) include_directories( ${LLCOMMON_INCLUDE_DIRS} + ${AISTATEMACHINE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} @@ -29,8 +31,7 @@ set(llmessage_SOURCE_FILES llchainio.cpp llcircuit.cpp llclassifiedflags.cpp - aicurl.cpp - aicurlthread.cpp + llcurlrequest.cpp lldatapacker.cpp lldispatcher.cpp llfiltersd2xmlrpc.cpp @@ -116,9 +117,7 @@ set(llmessage_HEADER_FILES llcircuit.h llclassifiedflags.h llcurl.h - aicurl.h - aicurlprivate.h - aicurlthread.h + llcurlrequest.h lldatapacker.h lldbstrings.h lldispatcher.h diff --git a/indra/newview/llcurlrequest.cpp b/indra/llmessage/llcurlrequest.cpp similarity index 98% rename from indra/newview/llcurlrequest.cpp rename to indra/llmessage/llcurlrequest.cpp index 75706af6d..89338dfce 100644 --- a/indra/newview/llcurlrequest.cpp +++ b/indra/llmessage/llcurlrequest.cpp @@ -41,7 +41,7 @@ #include "llsdserialize.h" #include "llcurlrequest.h" -#include "statemachine/aicurleasyrequeststatemachine.h" +#include "aicurleasyrequeststatemachine.h" //----------------------------------------------------------------------------- // class Request diff --git a/indra/newview/llcurlrequest.h b/indra/llmessage/llcurlrequest.h similarity index 100% rename from indra/newview/llcurlrequest.h rename to indra/llmessage/llcurlrequest.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 26e29533c..151568ca1 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -30,7 +30,7 @@ include(LLInventory) include(LLMath) include(LLMessage) include(LLPlugin) -include(AIStateMachine) +include(StateMachine) include(LLPrimitive) include(LLRender) include(LLUI) @@ -54,6 +54,7 @@ endif (WINDOWS) include_directories( ${CMAKE_SOURCE_DIR}/newview + ${STATEMACHINE_INCLUDE_DIRS} ${DBUSGLIB_INCLUDE_DIRS} ${HUNSPELL_INCLUDE_DIR} ${ELFIO_INCLUDE_DIR} @@ -152,7 +153,6 @@ set(viewer_SOURCE_FILES llconfirmationmanager.cpp llconsole.cpp llcontainerview.cpp - llcurlrequest.cpp llcurrencyuimanager.cpp llcylinder.cpp lldebugmessagebox.cpp @@ -650,7 +650,6 @@ set(viewer_HEADER_FILES llconfirmationmanager.h llconsole.h llcontainerview.h - llcurlrequest.h llcurrencyuimanager.h llcylinder.h lldebugmessagebox.h @@ -1541,7 +1540,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLINVENTORY_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLPLUGIN_LIBRARIES} - ${AISTATEMACHINE_LIBRARIES} + ${STATEMACHINE_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} ${LLRENDER_LIBRARIES} ${FREETYPE_LIBRARIES} diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 6440652ef..e6322efed 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -78,7 +78,7 @@ #include "llnetmap.h" #include "llrender.h" #include "llfloaterchat.h" -#include "statemachine/aistatemachine.h" +#include "aistatemachine.h" #include "aithreadsafe.h" #include "lldrawpoolbump.h" #include "emeraldboobutils.h" diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index b160e2c33..38c78e045 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -43,7 +43,7 @@ #include "llappviewer.h" #include "hippogridmanager.h" -#include "statemachine/aicurleasyrequeststatemachine.h" +#include "aicurleasyrequeststatemachine.h" #ifdef CWDEBUG #include diff --git a/indra/newview/statemachine/CMakeLists.txt b/indra/newview/statemachine/CMakeLists.txt index 08ecccecf..1100c7872 100644 --- a/indra/newview/statemachine/CMakeLists.txt +++ b/indra/newview/statemachine/CMakeLists.txt @@ -37,23 +37,17 @@ include_directories( ) set(statemachine_SOURCE_FILES - aistatemachine.cpp - aicurleasyrequeststatemachine.cpp aifilepicker.cpp aifetchinventoryfolder.cpp aievent.cpp - aitimer.cpp ) set(statemachine_HEADER_FILES CMakeLists.txt - aistatemachine.h - aicurleasyrequeststatemachine.h aifilepicker.h aidirpicker.h aifetchinventoryfolder.h aievent.h - aitimer.h ) set_source_files_properties(${statemachine_HEADER_FILES} From 3b7887a041f6e9987359609889f0f46ae0d22cf4 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 25 Jul 2012 03:53:51 +0200 Subject: [PATCH 02/64] Cleanup of some unnecessary dependencies. --- indra/llplugin/CMakeLists.txt | 7 ------- indra/llui/CMakeLists.txt | 2 -- indra/llwindow/CMakeLists.txt | 2 -- 3 files changed, 11 deletions(-) diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 231b10bfa..446028b0f 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -3,23 +3,16 @@ project(llplugin) include(00-Common) -include(CURL) include(LLCommon) -include(LLImage) include(LLMath) include(LLMessage) include(LLRender) -include(LLXML) -include(LLWindow) include_directories( ${LLCOMMON_INCLUDE_DIRS} - ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ${LLWINDOW_INCLUDE_DIRS} ${LLQTWEBKIT_INCLUDE_DIR} ) diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 92a54d021..3e7a62722 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -5,7 +5,6 @@ project(llui) include(00-Common) include(LLCommon) include(LLImage) -include(LLInventory) include(LLMath) include(LLMessage) include(LLRender) @@ -17,7 +16,6 @@ include(LLXUIXML) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} - ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index e5d61d180..12c778cd8 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -18,7 +18,6 @@ include(LLMath) include(LLRender) include(LLVFS) include(LLWindow) -include(LLXML) include(UI) include_directories( @@ -28,7 +27,6 @@ include_directories( ${LLRENDER_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} ) set(llwindow_SOURCE_FILES From 516f5a40d0c2810cc66655fec5c07443d841f665 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 25 Jul 2012 21:24:40 +0200 Subject: [PATCH 03/64] Change mainloop to no longer use gIdleCallbacks --- indra/aistatemachine/aistatemachine.cpp | 59 +++++++++++-------------- indra/aistatemachine/aistatemachine.h | 27 ++++++++++- indra/llcommon/aithreadsafe.h | 6 +-- indra/llcrashlogger/llcrashlogger.cpp | 1 + indra/newview/llappviewer.cpp | 11 +++++ 5 files changed, 66 insertions(+), 38 deletions(-) diff --git a/indra/aistatemachine/aistatemachine.cpp b/indra/aistatemachine/aistatemachine.cpp index 71a8ac47f..622eeb7f5 100644 --- a/indra/aistatemachine/aistatemachine.cpp +++ b/indra/aistatemachine/aistatemachine.cpp @@ -32,7 +32,6 @@ #include -#include "llcallbacklist.h" #include "llcontrol.h" #include "llfasttimer.h" #include "aithreadsafe.h" @@ -66,17 +65,11 @@ namespace { typedef std::vector active_statemachines_type; active_statemachines_type active_statemachines; - typedef std::vector continued_statemachines_type; - struct cscm_type - { - continued_statemachines_type continued_statemachines; - bool calling_mainloop; - }; - AIThreadSafeDC continued_statemachines_and_calling_mainloop; } // static AIThreadSafeSimpleDC AIStateMachine::sMaxCount; +AIThreadSafeDC AIStateMachine::sContinuedStateMachinesAndMainloopEnabled; void AIStateMachine::updateSettings(void) { @@ -221,24 +214,23 @@ void AIStateMachine::locked_cont(void) // If not_active is true then main-thread is not running this statemachine. // It might call cont() (or set_state()) but never locked_cont(), and will never // start actually running until we are done here and release the lock on - // continued_statemachines_and_calling_mainloop again. It is therefore safe + // sContinuedStateMachinesAndMainloopEnabled again. It is therefore safe // to release mSetStateLock here, with as advantage that if we're not the main- // thread and not_active is true, then the main-thread won't block when it has // a timer running that times out and calls set_state(). mSetStateLock.unlock(); if (not_active) { - AIWriteAccess cscm_w(continued_statemachines_and_calling_mainloop); + AIWriteAccess csme_w(sContinuedStateMachinesAndMainloopEnabled); // See above: it is not possible that mActive was changed since not_active // was set to true above. llassert_always(mActive == as_idle); Dout(dc::statemachine, "Adding " << (void*)this << " to continued_statemachines"); - cscm_w->continued_statemachines.push_back(this); - if (!cscm_w->calling_mainloop) + csme_w->continued_statemachines.push_back(this); + if (!csme_w->mainloop_enabled) { - Dout(dc::statemachine, "Adding AIStateMachine::mainloop to gIdleCallbacks"); - cscm_w->calling_mainloop = true; - gIdleCallbacks.addFunction(&AIStateMachine::mainloop); + Dout(dc::statemachine, "Activating AIStateMachine::mainloop."); + csme_w->mainloop_enabled = true; } mActive = as_queued; llassert_always(!mIdle); // It should never happen that the main thread calls idle(), while another thread calls cont() concurrently. @@ -499,11 +491,10 @@ void AIStateMachine::multiplex(U64 current_time) } //static -void AIStateMachine::add_continued_statemachines(void) +void AIStateMachine::add_continued_statemachines(AIReadAccess& csme_r) { - AIReadAccess cscm_r(continued_statemachines_and_calling_mainloop); bool nonempty = false; - for (continued_statemachines_type::const_iterator iter = cscm_r->continued_statemachines.begin(); iter != cscm_r->continued_statemachines.end(); ++iter) + for (continued_statemachines_type::const_iterator iter = csme_r->continued_statemachines.begin(); iter != csme_r->continued_statemachines.end(); ++iter) { nonempty = true; active_statemachines.push_back(QueueElement(*iter)); @@ -511,15 +502,12 @@ void AIStateMachine::add_continued_statemachines(void) (*iter)->mActive = as_active; } if (nonempty) - AIWriteAccess(cscm_r)->continued_statemachines.clear(); + AIWriteAccess(csme_r)->continued_statemachines.clear(); } -static LLFastTimer::DeclareTimer FTM_STATEMACHINE("State Machine"); // static -void AIStateMachine::mainloop(void*) +void AIStateMachine::dowork(void) { - LLFastTimer t(FTM_STATEMACHINE); - add_continued_statemachines(); llassert(!active_statemachines.empty()); // Run one or more state machines. U64 total_clocks = 0; @@ -590,12 +578,11 @@ void AIStateMachine::mainloop(void*) if (active_statemachines.empty()) { // If this was the last state machine, remove mainloop from the IdleCallbacks. - AIReadAccess cscm_r(continued_statemachines_and_calling_mainloop); - if (cscm_r->continued_statemachines.empty() && cscm_r->calling_mainloop) + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled, true); + if (csme_r->continued_statemachines.empty() && csme_r->mainloop_enabled) { - Dout(dc::statemachine, "Removing AIStateMachine::mainloop from gIdleCallbacks"); - AIWriteAccess(cscm_r)->calling_mainloop = false; - gIdleCallbacks.deleteFunction(&AIStateMachine::mainloop); + Dout(dc::statemachine, "Deactivating AIStateMachine::mainloop: no active state machines left."); + AIWriteAccess(csme_r)->mainloop_enabled = false; } } } @@ -604,7 +591,10 @@ void AIStateMachine::mainloop(void*) void AIStateMachine::flush(void) { DoutEntering(dc::curl, "AIStateMachine::flush(void)"); - add_continued_statemachines(); + { + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled); + add_continued_statemachines(csme_r); + } // Abort all state machines. for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter) { @@ -618,15 +608,18 @@ void AIStateMachine::flush(void) for(;;) { { - AIReadAccess cscm_r(continued_statemachines_and_calling_mainloop); - if (!cscm_r->calling_mainloop) + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled); + if (!csme_r->mainloop_enabled) break; } - mainloop(NULL); + mainloop(); } if (batch == 1) break; - add_continued_statemachines(); + { + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled); + add_continued_statemachines(csme_r); + } // Kill all state machines. for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter) { diff --git a/indra/aistatemachine/aistatemachine.h b/indra/aistatemachine/aistatemachine.h index 13da6fd3d..abdd46e31 100644 --- a/indra/aistatemachine/aistatemachine.h +++ b/indra/aistatemachine/aistatemachine.h @@ -192,6 +192,15 @@ class AIStateMachine { as_active // State machine is on active_statemachines list. }; + //! Type of continued_statemachines. + typedef std::vector continued_statemachines_type; + //! Type of sContinuedStateMachinesAndMainloopEnabled. + struct csme_type + { + continued_statemachines_type continued_statemachines; + bool mainloop_enabled; + }; + public: typedef U32 state_type; //!< The type of mRunState @@ -231,6 +240,7 @@ class AIStateMachine { callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected. static AIThreadSafeSimpleDC sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame. + static AIThreadSafeDC sContinuedStateMachinesAndMainloopEnabled; //!< Read/write locked variable pair. protected: LLMutex mSetStateLock; //!< For critical areas in set_state() and locked_cont(). @@ -365,11 +375,24 @@ class AIStateMachine { char const* state_str(state_type state); private: - static void add_continued_statemachines(void); - static void mainloop(void*); + static void add_continued_statemachines(AIReadAccess& csme_r); + static void dowork(void); void multiplex(U64 current_time); public: + //! Call this once per frame to give the statemachines CPU cycles. + static void mainloop(void) + { + { + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled, true); + if (!csme_r->mainloop_enabled) + return; + if (!csme_r->continued_statemachines.empty()) + add_continued_statemachines(csme_r); + } + dowork(); + } + //! Abort all running state machines and then run mainloop until all state machines are idle (called when application is exiting). static void flush(void); diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index b7d0045cb..df4de5ead 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -329,14 +329,14 @@ struct AIReadAccessConst }; //! Construct a AIReadAccessConst from a constant AIThreadSafe. - AIReadAccessConst(AIThreadSafe const& wrapper) + AIReadAccessConst(AIThreadSafe const& wrapper, bool high_priority = false) : mWrapper(const_cast&>(wrapper)), mState(readlocked) #if AI_NEED_ACCESS_CC , mIsCopyConstructed(false) #endif { - mWrapper.mRWLock.rdlock(); + mWrapper.mRWLock.rdlock(high_priority); } //! Destruct the AI*Access object. @@ -393,7 +393,7 @@ struct AIReadAccess : public AIReadAccessConst using AIReadAccessConst::readlocked; //! Construct a AIReadAccess from a non-constant AIThreadSafe. - AIReadAccess(AIThreadSafe& wrapper) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); } + AIReadAccess(AIThreadSafe& wrapper, bool high_priority = false) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); } protected: //! Constructor used by AIWriteAccess. diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index c42697ad9..030128b76 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -367,6 +367,7 @@ void LLCrashLogger::updateApplication(const std::string& message) { gServicePump->pump(); gServicePump->callback(); + //FIXME: AIStateMachine::mainloop(); needs CPU cycles. Can't call it from here though, because it uses gSavedSettings which is part of newview. } bool LLCrashLogger::init() diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 96b6166e4..f0985f2b5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1034,6 +1034,7 @@ static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service"); static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback"); static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot"); static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update"); +static LLFastTimer::DeclareTimer FTM_STATEMACHINE("State Machine"); bool LLAppViewer::mainLoop() { @@ -3772,6 +3773,16 @@ void LLAppViewer::idle() } } + ////////////////////////////////////// + // + // Run state machines + // + + { + LLFastTimer t(FTM_STATEMACHINE); + AIStateMachine::mainloop(); + } + // Must wait until both have avatar object and mute list, so poll // here. request_initial_instant_messages(); From adaf5cd69c672a4025010df3edeb8b63cb4125e0 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 27 Jul 2012 01:53:26 +0200 Subject: [PATCH 04/64] Update of a few comments. While comparing this function with v-d, I realized that I editted these instances for Singularity, so I might as well update the comments to be a bit more correct. Not saying that there aren't other comments still missing futher into the function. --- indra/newview/llappviewer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f0985f2b5..afb2a392c 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -597,11 +597,14 @@ bool LLAppViewer::init() // LLFastTimer::reset(); + // // We can call this early. LLFrameTimer::global_initialization(); + // // initialize SSE options LLVector4a::initClass(); + // Need to do this initialization before we do anything else, since anything // that touches files should really go through the lldir API gDirUtilp->initAppDirs("SecondLife"); @@ -611,13 +614,13 @@ bool LLAppViewer::init() initLogging(); + // // Curl must be initialized before any thread is running. AICurlInterface::initCurl(&AIStateMachine::flush); // Logging is initialized. Now it's safe to start the error thread. startErrorThread(); - // gDeleteScheduler = new LLDeleteScheduler(); gBuildNewViewsScheduler = new LLBuildNewViewsScheduler(); // From af4ac8fb5fa8ea5d86f7fb2400b63e18c20cf299 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 29 Jul 2012 01:26:28 +0200 Subject: [PATCH 05/64] WIP: work on rewriting LLURLRequest --- indra/aistatemachine/aicurl.cpp | 11 +- .../aicurleasyrequeststatemachine.cpp | 12 +- .../aicurleasyrequeststatemachine.h | 8 +- indra/aistatemachine/aicurlprivate.h | 6 + indra/aistatemachine/aistatemachine.cpp | 21 +-- indra/aistatemachine/aistatemachine.h | 6 +- indra/llmessage/CMakeLists.txt | 2 +- indra/llmessage/llbuffer.h | 2 +- indra/llmessage/llhttpclient.cpp | 22 ++- indra/llmessage/llhttpclient.h | 4 +- indra/llmessage/llurlrequest.cpp | 149 +++++++----------- indra/llmessage/llurlrequest.h | 85 ++++++++-- indra/newview/hipporestrequest.cpp | 10 +- indra/newview/llappviewer.cpp | 4 + indra/newview/llviewercontrol.cpp | 3 +- 15 files changed, 199 insertions(+), 146 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 61ed1adb9..51325e6c2 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1111,7 +1111,7 @@ static S32 const CURL_REQUEST_TIMEOUT = 30; // Seconds per operation. LLChannelDescriptors const CurlResponderBuffer::sChannels; -CurlResponderBuffer::CurlResponderBuffer() +CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0) { ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); AICurlEasyRequest_wat curl_easy_request_w(*lockobj); @@ -1230,9 +1230,12 @@ size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nm AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); AICurlResponderBuffer_wat buffer_w(*lockobj); - S32 n = size * nmemb; - buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, n); - return n; + // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. + //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; + S32 bytes = size * nmemb; + buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); + mResponseTransferedBytes += bytes; + return bytes; } //static diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index 0c2f0dbc5..221bfdfb2 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -119,9 +119,8 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void) // Set an inactivity timer. // This shouldn't really be necessary, except in the case of a bug // in libcurl; but lets be sure and set a timer for inactivity. - static LLCachedControl CurlRequestTimeOut("CurlRequestTimeOut", 40.f); mTimer = new AIPersistentTimer; // Do not delete timer upon expiration. - mTimer->setInterval(CurlRequestTimeOut); + mTimer->setInterval(sCurlRequestTimeOut); mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false); break; } @@ -242,6 +241,15 @@ AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mB Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); } +//static +F32 AICurlEasyRequestStateMachine::sCurlRequestTimeOut = 40.f; + +//static +void AICurlEasyRequestStateMachine::setCurlRequestTimeOut(F32 CurlRequestTimeOut) +{ + sCurlRequestTimeOut = CurlRequestTimeOut; +} + AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine() { Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.h b/indra/aistatemachine/aicurleasyrequeststatemachine.h index e5f875138..52134a02e 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.h +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.h @@ -40,7 +40,7 @@ // Before calling cersm.run() initialize the object (cersm) as follows: // // AICurlEasyRequest_wat cersm_w(cersm); -// cersm_w->setopt(...); // etc, see the interface of AICurlPrivate::CurlEasyRequest and it's base class AICurlPrivate::CurlEasyHandle. +// cersm_w->setopt(...); // etc, see the interface of AICurlPrivate::CurlEasyRequest. // // When the state machine finishes, call aborted() to check // whether or not the statemachine succeeded in fetching @@ -65,6 +65,12 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa bool mHandled; // Set when we processed the received data. AITimer* mTimer; // Expiration timer. + static F32 sCurlRequestTimeOut; // The time out value for mTimer. + + public: + // Called once to set a different timeout then the default of 40 seconds. + static void setCurlRequestTimeOut(F32 CurlRequestTimeOut); + protected: // AICurlEasyRequest Events. diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index 38ce00b5c..56b2d58ea 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -301,6 +301,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { // Called after removed_from_multi_handle was called. void processOutput(AICurlEasyRequest_wat& curl_easy_request_w); + // Do not write more than this amount. + //void setBodyLimit(U32 size) { mBodyLimit = size; } + protected: /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); @@ -311,6 +314,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { std::stringstream mHeaderOutput; LLIOPipe::buffer_ptr_t mOutput; AICurlInterface::ResponderPtr mResponder; + //U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used. + S32 mByteAccumulator; + S32 mResponseTransferedBytes; public: static LLChannelDescriptors const sChannels; // Channel object for mOutput: we ONLY use channel 0, so this can be a constant. diff --git a/indra/aistatemachine/aistatemachine.cpp b/indra/aistatemachine/aistatemachine.cpp index 622eeb7f5..ef16cf182 100644 --- a/indra/aistatemachine/aistatemachine.cpp +++ b/indra/aistatemachine/aistatemachine.cpp @@ -39,8 +39,6 @@ extern F64 calc_clock_frequency(void); -extern LLControlGroup gSavedSettings; - // Local variables. namespace { struct QueueElementComp; @@ -68,19 +66,15 @@ namespace { } // static -AIThreadSafeSimpleDC AIStateMachine::sMaxCount; +U64 AIStateMachine::sMaxCount; AIThreadSafeDC AIStateMachine::sContinuedStateMachinesAndMainloopEnabled; -void AIStateMachine::updateSettings(void) +// static +void AIStateMachine::setMaxCount(F32 StateMachineMaxTime) { - static const LLCachedControl StateMachineMaxTime("StateMachineMaxTime", 20); - static U32 last_StateMachineMaxTime = 0; - if (last_StateMachineMaxTime != StateMachineMaxTime) - { - Dout(dc::statemachine, "Initializing AIStateMachine::sMaxCount"); - *AIAccess(sMaxCount) = calc_clock_frequency() * StateMachineMaxTime / 1000; - last_StateMachineMaxTime = StateMachineMaxTime; - } + llassert(is_main_thread()); + Dout(dc::statemachine, "(Re)calculating AIStateMachine::sMaxCount"); + sMaxCount = calc_clock_frequency() * StateMachineMaxTime / 1000; } //---------------------------------------------------------------------------- @@ -511,7 +505,6 @@ void AIStateMachine::dowork(void) llassert(!active_statemachines.empty()); // Run one or more state machines. U64 total_clocks = 0; - U64 max_count = *AIAccess(sMaxCount); for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter) { AIStateMachine& statemachine(iter->statemachine()); @@ -525,7 +518,7 @@ void AIStateMachine::dowork(void) U64 delta = LLFastTimer::getCPUClockCount64() - start; iter->add(delta); total_clocks += delta; - if (total_clocks >= max_count) + if (total_clocks >= sMaxCount) { #ifndef LL_RELEASE_FOR_DOWNLOAD llwarns << "AIStateMachine::mainloop did run for " << (total_clocks * 1000 / calc_clock_frequency()) << " ms." << llendl; diff --git a/indra/aistatemachine/aistatemachine.h b/indra/aistatemachine/aistatemachine.h index abdd46e31..d009285af 100644 --- a/indra/aistatemachine/aistatemachine.h +++ b/indra/aistatemachine/aistatemachine.h @@ -239,7 +239,7 @@ class AIStateMachine { }; callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected. - static AIThreadSafeSimpleDC sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame. + static U64 sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame. static AIThreadSafeDC sContinuedStateMachinesAndMainloopEnabled; //!< Read/write locked variable pair. protected: @@ -254,7 +254,7 @@ class AIStateMachine { #ifdef SHOW_ASSERT , mContThread(0), mCalledThreadUnsafeIdle(false) #endif - { updateSettings(); } + { } protected: //! The user should call 'kill()', not delete a AIStateMachine (derived) directly. @@ -349,7 +349,7 @@ class AIStateMachine { // Other. //! Called whenever the StateMachineMaxTime setting is changed. - static void updateSettings(void); + static void setMaxCount(F32 StateMachineMaxTime); //--------------------------------------- // Accessors. diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 90eed3756..fe24dbc63 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories( ) set(llmessage_SOURCE_FILES + llhttpclient.cpp llares.cpp llareslistener.cpp llassetstorage.cpp @@ -36,7 +37,6 @@ set(llmessage_SOURCE_FILES lldispatcher.cpp llfiltersd2xmlrpc.cpp llhost.cpp - llhttpclient.cpp llhttpclientadapter.cpp llhttpnode.cpp llhttpsender.cpp diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index ccdb9fa7e..7f83896a7 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -306,7 +306,7 @@ public: typedef std::list segment_list_t; typedef segment_list_t::const_iterator const_segment_iterator_t; typedef segment_list_t::iterator segment_iterator_t; - enum { npos = 0xffffffff }; + static size_t const npos = (size_t)-1; // (U8*)npos is used as a magic address. LLBufferArray(); ~LLBufferArray(); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 355eebb77..9aef7d837 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -42,7 +42,9 @@ const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; +#ifdef AI_UNUSED LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL; +#endif // AI_UNUSED //////////////////////////////////////////////////////////////////////////// @@ -50,6 +52,7 @@ LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL; namespace { +#if 0 class LLHTTPClientURLAdaptor : public LLURLRequestComplete { public: @@ -93,7 +96,8 @@ namespace std::string mReason; LLSD mHeaderOutput; }; - +#endif + class Injector : public LLIOPipe { public: @@ -206,10 +210,12 @@ namespace LLPumpIO* theClientPump = NULL; } +#ifdef AI_UNUSED void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback) { LLHTTPClient::mCertVerifyCallback = callback; } +#endif static void request( const std::string& url, @@ -245,11 +251,9 @@ static void request( return ; } - req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); + //AIFIXME: getCertVerifyCallback() always return NULL, so we might as well not do this call: req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); - - lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " - << headers << llendl; + lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " << headers << llendl; // Insert custom headers if the caller sent any if (headers.isMap()) @@ -293,7 +297,7 @@ static void request( } } - req->setCallback(new LLHTTPClientURLAdaptor(responder)); + //AIFIXME: req->setCallback(new LLHTTPClientURLAdaptor(responder)); if (method == LLURLRequest::HTTP_POST && gMessageSystem) { @@ -319,7 +323,7 @@ static void request( chain.push_back(LLIOPipe::ptr_t(body_injector)); } - chain.push_back(LLIOPipe::ptr_t(req)); + //AIFIXEM: chain.push_back(LLIOPipe::ptr_t(req)); theClientPump->addChain(chain, timeout); } @@ -499,7 +503,7 @@ static LLSD blocking_request( { // We expect 404s, don't spam for them. llwarns << "CURL REQ URL: " << url << llendl; - llwarns << "CURL REQ METHOD TYPE: " << method << llendl; + llwarns << "CURL REQ METHOD TYPE: " << LLURLRequest::actionAsVerb(method) << llendl; llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl; llwarns << "CURL REQ BODY: " << body_str << llendl; llwarns << "CURL HTTP_STATUS: " << http_status << llendl; @@ -608,11 +612,13 @@ void LLHTTPClient::move( } +//static void LLHTTPClient::setPump(LLPumpIO& pump) { theClientPump = &pump; } +//static bool LLHTTPClient::hasPump() { return theClientPump != NULL; diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 39a6498d8..74c6c92f6 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -34,7 +34,7 @@ #include #include -#include "llurlrequest.h" +//#include "llurlrequest.h" #include "llassettype.h" #include "llcurl.h" #include "lliopipe.h" @@ -156,11 +156,13 @@ public: static LLPumpIO &getPump(); ///< Hippo special +#ifdef AI_UNUSED static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback); static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; } protected: static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback; +#endif // AI_UNUSED }; #endif // LL_LLHTTPCLIENT_H diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 91021186f..c54b2a837 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -36,7 +36,7 @@ #include #include #include -#include "llcurl.h" +#include "aicurleasyrequeststatemachine.h" #include "llfasttimer.h" #include "llioutil.h" #include "llmemtype.h" @@ -55,8 +55,9 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499; const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); -static size_t headerCallback(char* data, size_t size, size_t nmemb, void* user); +//static size_t headerCallback(char* data, size_t size, size_t nmemb, void* user); +#if 0 /** * class LLURLRequestDetail */ @@ -66,23 +67,21 @@ public: LLURLRequestDetail(); ~LLURLRequestDetail(); std::string mURL; - AICurlEasyRequest mCurlEasyRequest; + AICurlEasyRequestStateMachine* mStateMachine; LLIOPipe::buffer_ptr_t mResponseBuffer; LLChannelDescriptors mChannels; U8* mLastRead; U32 mBodyLimit; S32 mByteAccumulator; bool mIsBodyLimitSet; - LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback; }; LLURLRequestDetail::LLURLRequestDetail() : - mCurlEasyRequest(false), + mStateMachine(new AICurlEasyRequestStateMachine(false)), mLastRead(NULL), mBodyLimit(0), mByteAccumulator(0), - mIsBodyLimitSet(false), - mSSLVerifyCallback(NULL) + mIsBodyLimitSet(false) { } @@ -90,18 +89,19 @@ LLURLRequestDetail::~LLURLRequestDetail() { mLastRead = NULL; } +#endif +#if AI_UNUSED void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); mDetail->mSSLVerifyCallback = callback; - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, true); curlEasyRequest_w->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 @@ -123,6 +123,7 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param) return CURLE_OK; } +#endif /** * class LLURLRequest @@ -131,7 +132,8 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param) // static std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) { - static const std::string VERBS[] = + static int const array_size = HTTP_MOVE + 1; // INVALID == 0 + static char const* const VERBS[array_size] = { "(invalid)", "HEAD", @@ -141,60 +143,45 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) "DELETE", "MOVE" }; - if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT)) + return VERBS[action >= array_size ? INVALID : action]; +} + +// This might throw AICurlNoEasyHandle. +LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url) : AICurlEasyRequestStateMachine(false), mAction(action), mURL(url) +{ + LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); + { - return VERBS[0]; + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); + //AIFIXME: we can't really use the other callbacks: they have to be extended... curlEasyRequest_w->setWriteCallback(&downCallback, (void*)this); + //AIFIXME: curlEasyRequest_w->setReadCallback(&upCallback, (void*)this); } - return VERBS[action]; + + //AIFIXME: stuff they have to be extended with... mRequestTransferedBytes = 0; + //AIFIXME: stuff they have to be extended with... mResponseTransferedBytes = 0; + //AIFIXME: start statemachine mState = STATE_INITIALIZED; } -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) : - mAction(action) -{ - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - // This might throw AICurlNoEasyHandle. - initialize(); -} - -LLURLRequest::LLURLRequest( - LLURLRequest::ERequestAction action, - const std::string& url) : - mAction(action) -{ - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - // This might throw AICurlNoEasyHandle. - initialize(); - setURL(url); -} - -LLURLRequest::~LLURLRequest() -{ - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - { - AICurlEasyRequest_wat curl_easy_request_w(*mDetail->mCurlEasyRequest); - curl_easy_request_w->revokeCallbacks(); - curl_easy_request_w->send_events_to(NULL); - } - delete mDetail; -} - -void LLURLRequest::setURL(const std::string& url) +#if 0 +void LLURLRequest::setURL2(const std::string& url) { mDetail->mURL = url; } -std::string LLURLRequest::getURL() const +std::string LLURLRequest::getURL2() const { return mDetail->mURL; } +#endif void LLURLRequest::addHeader(const char* header) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->addHeader(header); } +#ifdef AI_UNUSED void LLURLRequest::setBodyLimit(U32 size) { mDetail->mBodyLimit = size; @@ -205,9 +192,10 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); mCompletionCallback = callback; - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->setHeaderCallback(&headerCallback, (void*)callback); } +#endif // Added to mitigate the effect of libcurl looking // for the ALL_PROXY and http_proxy env variables @@ -242,38 +230,41 @@ void LLURLRequest::useProxy(bool use_proxy) lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl; - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->setoptString(CURLOPT_PROXY, use_proxy ? env_proxy : std::string("")); } +#ifdef AI_UNUSED void LLURLRequest::useProxy(const std::string &proxy) { - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->setoptString(CURLOPT_PROXY, proxy); } +#endif void LLURLRequest::allowCookies() { - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, ""); } +#ifdef AI_UNUSED // no longer derived from LLIOPipe //virtual bool LLURLRequest::hasExpiration(void) const { // Currently, this ALWAYS returns false -- because only AICurlEasyRequestStateMachine uses buffered // AICurlEasyRequest objects, and LLURLRequest uses (unbuffered) AICurlEasyRequest directly, which // have no expiration facility. - return mDetail->mCurlEasyRequest.isBuffered(); + return mDetail->mStateMachine->isBuffered(); } //virtual bool LLURLRequest::hasNotExpired(void) const { - if (!mDetail->mCurlEasyRequest.isBuffered()) + if (!mDetail->mStateMachine->isBuffered()) return true; - AICurlEasyRequest_wat buffered_easy_request_w(*mDetail->mCurlEasyRequest); - AICurlResponderBuffer_wat buffer_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat buffered_easy_request_w(*mCurlEasyRequest); + AICurlResponderBuffer_wat buffer_w(*mCurlEasyRequest); return buffer_w->isValid(); } @@ -285,20 +276,20 @@ LLIOPipe::EStatus LLURLRequest::handleError( DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ")"); LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - if (LL_LIKELY(!mDetail->mCurlEasyRequest.isBuffered())) // Currently always true. + if (LL_LIKELY(!mDetail->mStateMachine->isBuffered())) // Currently always true. { // The last reference will be deleted when the pump that this chain belongs to // is removed from the running chains vector, upon returning from this function. // This keeps the CurlEasyRequest object alive until the curl thread cleanly removed it. - Dout(dc::curl, "Calling mDetail->mCurlEasyRequest.removeRequest()"); - mDetail->mCurlEasyRequest.removeRequest(); + Dout(dc::curl, "Calling mDetail->mStateMachine->removeRequest()"); + mDetail->mStateMachine->removeRequest(); } else if (!hasNotExpired()) { // The buffered version has it's own time out handling, and that already expired, // so we can ignore the expiration of this timer (currently never happens). // I left it here because it's what LL did (in the form if (!isValid() ...), - // and it would be relevant if this characteristic of mDetail->mCurlEasyRequest + // and it would be relevant if this characteristic of mDetail->mStateMachine // would change. --Aleric return STATUS_EXPIRED ; } @@ -317,19 +308,6 @@ LLIOPipe::EStatus LLURLRequest::handleError( return status; } -void LLURLRequest::added_to_multi_handle(AICurlEasyRequest_wat&) -{ -} - -void LLURLRequest::finished(AICurlEasyRequest_wat&) -{ -} - -void LLURLRequest::removed_from_multi_handle(AICurlEasyRequest_wat&) -{ - mRemoved = true; -} - static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request"); // virtual @@ -392,7 +370,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl( } mRemoved = false; mState = STATE_WAITING_FOR_RESPONSE; - mDetail->mCurlEasyRequest.addRequest(); // Add easy handle to multi handle. + mDetail->mStateMachine->addRequest(); // Add easy handle to multi handle. return STATUS_BREAK; } @@ -418,7 +396,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl( static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); - AICurlEasyRequest_wat(*mDetail->mCurlEasyRequest)->getResult(&result); + AICurlEasyRequest_wat(*mCurlEasyRequest)->getResult(&result); mState = STATE_HAVE_RESPONSE; context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; @@ -488,23 +466,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl( return STATUS_ERROR; } } - -void LLURLRequest::initialize() -{ - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - mState = STATE_INITIALIZED; - // This might throw AICurlNoEasyHandle. - mDetail = new LLURLRequestDetail; - - { - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); - curlEasyRequest_w->setWriteCallback(&downCallback, (void*)this); - curlEasyRequest_w->setReadCallback(&upCallback, (void*)this); - } - - mRequestTransferedBytes = 0; - mResponseTransferedBytes = 0; -} +#endif // AI_UNUSED static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure"); bool LLURLRequest::configure() @@ -517,7 +479,7 @@ bool LLURLRequest::configure() mDetail->mChannels.in(), NULL); { - AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); + AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); switch(mAction) { case HTTP_HEAD: @@ -582,12 +544,12 @@ bool LLURLRequest::configure() if(rv) { curlEasyRequest_w->finalizeRequest(mDetail->mURL); - curlEasyRequest_w->send_events_to(this); } } return rv; } +#if 0 // static size_t LLURLRequest::downCallback( char* data, @@ -713,7 +675,9 @@ static size_t headerCallback(char* header_line, size_t size, size_t nmemb, void* return header_len; } +#endif +#ifdef AI_UNUSED /** * LLURLRequestComplete */ @@ -783,3 +747,4 @@ LLIOPipe::EStatus LLURLRequestComplete::process_impl( complete(channels, buffer); return STATUS_OK; } +#endif diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index aee8a1a84..9a20d8cc6 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -7,6 +7,7 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2012, Aleric Inglewood. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,12 +36,73 @@ */ #include -#include "lliopipe.h" -#include "llchainio.h" -#include "llerror.h" -#include "llcurl.h" +#include "aicurleasyrequeststatemachine.h" +class LLURLRequest : public AICurlEasyRequestStateMachine { + public: + /** + * @brief This enumeration is for specifying the type of request. + */ + enum ERequestAction + { + INVALID, + HTTP_HEAD, + HTTP_GET, + HTTP_PUT, + HTTP_POST, + HTTP_DELETE, + HTTP_MOVE, // Caller will need to set 'Destination' header + REQUEST_ACTION_COUNT + }; + /** + * @brief Turn the request action into an http verb. + */ + static std::string actionAsVerb(ERequestAction action); + + /** + * @brief Constructor. + * + * @param action One of the ERequestAction enumerations. + * @param url The url of the request. It should already be encoded. + */ + LLURLRequest(ERequestAction action, std::string const& url); + + /** + * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE. + */ + void allowCookies(void); + + /** + * @ brief Turn off (or on) the CURLOPT_PROXY header. + */ + void useProxy(bool use_proxy); + + /** + * @brief Add a header to the http post. + * + * The header must be correctly formatted for HTTP requests. This + * provides a raw interface if you know what kind of request you + * 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(char const* header); + + private: + /** + * @brief Handle action specific url request configuration. + * + * @return Returns true if this is configured. + */ + bool configure(void); + + private: + ERequestAction mAction; + std::string mURL; +}; + +#if 0 extern const std::string CONTEXT_REQUEST; extern const std::string CONTEXT_RESPONSE; extern const std::string CONTEXT_TRANSFERED_BYTES; @@ -65,7 +127,7 @@ typedef struct x509_store_ctx_st X509_STORE_CTX; * worth the time and effort to eventually port this to a raw client * socket. */ -class LLURLRequest : public LLIOPipe, protected AICurlEasyHandleEvents +class LLURLRequest : public LLIOPipe { LOG_CLASS(LLURLRequest); public: @@ -171,9 +233,6 @@ public: void setCallback(LLURLRequestComplete* callback); //@} - /* @name LLIOPipe virtual implementations - */ - /** * @ brief Turn off (or on) the CURLOPT_PROXY header. */ @@ -189,6 +248,9 @@ public: */ void allowCookies(); + /* @name LLIOPipe virtual implementations + */ + /*virtual*/ bool hasExpiration(void) const; /*virtual*/ bool hasNotExpired(void) const; @@ -229,13 +291,7 @@ protected: static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param); - // mRemoved is used instead of changing mState directly, because I'm not convinced the latter is atomic. - // Set to false before adding curl request and then only tested. - // Reset in removed_from_multi_handle (by another thread), this is thread-safe. bool mRemoved; - /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&); - /*virtual*/ void finished(AICurlEasyRequest_wat&); - /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&); private: /** @@ -346,5 +402,6 @@ protected: // depends on correct useage from the LLURLRequest instance. EStatus mRequestStatus; }; +#endif #endif // LL_LLURLREQUEST_H diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp index 17875f27e..d97c194ac 100644 --- a/indra/newview/hipporestrequest.cpp +++ b/indra/newview/hipporestrequest.cpp @@ -19,7 +19,7 @@ // ******************************************************************** -class HippoRestComplete : public LLURLRequestComplete +class HippoRestComplete /* AIFIXME: public LLURLRequestComplete*/ { public: HippoRestComplete(HippoRestHandler *handler) : @@ -40,6 +40,7 @@ class HippoRestComplete : public LLURLRequestComplete mHandler->addHeader(header, value); } +#if 0 // AIFIXME: doesn't compile // Always called on request completion, prior to complete void httpStatus(U32 status, const std::string& reason) { @@ -52,6 +53,7 @@ class HippoRestComplete : public LLURLRequestComplete { mHandler->handle(mStatus, mReason, channels, buffer); } +#endif private: HippoRestHandler *mHandler; @@ -265,7 +267,7 @@ static void request(const std::string &url, llwarns << "Failed to create LLURLRequest: " << error.what() << llendl; return; } - req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); + //AIFIXME: req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); /* // Insert custom headers if the caller sent any @@ -300,7 +302,7 @@ static void request(const std::string &url, req->addHeader(accept.c_str()); } - req->setCallback(new HippoRestComplete(handler)); + //AIFIXME: req->setCallback(new HippoRestComplete(handler)); if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) { std::string content = "Content-Type: "; @@ -309,7 +311,7 @@ static void request(const std::string &url, chain.push_back(LLIOPipe::ptr_t(body)); } - chain.push_back(LLIOPipe::ptr_t(req)); + //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req)); LLHTTPClient::getPump().addChain(chain, timeout); } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index afb2a392c..23262bad3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -118,6 +118,7 @@ // #include "lldelayeduidelete.h" #include "llbuildnewviewsscheduler.h" +#include "aicurleasyrequeststatemachine.h" // // The files below handle dependencies from cleanup. #include "llcalc.h" @@ -642,6 +643,9 @@ bool LLAppViewer::init() mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); + AIStateMachine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime")); + AICurlEasyRequestStateMachine::setCurlRequestTimeOut(gSavedSettings.getF32("CurlRequestTimeOut")); + initThreads(); LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index e6322efed..85e8feebb 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -124,7 +124,8 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue) bool handleStateMachineMaxTimeChanged(const LLSD& newvalue) { - AIStateMachine::updateSettings(); + F32 StateMachineMaxTime = newvalue.asFloat(); + AIStateMachine::setMaxCount(StateMachineMaxTime); return true; } From 29908533cd18ec058f76096dbd435187e9293520 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 31 Jul 2012 22:23:52 +0200 Subject: [PATCH 06/64] More work in progress --- indra/aistatemachine/aicurl.cpp | 7 +++-- .../aicurleasyrequeststatemachine.cpp | 4 +++ indra/aistatemachine/aicurlprivate.h | 2 +- indra/aistatemachine/aicurlthread.cpp | 4 +++ indra/llmessage/llhttpclient.cpp | 1 + indra/llmessage/llurlrequest.cpp | 31 ++++++++++--------- indra/llmessage/llurlrequest.h | 7 +++++ 7 files changed, 37 insertions(+), 19 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 090876f4e..1cbf1afaa 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1231,12 +1231,12 @@ size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nm // to make sure that callbacks and destruction aren't done simultaneously. AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + S32 bytes = size * nmemb; // The amount to write. AICurlResponderBuffer_wat buffer_w(*lockobj); // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; - S32 bytes = size * nmemb; buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); - mResponseTransferedBytes += bytes; + buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. return bytes; } @@ -1252,7 +1252,8 @@ size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nme S32 bytes = size * nmemb; // The maximum amount to read. AICurlResponderBuffer_wat buffer_w(*lockobj); buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); - return bytes; // Return the amount actually read. + buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + return bytes; // Return the amount actually read (might be lowered by readAfter()). } //static diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index 221bfdfb2..d6ab002db 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -239,6 +239,10 @@ void AICurlEasyRequestStateMachine::finish_impl(void) AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mBuffered(buffered), mCurlEasyRequest(buffered) { Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); + if (!mBuffered) + { + llwarns << "Using unbuffered AICurlEasyRequestStateMachine" << llendl; + } } //static diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index acd3a808c..a99224f96 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -316,7 +316,7 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { LLIOPipe::buffer_ptr_t mOutput; AICurlInterface::ResponderPtr mResponder; //U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used. - S32 mByteAccumulator; + S32 mRequestTransferedBytes; S32 mResponseTransferedBytes; public: diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index c75912047..65ef1317b 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -39,7 +39,11 @@ #endif #include +// On linux, add -DDEBUG_WINDOWS_CODE_ON_LINUX to test the windows code used in this file. +#if !defined(DEBUG_WINDOWS_CODE_ON_LINUX) || !defined(LL_LINUX) || defined(LL_RELEASE) +#undef DEBUG_WINDOWS_CODE_ON_LINUX #define DEBUG_WINDOWS_CODE_ON_LINUX 0 +#endif #if DEBUG_WINDOWS_CODE_ON_LINUX diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 9aef7d837..e954dcd1b 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -298,6 +298,7 @@ static void request( } //AIFIXME: req->setCallback(new LLHTTPClientURLAdaptor(responder)); + llassert_always(false); if (method == LLURLRequest::HTTP_POST && gMessageSystem) { diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index c54b2a837..e66dc3c1b 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -147,19 +147,12 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) } // This might throw AICurlNoEasyHandle. -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url) : AICurlEasyRequestStateMachine(false), mAction(action), mURL(url) +LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url) : AICurlEasyRequestStateMachine(true), mAction(action), mURL(url) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - { - AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); - //AIFIXME: we can't really use the other callbacks: they have to be extended... curlEasyRequest_w->setWriteCallback(&downCallback, (void*)this); - //AIFIXME: curlEasyRequest_w->setReadCallback(&upCallback, (void*)this); - } - - //AIFIXME: stuff they have to be extended with... mRequestTransferedBytes = 0; - //AIFIXME: stuff they have to be extended with... mResponseTransferedBytes = 0; //AIFIXME: start statemachine mState = STATE_INITIALIZED; + llassert_always(false); } #if 0 @@ -468,6 +461,13 @@ LLIOPipe::EStatus LLURLRequest::process_impl( } #endif // AI_UNUSED +S32 LLURLRequest::bytes_to_send(void) const +{ + //AIFIXME: how to get the number of bytes to send? + llassert_always(false); + return 0; +} + static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure"); bool LLURLRequest::configure() { @@ -475,9 +475,6 @@ bool LLURLRequest::configure() LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); bool rv = false; - S32 bytes = mDetail->mResponseBuffer->countAfter( - mDetail->mChannels.in(), - NULL); { AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); switch(mAction) @@ -498,16 +495,19 @@ bool LLURLRequest::configure() 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("Expect:"); + S32 bytes = bytes_to_send(); curlEasyRequest_w->setopt(CURLOPT_UPLOAD, 1); curlEasyRequest_w->setopt(CURLOPT_INFILESIZE, bytes); rv = true; break; - + } case HTTP_POST: + { // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. addHeader("Expect:"); @@ -517,13 +517,14 @@ bool LLURLRequest::configure() addHeader("Content-Type:"); // Set the handle for an http post + S32 bytes = bytes_to_send(); curlEasyRequest_w->setPost(NULL, bytes); // Set Accept-Encoding to allow response compression curlEasyRequest_w->setoptString(CURLOPT_ENCODING, ""); rv = true; break; - + } case HTTP_DELETE: // Set the handle for an http post curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE"); @@ -543,7 +544,7 @@ bool LLURLRequest::configure() } if(rv) { - curlEasyRequest_w->finalizeRequest(mDetail->mURL); + curlEasyRequest_w->finalizeRequest(mURL); } } return rv; diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 9a20d8cc6..65b714556 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -97,6 +97,13 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { */ bool configure(void); + /** + * @ brief Return the number of bytes to POST or PUT to the server. + * + * @return Returns the number of bytes we're about to upload. + */ + S32 bytes_to_send(void) const; + private: ERequestAction mAction; std::string mURL; From 5fb4badb7ccd66b0d834f132c17e7531aec558a8 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 2 Aug 2012 22:34:23 +0200 Subject: [PATCH 07/64] WIP --- indra/aistatemachine/aicurl.cpp | 94 ++++++++++++++++--- indra/aistatemachine/aicurl.h | 1 + .../aicurleasyrequeststatemachine.cpp | 52 ++++++---- .../aicurleasyrequeststatemachine.h | 23 +++-- indra/aistatemachine/aicurlprivate.h | 11 ++- indra/llcommon/llstring.h | 14 +++ indra/llmessage/llhttpclient.cpp | 70 +++++++------- indra/llmessage/llurlrequest.cpp | 4 +- 8 files changed, 192 insertions(+), 77 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 1cbf1afaa..054d78389 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1091,6 +1091,12 @@ void CurlEasyRequest::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_req mEventsTarget->added_to_multi_handle(curl_easy_request_w); } +void CurlEasyRequest::decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) +{ + if (mEventsTarget) + mEventsTarget->decoded_header(curl_easy_request_w, key, value); +} + void CurlEasyRequest::finished(AICurlEasyRequest_wat& curl_easy_request_w) { if (mEventsTarget) @@ -1106,7 +1112,7 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy //----------------------------------------------------------------------------- // CurlResponderBuffer -static unsigned int const MAX_REDIRECTS = 5; +static int const HTTP_REDIRECTS_DEFAULT = 10; static S32 const CURL_REQUEST_TIMEOUT = 30; // Seconds per operation. LLChannelDescriptors const CurlResponderBuffer::sChannels; @@ -1165,9 +1171,6 @@ void CurlResponderBuffer::resetState(AICurlEasyRequest_wat& curl_easy_request_w) mOutput.reset(); mInput.reset(); - - mHeaderOutput.str(""); - mHeaderOutput.clear(); } ThreadSafeBufferedCurlEasyRequest* CurlResponderBuffer::get_lockobj(void) @@ -1194,14 +1197,14 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w curl_easy_request_w->setReadCallback(&curlReadCallback, lockobj); curl_easy_request_w->setHeaderCallback(&curlHeaderCallback, lockobj); - // Allow up to five redirects. + // Allow up to ten redirects. if (responder && responder->followRedir()) { curl_easy_request_w->setopt(CURLOPT_FOLLOWLOCATION, 1); - curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS); + curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); } - curl_easy_request_w->setopt(CURLOPT_SSL_VERIFYPEER, true); + curl_easy_request_w->setopt(CURLOPT_SSL_VERIFYPEER, 1); // Don't verify host name so urls with scrubbed host names will work (improves DNS performance). curl_easy_request_w->setopt(CURLOPT_SSL_VERIFYHOST, 0); @@ -1261,14 +1264,74 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n { ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); - // We need to lock the curl easy request object too, because that lock is used + // We need to lock the curl easy request object, because that lock is used // to make sure that callbacks and destruction aren't done simultaneously. AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); - AICurlResponderBuffer_wat buffer_w(*lockobj); - size_t n = size * nmemb; - buffer_w->getHeaderOutput().write(data, n); - return n; + // This used to be headerCallback() in llurlrequest.cpp. + + char const* const header_line = static_cast(data); + size_t const header_len = size * nmemb; + + if (!header_len) + { + return header_len; + } + std::string header(header_line, header_len); + if (!LLStringUtil::_isASCII(header)) + { + return header_len; + } + + // Per HTTP spec the first header line must be the status line. + if (header.substr(0, 5) == "HTTP/") + { + std::string::iterator const begin = header.begin(); + std::string::iterator const end = header.end(); + std::string::iterator pos1 = std::find(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'); + U32 status; + std::string reason; + if (pos3 != end && std::isdigit(*pos1)) + { + status = atoi(&header_line[pos1 - begin]); + reason.assign(pos2, pos3); + } + else + { + status = HTTP_INTERNAL_ERROR; + reason = "Header parse error."; + llwarns << "Received broken header line from server: \"" << header << "\"" << llendl; + } + AICurlResponderBuffer_wat(*lockobj)->setStatusAndReason(status, 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); + + AICurlResponderBuffer_wat(*lockobj)->decoded_header(buffered_easy_request_w, key, value); + } + else + { + LLStringUtil::trim(header); + if (!header.empty()) + { + llwarns << "Unable to parse header: " << header << llendl; + } + } + + return header_len; } void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) @@ -1276,6 +1339,11 @@ void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy Dout(dc::curl, "Calling CurlResponderBuffer::added_to_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); } +void CurlResponderBuffer::decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) +{ + Dout(dc::curl, "Calling CurlResponderBuffer::decoded_header(@" << (void*)&*curl_easy_request_w << ", \"" << key << "\", \"" << value << "\") for this = " << (void*)this); +} + void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w) { Dout(dc::curl, "Calling CurlResponderBuffer::finished(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); @@ -1304,7 +1372,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request if (code == CURLE_OK) { curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode); - //*TODO: get reason from first line of mHeaderOutput + //AIFIXME: fill responseReason if (responseCode < 200 || responseCode >= 300). } else { diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 90803e050..a8b4dda90 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -235,6 +235,7 @@ typedef AIAccess AICurlEasyRequest_wat; struct AICurlEasyHandleEvents { // Events. virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0; + virtual void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) = 0; virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0; virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0; // Avoid compiler warning. diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index d6ab002db..b4e98a22b 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -77,6 +77,11 @@ void AICurlEasyRequestStateMachine::added_to_multi_handle(AICurlEasyRequest_wat& set_state(AICurlEasyRequestStateMachine_added); } +// CURL-THREAD +void AICurlEasyRequestStateMachine::decoded_header(AICurlEasyRequest_wat&, std::string const& key, std::string const& value) +{ +} + // CURL-THREAD void AICurlEasyRequestStateMachine::finished(AICurlEasyRequest_wat&) { @@ -116,12 +121,15 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void) // 3) AICurlEasyRequestStateMachine_finished (running) // 4) AICurlEasyRequestStateMachine_removed_after_finished (running) - // Set an inactivity timer. - // This shouldn't really be necessary, except in the case of a bug - // in libcurl; but lets be sure and set a timer for inactivity. - mTimer = new AIPersistentTimer; // Do not delete timer upon expiration. - mTimer->setInterval(sCurlRequestTimeOut); - mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false); + if (mRequestTimeOut > 0.f) + { + // Set an inactivity timer. + // This shouldn't really be necessary, except in the case of a bug + // in libcurl; but lets be sure and set a timer for inactivity. + mTimer = new AIPersistentTimer; // Do not delete timer upon expiration. + mTimer->setInterval(mRequestTimeOut); + mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false); + } break; } case AICurlEasyRequestStateMachine_added: @@ -160,9 +168,12 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void) // Only do this once. mHandled = true; - // Stop the timer. Note that it's the main thread that generates timer events, - // so we're certain that there will be no time out anymore if we reach this point. - mTimer->abort(); + if (mTimer) + { + // Stop the timer. Note that it's the main thread that generates timer events, + // so we're certain that there will be no time out anymore if we reach this point. + mTimer->abort(); + } // The request finished and either data or an error code is available. if (mBuffered) @@ -228,15 +239,19 @@ void AICurlEasyRequestStateMachine::finish_impl(void) curl_easy_request_w->send_events_to(NULL); curl_easy_request_w->revokeCallbacks(); } - // Note that even if the timer expired, it wasn't deleted because we used AIPersistentTimer; so mTimer is still valid. - // Stop the timer, if it's still running. - if (!mHandled) - mTimer->abort(); + if (mTimer) + { + // Note that even if the timer expired, it wasn't deleted because we used AIPersistentTimer; so mTimer is still valid. + // Stop the timer, if it's still running. + if (!mHandled) + mTimer->abort(); + } // Auto clean up ourselves. kill(); } -AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mBuffered(buffered), mCurlEasyRequest(buffered) +AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : + mBuffered(buffered), mCurlEasyRequest(buffered), mTimer(NULL), mRequestTimeOut(sCurlRequestTimeOut) { Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); if (!mBuffered) @@ -249,9 +264,14 @@ AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mB F32 AICurlEasyRequestStateMachine::sCurlRequestTimeOut = 40.f; //static -void AICurlEasyRequestStateMachine::setCurlRequestTimeOut(F32 CurlRequestTimeOut) +void AICurlEasyRequestStateMachine::setDefaultRequestTimeOut(F32 defaultRequestTimeOut) { - sCurlRequestTimeOut = CurlRequestTimeOut; + sCurlRequestTimeOut = defaultRequestTimeOut; +} + +void AICurlEasyRequestStateMachine::setRequestTimeOut(F32 curlRequestTimeOut) +{ + mRequestTimeOut = curlRequestTimeOut; } AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine() diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.h b/indra/aistatemachine/aicurleasyrequeststatemachine.h index 52134a02e..b3aae1c2e 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.h +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.h @@ -58,18 +58,22 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa AICurlEasyRequest mCurlEasyRequest; private: - bool mBuffered; // Argument used for construction of mCurlEasyRequest. - bool mAdded; // Set when the last command to the curl thread was to add the request. - bool mTimedOut; // Set if the expiration timer timed out. - bool mFinished; // Set by the curl thread to signal it finished. - bool mHandled; // Set when we processed the received data. - AITimer* mTimer; // Expiration timer. + bool mBuffered; // Argument used for construction of mCurlEasyRequest. + bool mAdded; // Set when the last command to the curl thread was to add the request. + bool mTimedOut; // Set if the expiration timer timed out. + bool mFinished; // Set by the curl thread to signal it finished. + bool mHandled; // Set when we processed the received data. + AITimer* mTimer; // Expiration timer. + F32 mRequestTimeOut; // The time out value for mTimer. - static F32 sCurlRequestTimeOut; // The time out value for mTimer. + static F32 sCurlRequestTimeOut; // The default time out value for mTimer (CurlRequestTimeOut debug setting). public: // Called once to set a different timeout then the default of 40 seconds. - static void setCurlRequestTimeOut(F32 CurlRequestTimeOut); + static void setDefaultRequestTimeOut(F32 defaultRequestTimeOut); + + // Called to set a specific time out, instead of the default one. + void setRequestTimeOut(F32 requestTimeOut); protected: // AICurlEasyRequest Events. @@ -77,6 +81,9 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa // Called when this curl easy handle was added to a multi handle. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&); + // Called for each received HTTP header key/value pair. + /*virtual*/ void decoded_header(AICurlEasyRequest_wat&, std::string const& key, std::string const& value); + // Called when this curl easy handle finished processing (right before it is removed from the multi handle). /*virtual*/ void finished(AICurlEasyRequest_wat&); diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index a99224f96..d45b91fa1 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -267,6 +267,7 @@ class CurlEasyRequest : public CurlEasyHandle { protected: // Pass events to parent. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); + /*virtual*/ void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); }; @@ -292,10 +293,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, std::vector const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0, bool post = false); LLIOPipe::buffer_ptr_t& getInput(void) { return mInput; } - std::stringstream& getHeaderOutput(void) { return mHeaderOutput; } LLIOPipe::buffer_ptr_t& getOutput(void) { return mOutput; } - // Called if libcurl doesn't deliver within CurlRequestTimeOut seconds. + // Called if libcurl doesn't deliver within mRequestTimeOut seconds. void timed_out(void); // Called after removed_from_multi_handle was called. @@ -306,16 +306,18 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { protected: /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); + /*virtual*/ void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); private: LLIOPipe::buffer_ptr_t mInput; U8* mLastRead; // Pointer into mInput where we last stopped reading (or NULL to start at the beginning). - std::stringstream mHeaderOutput; LLIOPipe::buffer_ptr_t mOutput; AICurlInterface::ResponderPtr mResponder; //U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used. + U32 mStatus; // HTTP status, decoded from the first header line. + std::string mReason; // The "reason" from the same header line. S32 mRequestTransferedBytes; S32 mResponseTransferedBytes; @@ -334,6 +336,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { static size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data); static size_t curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data); + // Called from curlHeaderCallback. + void setStatusAndReason(U32 status, std::string const& reason) { mStatus = status; mReason = reason; } + public: // Return pointer to the ThreadSafe (wrapped) version of this object. ThreadSafeBufferedCurlEasyRequest* get_lockobj(void); diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index bdbefe935..84f4d0f69 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -318,6 +318,7 @@ public: * should work. */ static void _makeASCII(std::basic_string& string); + static bool _isASCII(std::basic_string const& string); // Conversion to other data types static BOOL convertToBOOL(const std::basic_string& string, BOOL& value); @@ -1073,6 +1074,19 @@ void LLStringUtilBase::_makeASCII(std::basic_string& string) } } +template +bool LLStringUtilBase::_isASCII(std::basic_string const& string) +{ + size_type const len = string.length(); + T bit_collector = 0; + for (size_type i = 0; i < len; ++i) + { + bit_collector |= string[i]; + } + T const ascii_bits = 0x7f; + return !(bit_collector & ~ascii_bits); +} + // static template void LLStringUtilBase::copy( T* dst, const T* src, size_type dst_size ) diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index e954dcd1b..78d77db1d 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -251,7 +251,8 @@ static void request( return ; } - //AIFIXME: getCertVerifyCallback() always return NULL, so we might as well not do this call: req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); + //AIFIXME: getCertVerifyCallback() always return NULL, so we might as well not do this call: + //req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " << headers << llendl; @@ -283,50 +284,51 @@ static void request( lldebugs << "header = " << header.str() << llendl; req->addHeader(header.str().c_str()); } + + if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) + { + static std::string const CONTENT_TYPE("Content-Type"); + if(!headers.has(CONTENT_TYPE)) + { + // If the Content-Type header was passed in, it has + // already been added as a header through req->addHeader + // in the loop above. We defer to the caller's wisdom, but + // if they did not specify a Content-Type, then ask the + // injector. + req->addHeader(llformat("Content-Type: %s", body_injector->contentType()).c_str()); + } + } + else + { + // 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. + static std::string const ACCEPT("Accept"); + if (!headers.has(ACCEPT)) + { + req->addHeader("Accept: application/llsd+xml"); + } + } } - // Check to see if we have already set Accept or not. If no one - // set it, set it to application/llsd+xml since that's what we - // almost always want. - if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST ) + if (method == LLURLRequest::HTTP_POST && gMessageSystem) { - static const std::string ACCEPT("Accept"); - if(!headers.has(ACCEPT)) - { - req->addHeader("Accept: application/llsd+xml"); - } - } - - //AIFIXME: req->setCallback(new LLHTTPClientURLAdaptor(responder)); - llassert_always(false); - - if (method == LLURLRequest::HTTP_POST && gMessageSystem) - { - req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", - gMessageSystem->mPort).c_str()); + req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", gMessageSystem->mPort).c_str()); } if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) { - static const std::string CONTENT_TYPE("Content-Type"); - if(!headers.has(CONTENT_TYPE)) - { - // If the Content-Type header was passed in, it has - // already been added as a header through req->addHeader - // in the loop above. We defer to the caller's wisdom, but - // if they did not specify a Content-Type, then ask the - // injector. - req->addHeader( - llformat( - "Content-Type: %s", - body_injector->contentType()).c_str()); - } chain.push_back(LLIOPipe::ptr_t(body_injector)); } - //AIFIXEM: chain.push_back(LLIOPipe::ptr_t(req)); + //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req)); - theClientPump->addChain(chain, timeout); + AICurlEasyRequest_wat buffered_easy_request_w(*req->mCurlEasyRequest); + AICurlResponderBuffer_wat buffer_w(*req->mCurlEasyRequest); + buffer_w->prepRequest(buffered_easy_request_w, headers, responder); + + req->setRequestTimeOut(timeout); + //AIFIXME: theClientPump->addChain(chain, timeout); } diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index e66dc3c1b..699214204 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -150,9 +150,7 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url) : AICurlEasyRequestStateMachine(true), mAction(action), mURL(url) { LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - - //AIFIXME: start statemachine mState = STATE_INITIALIZED; - llassert_always(false); + run(); } #if 0 From 95083e846b667772e90cf3c6243f4e99a1ebc081 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 6 Aug 2012 23:19:09 +0200 Subject: [PATCH 08/64] WIP --- indra/llmessage/llhttpclient.cpp | 109 +++++++++++++++++-------------- indra/newview/llappviewer.cpp | 2 +- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 78d77db1d..a49ee17de 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -195,8 +195,8 @@ namespace S32 fileSize = vfile.getSize(); U8* fileBuffer; fileBuffer = new U8 [fileSize]; - vfile.read(fileBuffer, fileSize); - ostream.write((char*)fileBuffer, fileSize); + vfile.read(fileBuffer, fileSize); + ostream.write((char*)fileBuffer, fileSize); delete [] fileBuffer; eos = true; return STATUS_DONE; @@ -224,7 +224,7 @@ static void request( LLCurl::ResponderPtr responder, const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, const LLSD& headers = LLSD() - ) + ) { if (responder) { @@ -256,7 +256,13 @@ static void request( lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " << headers << llendl; - // Insert custom headers if the caller sent any + // Insert custom headers if the caller sent any. + + std::vector headers_vector; + bool has_content_type = false; + bool has_accept = false; + + // Note that headers always is a map, unless no argument was passed. if (headers.isMap()) { if (headers.has("Cookie")) @@ -264,68 +270,71 @@ static void request( req->allowCookies(); } - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator end = headers.endMap(); + LLSD::map_const_iterator iter = headers.beginMap(); + LLSD::map_const_iterator const end = headers.endMap(); - for (; iter != end; ++iter) - { - std::ostringstream header; - //if the header is "Pragma" with no value - //the caller intends to force libcurl to drop - //the Pragma header it so gratuitously inserts - //Before inserting the header, force libcurl - //to not use the proxy (read: llurlrequest.cpp) - static const std::string PRAGMA("Pragma"); - if ((iter->first == PRAGMA) && (iter->second.asString().empty())) - { - req->useProxy(false); - } - header << iter->first << ": " << iter->second.asString() ; - lldebugs << "header = " << header.str() << llendl; - req->addHeader(header.str().c_str()); - } - - if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) + for (; iter != end; ++iter) { - static std::string const CONTENT_TYPE("Content-Type"); - if(!headers.has(CONTENT_TYPE)) + // 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. + if (iter->first.compare("Pragma") == 0 && iter->second.asString().empty()) { - // If the Content-Type header was passed in, it has - // already been added as a header through req->addHeader - // in the loop above. We defer to the caller's wisdom, but - // if they did not specify a Content-Type, then ask the - // injector. - req->addHeader(llformat("Content-Type: %s", body_injector->contentType()).c_str()); + req->useProxy(false); } - } - else - { - // 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. - static std::string const ACCEPT("Accept"); - if (!headers.has(ACCEPT)) + if (iter->first.compare("Content-Type") == 0) { - req->addHeader("Accept: application/llsd+xml"); + has_content_type = true; + } + if (iter->first.compare("Accept") == 0) + { + has_accept = true; } - } - } - if (method == LLURLRequest::HTTP_POST && gMessageSystem) - { - req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", gMessageSystem->mPort).c_str()); - } + std::ostringstream header; + header << iter->first << ": " << iter->second.asString(); + headers_vector.push_back(header.str()); + } + } if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) { - chain.push_back(LLIOPipe::ptr_t(body_injector)); + if (!has_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. + headers_vector.push_back(llformat("Content-Type: %s", body_injector->contentType())); + } + } + else + { + // 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 (!has_accept) + { + headers_vector.push_back("Accept: application/llsd+xml"); + } + } + if (method == LLURLRequest::HTTP_POST && gMessageSystem) + { + headers_vector.push_back(llformat("X-SecondLife-UDP-Listen-Port: %d", gMessageSystem->mPort)); + } + + if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) + { + //AIFIXME: + chain.push_back(LLIOPipe::ptr_t(body_injector)); } //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req)); AICurlEasyRequest_wat buffered_easy_request_w(*req->mCurlEasyRequest); AICurlResponderBuffer_wat buffer_w(*req->mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, headers, responder); + buffer_w->prepRequest(buffered_easy_request_w, headers_vector, responder); req->setRequestTimeOut(timeout); //AIFIXME: theClientPump->addChain(chain, timeout); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 23262bad3..800a20f85 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -644,7 +644,7 @@ bool LLAppViewer::init() mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); AIStateMachine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime")); - AICurlEasyRequestStateMachine::setCurlRequestTimeOut(gSavedSettings.getF32("CurlRequestTimeOut")); + AICurlEasyRequestStateMachine::setDefaultRequestTimeOut(gSavedSettings.getF32("CurlRequestTimeOut")); initThreads(); LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; From 83b13f6a3f332b0b61052ef0024382b360507a11 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 20 Aug 2012 17:29:15 +0200 Subject: [PATCH 09/64] WIP: make everything use AICurlEasyRequestStateMachine --- indra/aistatemachine/aicurl.cpp | 41 +- indra/aistatemachine/aicurl.h | 22 +- indra/aistatemachine/aicurlprivate.h | 25 +- indra/aistatemachine/debug_libcurl.cpp | 6 +- indra/llcommon/llfile.h | 2 +- indra/llcommon/llmemtype.cpp | 1 - indra/llcommon/llmemtype.h | 1 - indra/llcrashlogger/llcrashlogger.cpp | 3 +- indra/llmessage/CMakeLists.txt | 2 + indra/llmessage/aihttpheaders.cpp | 107 ++++ indra/llmessage/aihttpheaders.h | 86 +++ indra/llmessage/llavatarnamecache.cpp | 4 +- indra/llmessage/llbufferstream.h | 14 + indra/llmessage/llcurlrequest.cpp | 22 +- indra/llmessage/llcurlrequest.h | 12 +- indra/llmessage/llhttpclient.cpp | 511 ++++++------------ indra/llmessage/llhttpclient.h | 119 ++-- indra/llmessage/llhttpclientadapter.cpp | 12 +- indra/llmessage/llhttpsender.cpp | 2 +- indra/llmessage/llsdmessage.cpp | 3 +- indra/llmessage/llurlrequest.cpp | 113 ++-- indra/llmessage/llurlrequest.h | 37 +- indra/newview/floatervoicelicense.cpp | 2 +- indra/newview/hgfloatertexteditor.cpp | 2 +- indra/newview/hipporestrequest.cpp | 69 +-- indra/newview/hipporestrequest.h | 19 +- indra/newview/lggdicdownload.cpp | 8 +- indra/newview/llaccountingcostmanager.cpp | 2 +- indra/newview/llagent.cpp | 2 +- indra/newview/llagentlanguage.cpp | 2 +- indra/newview/llappviewer.cpp | 1 - indra/newview/llassetuploadqueue.cpp | 10 +- indra/newview/llassetuploadqueue.h | 4 +- indra/newview/llassetuploadresponders.cpp | 8 +- indra/newview/llcapabilitylistener.cpp | 3 +- indra/newview/llcaphttpsender.cpp | 2 +- indra/newview/llcompilequeue.cpp | 4 +- indra/newview/lleventpoll.cpp | 6 +- indra/newview/llfloateractivespeakers.cpp | 6 +- indra/newview/llfloatermodeluploadbase.cpp | 2 +- indra/newview/llfloaterpostcard.cpp | 2 +- indra/newview/llfloaterregiondebugconsole.cpp | 4 +- indra/newview/llfloaterregioninfo.cpp | 4 +- indra/newview/llfloaterreporter.cpp | 4 +- indra/newview/llfloaterteleport.cpp | 2 +- indra/newview/llfloatertos.cpp | 2 +- indra/newview/llfloaterurlentry.cpp | 2 +- indra/newview/llimpanel.cpp | 6 +- indra/newview/llimview.cpp | 6 +- indra/newview/llinventorymodel.cpp | 2 +- .../llinventorymodelbackgroundfetch.cpp | 8 +- indra/newview/llinventoryobserver.cpp | 2 +- indra/newview/llmeshrepository.cpp | 33 +- indra/newview/llpanelclassified.cpp | 4 +- indra/newview/llpanelgroupvoting.cpp | 4 +- indra/newview/llpanellogin.cpp | 2 +- indra/newview/llpanelplace.cpp | 2 +- indra/newview/llpathfindingmanager.cpp | 18 +- indra/newview/llpreviewgesture.cpp | 4 +- indra/newview/llpreviewnotecard.cpp | 4 +- indra/newview/llpreviewscript.cpp | 4 +- indra/newview/llproductinforequest.cpp | 2 +- indra/newview/lltexlayer.cpp | 2 +- indra/newview/lltexturefetch.cpp | 11 +- indra/newview/lltexturestatsuploader.cpp | 2 +- indra/newview/lltranslate.cpp | 10 +- indra/newview/lltranslate.h | 2 +- indra/newview/llviewerdisplayname.cpp | 5 +- indra/newview/llviewerinventory.cpp | 2 +- indra/newview/llviewermedia.cpp | 22 +- indra/newview/llviewermenufile.cpp | 4 +- indra/newview/llviewermessage.cpp | 2 +- indra/newview/llviewerobjectbackup.cpp | 2 +- indra/newview/llviewerobjectlist.cpp | 4 +- indra/newview/llviewerparcelmedia.cpp | 2 +- indra/newview/llviewerparcelmgr.cpp | 2 +- indra/newview/llviewerregion.cpp | 12 +- indra/newview/llviewerstats.cpp | 2 +- indra/newview/llvoiceclient.cpp | 4 +- indra/newview/llwaterparammanager.cpp | 2 +- indra/newview/llwlhandlers.cpp | 4 +- indra/newview/llwlparammanager.cpp | 2 +- indra/newview/llworldmap.cpp | 2 +- 83 files changed, 766 insertions(+), 752 deletions(-) create mode 100644 indra/llmessage/aihttpheaders.cpp create mode 100644 indra/llmessage/aihttpheaders.h diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index cb455343a..68e8e50ae 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -51,6 +51,7 @@ #include "lltimer.h" // ms_sleep #include "llproxy.h" #include "llhttpstatuscodes.h" +#include "aihttpheaders.h" #ifdef CWDEBUG #include #endif @@ -797,7 +798,7 @@ void CurlEasyRequest::setoptString(CURLoption option, std::string const& value) setopt(option, value.c_str()); } -void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, S32 size) +void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size) { llassert_always(postdata->data()); @@ -807,7 +808,7 @@ void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, S32 size) setPost_raw(size, postdata->data()); } -void CurlEasyRequest::setPost_raw(S32 size, char const* data) +void CurlEasyRequest::setPost_raw(U32 size, char const* data) { if (!data) { @@ -815,6 +816,9 @@ void CurlEasyRequest::setPost_raw(S32 size, char const* data) Dout(dc::curl, "POST size is " << size << " bytes."); } + // Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)). + setoptString(CURLOPT_ENCODING, ""); // CURLOPT_ACCEPT_ENCODING + // The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default. addHeader("Expect:"); if (size > 0) @@ -823,7 +827,7 @@ void CurlEasyRequest::setPost_raw(S32 size, char const* data) addHeader("Keep-alive: 300"); } setopt(CURLOPT_POSTFIELDSIZE, size); - setopt(CURLOPT_POSTFIELDS, data); + setopt(CURLOPT_POSTFIELDS, data); // Implies CURLOPT_POST } ThreadSafeCurlEasyRequest* CurlEasyRequest::get_lockobj(void) @@ -979,6 +983,12 @@ void CurlEasyRequest::addHeader(char const* header) mHeaders = curl_slist_append(mHeaders, header); } +void CurlEasyRequest::addHeaders(AIHTTPHeaders const& headers) +{ + llassert(!mRequestFinalized); + headers.append_to(mHeaders); +} + #if defined(CWDEBUG) || defined(DEBUG_CURLIO) static int curl_debug_cb(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr) @@ -1307,14 +1317,8 @@ ThreadSafeBufferedCurlEasyRequest* CurlResponderBuffer::get_lockobj(void) return static_cast(AIThreadSafeSimple::wrapper_cast(this)); } -void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, std::vector const& headers, AICurlInterface::ResponderPtr responder, S32 time_out, bool post) +void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder, S32 time_out) { - if (post) - { - // Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)). - curl_easy_request_w->setoptString(CURLOPT_ENCODING, ""); // CURLOPT_ACCEPT_ENCODING - } - mInput.reset(new LLBufferArray); mInput->setThreaded(true); mLastRead = NULL; @@ -1343,14 +1347,8 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w // Keep responder alive. mResponder = responder; - if (!post) - { - // Add extra headers. - for (std::vector::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) - { - curl_easy_request_w->addHeader((*iter).c_str()); - } - } + // Add extra headers. + curl_easy_request_w->addHeaders(headers); } //static @@ -1500,7 +1498,12 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request if (code == CURLE_OK) { curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode); - //AIFIXME: fill responseReason if (responseCode < 200 || responseCode >= 300). + // If getResult code is CURLE_OK then we should have decoded the first header line ourselves. + llassert(responseCode == mStatus); + if (responseCode == mStatus) + responseReason = mReason; + else + responseReason = "Unknown reason."; } else { diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 6a9728673..4cdf57c68 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "llpreprocessor.h" @@ -49,11 +50,12 @@ #define CURLOPT_DNS_USE_GLOBAL_CACHE do_not_use_CURLOPT_DNS_USE_GLOBAL_CACHE #include "stdtypes.h" // U32 -#include "lliopipe.h" // LLIOPipe::buffer_ptr_t #include "llatomic.h" // LLAtomicU32 #include "aithreadsafe.h" class LLSD; +class LLBufferArray; +class LLChannelDescriptors; //----------------------------------------------------------------------------- // Exceptions. @@ -76,6 +78,11 @@ class AICurlNoMultiHandle : public AICurlError { AICurlNoMultiHandle(std::string const& message) : AICurlError(message) { } }; +class AICurlNoBody : public AICurlError { + public: + AICurlNoBody(std::string const& message) : AICurlError(message) { } +}; + // End Exceptions. //----------------------------------------------------------------------------- @@ -147,6 +154,9 @@ void setCAPath(std::string const& file); // destructed too. // class Responder { + public: + typedef boost::shared_ptr buffer_ptr_t; + protected: Responder(void); virtual ~Responder(); @@ -169,7 +179,7 @@ class Responder { // Derived classes can override this to get the raw data of the body of the HTML message that was received. // The default is to interpret the content as LLSD and call completed(). - virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer); + virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); // Called from LLHTTPClient request calls, if an error occurs even before we can call one of the above. // It calls completed() with a fake status U32_MAX, as that is what some derived clients expect (bad design). @@ -272,13 +282,19 @@ typedef LLPointer AIPostFieldPtr; // AICurlEasyRequest: a thread safe, reference counting, auto-cleaning curl easy handle. class AICurlEasyRequest { - public: + private: + // Use AICurlEasyRequestStateMachine, not AICurlEasyRequest. + friend class AICurlEasyRequestStateMachine; + // Initial construction is allowed (thread-safe). // Note: If ThreadSafeCurlEasyRequest() throws then the memory allocated is still freed. // 'new' never returned however and neither the constructor nor destructor of mCurlEasyRequest is called in this case. // This might throw AICurlNoEasyHandle. AICurlEasyRequest(bool buffered) : mCurlEasyRequest(buffered ? new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest : new AICurlPrivate::ThreadSafeCurlEasyRequest) { } + + public: + // Used for storing this object in a standard container (see MultiHandle::add_easy_request). AICurlEasyRequest(AICurlEasyRequest const& orig) : mCurlEasyRequest(orig.mCurlEasyRequest) { } // For the rest, only allow read operations. diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index 8232effb1..26f4df884 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -34,6 +34,8 @@ #include #include "llatomic.h" +class AIHTTPHeaders; + namespace AICurlPrivate { namespace curlthread { class MultiHandle; } @@ -213,13 +215,14 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven // and the CurlEasyRequest destructed. class CurlEasyRequest : public CurlEasyHandle { private: - void setPost_raw(S32 size, char const* data); + void setPost_raw(U32 size, char const* data); public: - void setPost(S32 size) { setPost_raw(size, NULL); } - void setPost(AIPostFieldPtr const& postdata, S32 size); - void setPost(char const* data, S32 size) { setPost(new AIPostField(data), size); } + void setPost(U32 size) { setPost_raw(size, NULL); } + void setPost(AIPostFieldPtr const& postdata, U32 size); + void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } void setoptString(CURLoption option, std::string const& value); void addHeader(char const* str); + void addHeaders(AIHTTPHeaders const& headers); private: // Callback stubs. @@ -324,11 +327,13 @@ class CurlEasyRequest : public CurlEasyHandle { // is deleted and the CurlResponderBuffer destructed. class CurlResponderBuffer : protected AICurlEasyHandleEvents { public: - void resetState(AICurlEasyRequest_wat& curl_easy_request_w); - void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, std::vector const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0, bool post = false); + typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t; - LLIOPipe::buffer_ptr_t& getInput(void) { return mInput; } - LLIOPipe::buffer_ptr_t& getOutput(void) { return mOutput; } + void resetState(AICurlEasyRequest_wat& curl_easy_request_w); + void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0); + + buffer_ptr_t& getInput(void) { return mInput; } + buffer_ptr_t& getOutput(void) { return mOutput; } // Called if libcurl doesn't deliver within mRequestTimeOut seconds. void timed_out(void); @@ -346,9 +351,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); private: - LLIOPipe::buffer_ptr_t mInput; + buffer_ptr_t mInput; U8* mLastRead; // Pointer into mInput where we last stopped reading (or NULL to start at the beginning). - LLIOPipe::buffer_ptr_t mOutput; + buffer_ptr_t mOutput; AICurlInterface::ResponderPtr mResponder; //U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used. U32 mStatus; // HTTP status, decoded from the first header line. diff --git a/indra/aistatemachine/debug_libcurl.cpp b/indra/aistatemachine/debug_libcurl.cpp index 40b75d200..bacf78480 100644 --- a/indra/aistatemachine/debug_libcurl.cpp +++ b/indra/aistatemachine/debug_libcurl.cpp @@ -702,7 +702,11 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) { LibcwDoutStream << "NULL"; } - LibcwDoutStream << "](" << (is_postfield ? postfieldsize : size) << " bytes))"; + LibcwDoutStream << "]"; + if (str) + { + LibcwDoutStream << "(" << (is_postfield ? postfieldsize : size) << " bytes))"; + } } else { diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 31d025bb0..0c16e55de 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -227,7 +227,7 @@ public: #endif /** - * @breif filesize helpers. + * @brief filesize helpers. * * The file size helpers are not considered particularly efficient, * and should only be used for config files and the like -- not in a diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp index 6290a7158..9dcdaeff1 100644 --- a/indra/llcommon/llmemtype.cpp +++ b/indra/llcommon/llmemtype.cpp @@ -179,7 +179,6 @@ LLMemType::DeclareMemType LLMemType::MTYPE_IO_BUFFER("IoBuffer"); LLMemType::DeclareMemType LLMemType::MTYPE_IO_HTTP_SERVER("IoHttpServer"); LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_SERVER("IoSDServer"); LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_CLIENT("IoSDClient"); -LLMemType::DeclareMemType LLMemType::MTYPE_IO_URL_REQUEST("IOUrlRequest"); LLMemType::DeclareMemType LLMemType::MTYPE_DIRECTX_INIT("DirectXInit"); diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index 677fad303..413540d7c 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -223,7 +223,6 @@ public: static DeclareMemType MTYPE_IO_HTTP_SERVER; static DeclareMemType MTYPE_IO_SD_SERVER; static DeclareMemType MTYPE_IO_SD_CLIENT; - static DeclareMemType MTYPE_IO_URL_REQUEST; static DeclareMemType MTYPE_DIRECTX_INIT; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 030128b76..5e5010c64 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -315,7 +315,7 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg for(int i = 0; i < retries; ++i) { status_message = llformat("%s, try %d...", msg.c_str(), i+1); - LLHTTPClient::post(host, data, new LLCrashLoggerResponder(), timeout); + LLHTTPClient::post4(host, data, new LLCrashLoggerResponder(), timeout); while(!gBreak) { updateApplication(status_message); @@ -395,7 +395,6 @@ bool LLCrashLogger::init() } gServicePump = new LLPumpIO; - LLHTTPClient::setPump(*gServicePump); //If we've opened the crash logger, assume we can delete the marker file if it exists if( gDirUtilp ) diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index fe24dbc63..0c0650330 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories( ) set(llmessage_SOURCE_FILES + aihttpheaders.cpp llhttpclient.cpp llares.cpp llareslistener.cpp @@ -104,6 +105,7 @@ set(llmessage_SOURCE_FILES set(llmessage_HEADER_FILES CMakeLists.txt + aihttpheaders.h llares.h llareslistener.h llassetstorage.h diff --git a/indra/llmessage/aihttpheaders.cpp b/indra/llmessage/aihttpheaders.cpp new file mode 100644 index 000000000..1c6c6bc07 --- /dev/null +++ b/indra/llmessage/aihttpheaders.cpp @@ -0,0 +1,107 @@ +/** + * @file aihttpheaders.cpp + * @brief Implementation of AIHTTPHeaders + * + * Copyright (c) 2012, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 15/08/2012 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include "aihttpheaders.h" +#include +#ifdef DEBUG_CURLIO +#include "debug_libcurl.h" +#endif + +AIHTTPHeaders::AIHTTPHeaders(void) +{ +} + +AIHTTPHeaders::AIHTTPHeaders(std::string const& key, std::string const& value) : mContainer(new Container) +{ + addHeader(key, value); +} + +bool AIHTTPHeaders::addHeader(std::string const& key, std::string const& value, op_type op) +{ + if (!mContainer) + { + mContainer = new Container; + } + insert_t res = mContainer->mKeyValuePairs.insert(container_t::value_type(key, value)); + bool key_already_exists = !res.second; + if (key_already_exists) + { + llassert_always(op != new_header); + if (op == replace_if_exists) + res.first->second = value; + } + return key_already_exists; +} + +void AIHTTPHeaders::append_to(curl_slist*& slist) const +{ + if (!mContainer) + return; + container_t::const_iterator const end = mContainer->mKeyValuePairs.end(); + for (container_t::const_iterator iter = mContainer->mKeyValuePairs.begin(); iter != end; ++iter) + { + slist = curl_slist_append(slist, llformat("%s: %s", iter->first.c_str(), iter->second.c_str()).c_str()); + } +} + +bool AIHTTPHeaders::hasHeader(std::string const& key) const +{ + return !mContainer ? false : (mContainer->mKeyValuePairs.find(key) != mContainer->mKeyValuePairs.end()); +} + +bool AIHTTPHeaders::getValue(std::string const& key, std::string& value_out) const +{ + AIHTTPHeaders::container_t::const_iterator iter; + if (!mContainer || (iter = mContainer->mKeyValuePairs.find(key)) == mContainer->mKeyValuePairs.end()) + return false; + value_out = iter->second; + return true; +} + +std::ostream& operator<<(std::ostream& os, AIHTTPHeaders const& headers) +{ + os << '{'; + if (headers.mContainer) + { + bool first = true; + AIHTTPHeaders::container_t::const_iterator const end = headers.mContainer->mKeyValuePairs.end(); + for (AIHTTPHeaders::container_t::const_iterator iter = headers.mContainer->mKeyValuePairs.begin(); iter != end; ++iter) + { + if (!first) + os << ", "; + os << '"' << iter->first << ": " << iter->second << '"'; + first = false; + } + } + os << '}'; + return os; +} + diff --git a/indra/llmessage/aihttpheaders.h b/indra/llmessage/aihttpheaders.h new file mode 100644 index 000000000..671584f6c --- /dev/null +++ b/indra/llmessage/aihttpheaders.h @@ -0,0 +1,86 @@ +/** + * @file aihttpheaders.h + * @brief Keep a list of HTTP headers. + * + * Copyright (c) 2012, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 15/08/2012 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIHTTPHEADERS_H +#define AIHTTPHEADERS_H + +#include +#include +#include +#include "llpointer.h" +#include "llthread.h" // LLThreadSafeRefCount + +extern "C" struct curl_slist; + +class AIHTTPHeaders { + public: + enum op_type + { + new_header, // The inserted header must be the first one. + replace_if_exists, // If a header of this type already exists, replace it. Otherwise add the header. + keep_existing_header // If a header of this type already exists, do nothing. + }; + + // Construct an empty container. + AIHTTPHeaders(void); + + // Construct a container with a single header. + AIHTTPHeaders(std::string const& key, std::string const& value); + + // Add a header. Returns true if the header already existed. + bool addHeader(std::string const& key, std::string const& value, op_type op = new_header); + + // Return true if there are no headers associated with this object. + bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); } + + // Return true if the header already exists. + bool hasHeader(std::string const& key) const; + + // Return true if key exists and full value_out with the value. Return false otherwise. + bool getValue(std::string const& key, std::string& value_out) const; + + // Append the headers to slist. + void append_to(curl_slist*& slist) const; + + // For debug purposes. + friend std::ostream& operator<<(std::ostream& os, AIHTTPHeaders const& headers); + + private: + typedef std::map container_t; + typedef std::pair insert_t; + + struct Container : public LLThreadSafeRefCount { + container_t mKeyValuePairs; + }; + + LLPointer mContainer; +}; + +#endif // AIHTTPHEADERS_H diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 07d4854c4..5903af76a 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -382,7 +382,7 @@ void LLAvatarNameCache::requestNamesViaCapability() LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first " << ids << " ids" << LL_ENDL; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); + LLHTTPClient::get4(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } @@ -393,7 +393,7 @@ void LLAvatarNameCache::requestNamesViaCapability() LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all " << ids << " ids" << LL_ENDL; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); + LLHTTPClient::get4(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } diff --git a/indra/llmessage/llbufferstream.h b/indra/llmessage/llbufferstream.h index 19749612f..723269307 100644 --- a/indra/llmessage/llbufferstream.h +++ b/indra/llmessage/llbufferstream.h @@ -118,6 +118,17 @@ protected: //virtual streamsize xsputn(char* src, streamsize length); //@} +public: + /* + * @brief Return number of bytes in input channel. + */ + S32 count_in(void) const { return mBuffer->count(mChannels.in()); } + + /* + * @brief Return number of bytes in output channel. + */ + S32 count_out(void) const { return mBuffer->count(mChannels.out()); } + protected: // This channels we are working on. LLChannelDescriptors mChannels; @@ -144,6 +155,9 @@ public: LLBufferArray* buffer); ~LLBufferStream(); + S32 count_in(void) const { return mStreamBuf.count_in(); } + S32 count_out(void) const { return mStreamBuf.count_out(); } + protected: LLBufferStreamBuf mStreamBuf; }; diff --git a/indra/llmessage/llcurlrequest.cpp b/indra/llmessage/llcurlrequest.cpp index 3f40764fa..fffddcd46 100644 --- a/indra/llmessage/llcurlrequest.cpp +++ b/indra/llmessage/llcurlrequest.cpp @@ -43,6 +43,7 @@ #include "llcurlrequest.h" #include "llbufferstream.h" #include "aicurleasyrequeststatemachine.h" +#include "aihttpheaders.h" //----------------------------------------------------------------------------- // class Request @@ -50,12 +51,13 @@ namespace AICurlInterface { -bool Request::get(std::string const& url, ResponderPtr responder) +bool Request::get2(std::string const& url, ResponderPtr responder) { - return getByteRange(url, headers_t(), 0, -1, responder); + AIHTTPHeaders empty_headers; + return getByteRange2(url, empty_headers, 0, -1, responder); } -bool Request::getByteRange(std::string const& url, headers_t const& headers, S32 offset, S32 length, ResponderPtr responder) +bool Request::getByteRange2(std::string const& url, AIHTTPHeaders const& headers, S32 offset, S32 length, ResponderPtr responder) { DoutEntering(dc::curl, "Request::getByteRange(" << url << ", ...)"); @@ -63,7 +65,7 @@ bool Request::getByteRange(std::string const& url, headers_t const& headers, S32 AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true); { - AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); + AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); AICurlResponderBuffer_wat(*buffered_easy_request->mCurlEasyRequest)->prepRequest(buffered_easy_request_w, headers, responder); @@ -82,7 +84,7 @@ bool Request::getByteRange(std::string const& url, headers_t const& headers, S32 return true; // We throw in case of problems. } -bool Request::post(std::string const& url, headers_t const& headers, std::string const& data, ResponderPtr responder, S32 time_out) +bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder, S32 time_out) { DoutEntering(dc::curl, "Request::post(" << url << ", ...)"); @@ -97,14 +99,14 @@ bool Request::post(std::string const& url, headers_t const& headers, std::string U32 bytes = data.size(); bool success = buffer_w->getInput()->append(buffer_w->sChannels.out(), (U8 const*)data.data(), bytes); - llassert_always(success); // AIFIXME: Maybe throw an error. if (!success) - return false; + { + buffered_easy_request->kill(); + throw AICurlNoBody("LLBufferArray::copyIntoBuffers() returned false"); + } buffered_easy_request_w->setPost(bytes); buffered_easy_request_w->addHeader("Content-Type: application/octet-stream"); buffered_easy_request_w->finalizeRequest(url); - - lldebugs << "POSTING: " << bytes << " bytes." << llendl; } buffered_easy_request->run(); @@ -112,7 +114,7 @@ bool Request::post(std::string const& url, headers_t const& headers, std::string return true; // We throw in case of problems. } -bool Request::post(std::string const& url, headers_t const& headers, LLSD const& data, ResponderPtr responder, S32 time_out) +bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder, S32 time_out) { DoutEntering(dc::curl, "Request::post(" << url << ", ...)"); diff --git a/indra/llmessage/llcurlrequest.h b/indra/llmessage/llcurlrequest.h index d10c20b98..54bdb35ed 100644 --- a/indra/llmessage/llcurlrequest.h +++ b/indra/llmessage/llcurlrequest.h @@ -35,6 +35,8 @@ #include #include +class AIHTTPHeaders; + // Things defined in this namespace are called from elsewhere in the viewer code. namespace AICurlInterface { @@ -44,12 +46,10 @@ typedef boost::intrusive_ptr ResponderPtr; class Request { public: - typedef std::vector headers_t; - - bool get(std::string const& url, ResponderPtr responder); - bool getByteRange(std::string const& url, headers_t const& headers, S32 offset, S32 length, ResponderPtr responder); - bool post(std::string const& url, headers_t const& headers, std::string const& data, ResponderPtr responder, S32 time_out = 0); - bool post(std::string const& url, headers_t const& headers, LLSD const& data, ResponderPtr responder, S32 time_out = 0); + bool get2(std::string const& url, ResponderPtr responder); + bool getByteRange2(std::string const& url, AIHTTPHeaders const& headers, S32 offset, S32 length, ResponderPtr responder); + bool post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder, S32 time_out = 0); + bool post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder, S32 time_out = 0); }; } // namespace AICurlInterface diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index debaad19d..da5ad61af 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -25,191 +25,162 @@ */ #include "linden_common.h" -#include "llhttpclient.h" -#include "llassetstorage.h" -#include "lliopipe.h" -#include "llurlrequest.h" +#include + +#include "llhttpclient.h" #include "llbufferstream.h" #include "llsdserialize.h" #include "llvfile.h" -#include "llvfs.h" -#include "lluri.h" -#include "llpumpio.h" // LLPumpIO::chain_t +#include "llurlrequest.h" -#include "message.h" - -const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; -#ifdef AI_UNUSED -#endif // AI_UNUSED +F32 const HTTP_REQUEST_EXPIRY_SECS = 60.0f; //////////////////////////////////////////////////////////////////////////// -// Responder class moved to LLCurl - -namespace -{ #if 0 - class LLHTTPClientURLAdaptor : public LLURLRequestComplete +class LLHTTPClientURLAdaptor : public LLURLRequestComplete +{ +public: + LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder) + : LLURLRequestComplete(), mResponder(responder), mStatus(499), + mReason("LLURLRequest complete w/no status") { - public: - LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder) - : LLURLRequestComplete(), mResponder(responder), mStatus(499), - mReason("LLURLRequest complete w/no status") - { - } - - ~LLHTTPClientURLAdaptor() - { - } + } + + ~LLHTTPClientURLAdaptor() + { + } - virtual void httpStatus(U32 status, const std::string& reason) - { - LLURLRequestComplete::httpStatus(status,reason); + virtual void httpStatus(U32 status, const std::string& reason) + { + LLURLRequestComplete::httpStatus(status,reason); - mStatus = status; - mReason = reason; - } + mStatus = status; + mReason = reason; + } - virtual void complete(const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) + virtual void complete(const LLChannelDescriptors& channels, + const buffer_ptr_t& buffer) + { + if (mResponder.get()) { - if (mResponder.get()) - { - // Allow clients to parse headers before we attempt to parse - // the body and provide completed/result/error calls. - mResponder->completedHeader(mStatus, mReason, mHeaderOutput); - mResponder->completedRaw(mStatus, mReason, channels, buffer); - } - } - virtual void header(const std::string& header, const std::string& value) - { - mHeaderOutput[header] = value; + // Allow clients to parse headers before we attempt to parse + // the body and provide completed/result/error calls. + mResponder->completedHeader(mStatus, mReason, mHeaderOutput); + mResponder->completedRaw(mStatus, mReason, channels, buffer); } + } + virtual void header(const std::string& header, const std::string& value) + { + mHeaderOutput[header] = value; + } - private: - LLCurl::ResponderPtr mResponder; - U32 mStatus; - std::string mReason; - LLSD mHeaderOutput; - }; +private: + LLCurl::ResponderPtr mResponder; + U32 mStatus; + std::string mReason; + LLSD mHeaderOutput; +}; #endif - class Injector : public LLIOPipe +class LLSDInjector : public Injector +{ + public: + LLSDInjector(LLSD const& sd) : mSD(sd) { } + + /*virtual*/ char const* contentType(void) const { return "application/llsd+xml"; } + + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { - public: - virtual const char* contentType() = 0; - }; + LLBufferStream ostream(channels, buffer.get()); + LLSDSerialize::toXML(mSD, ostream); + //AIFIXME: remove this + llassert(ostream.count_out() > 0 && ostream.count_in() == 0); + return ostream.count_out(); + } - class LLSDInjector : public Injector + LLSD const mSD; +}; + +class RawInjector : public Injector +{ + public: + RawInjector(char const* data, U32 size) : mData(data), mSize(size) { } + /*virtual*/ ~RawInjector() { delete [] mData; } + + /*virtual*/ char const* contentType(void) const { return "application/octet-stream"; } + + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { - public: - LLSDInjector(const LLSD& sd) : mSD(sd) {} - virtual ~LLSDInjector() {} + LLBufferStream ostream(channels, buffer.get()); + ostream.write(mData, mSize); + return mSize; + } - const char* contentType() { return "application/llsd+xml"; } + char const* mData; + U32 mSize; +}; - 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; - } +class FileInjector : public Injector +{ + public: + FileInjector(std::string const& filename) : mFilename(filename) { } - const LLSD mSD; - }; + char const* contentType(void) const { return "application/octet-stream"; } - class RawInjector : public Injector + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { - public: - RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {} - virtual ~RawInjector() {delete [] mData;} + LLBufferStream ostream(channels, buffer.get()); - const char* contentType() { return "application/octet-stream"; } + llifstream fstream(mFilename, std::iostream::binary | std::iostream::out); + if (!fstream.is_open()) + throw AICurlNoBody(llformat("Failed to open \"%s\".", mFilename.c_str())); - 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; - } + fstream.seekg(0, std::ios::end); + U32 fileSize = fstream.tellg(); + fstream.seekg(0, std::ios::beg); + std::vector fileBuffer(fileSize); + fstream.read(&fileBuffer[0], fileSize); + ostream.write(&fileBuffer[0], fileSize); + fstream.close(); - const U8* mData; - S32 mSize; - }; - - class FileInjector : public Injector + return fileSize; + } + + std::string const mFilename; +}; + +class VFileInjector : public Injector +{ +public: + VFileInjector(LLUUID const& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) { } + + /*virtual*/ char const* contentType(void) const { return "application/octet-stream"; } + + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { - public: - FileInjector(const std::string& filename) : mFilename(filename) {} - virtual ~FileInjector() {} + LLBufferStream ostream(channels, buffer.get()); + + LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ); + S32 fileSize = vfile.getSize(); + std::vector fileBuffer(fileSize); + vfile.read(&fileBuffer[0], fileSize); + ostream.write((char*)&fileBuffer[0], fileSize); + + return fileSize; + } - const char* contentType() { return "application/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, std::iostream::binary | std::iostream::out); - if(fstream.is_open()) - { - fstream.seekg(0, std::ios::end); - U32 fileSize = fstream.tellg(); - fstream.seekg(0, std::ios::beg); - std::vector 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 char* contentType() { return "application/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(); - std::vector fileBuffer(fileSize); - vfile.read(&fileBuffer[0], fileSize); - ostream.write((char*)&fileBuffer[0], fileSize); - eos = true; - return STATUS_DONE; - } - - const LLUUID mUUID; - LLAssetType::EType mAssetType; - }; - - LLPumpIO* theClientPump = NULL; -} + LLUUID const mUUID; + LLAssetType::EType mAssetType; +}; static void request( const std::string& url, LLURLRequest::ERequestAction method, Injector* body_injector, LLCurl::ResponderPtr responder, - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, - const LLSD& headers = LLSD()) + AIHTTPHeaders& headers, + F32 timeout = HTTP_REQUEST_EXPIRY_SECS) { if (responder) { @@ -217,17 +188,10 @@ static void request( responder->setURL(url); } - if (!LLHTTPClient::hasPump()) - { - responder->fatalError("No pump"); - return; - } - LLPumpIO::chain_t chain; - LLURLRequest* req; try { - req = new LLURLRequest(method, url); + req = new LLURLRequest(method, url, body_injector, responder, headers); } catch(AICurlNoEasyHandle& error) { @@ -236,140 +200,40 @@ static void request( return ; } - req->checkRootCertificate(true); - - lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " << headers << llendl; - - // Insert custom headers if the caller sent any. - - std::vector headers_vector; - bool has_content_type = false; - bool has_accept = false; - - // Note that headers always is a map, unless no argument was passed. - if (headers.isMap()) - { - if (headers.has("Cookie")) - { - req->allowCookies(); - } - - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator const 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. - if (iter->first.compare("Pragma") == 0 && iter->second.asString().empty()) - { - req->useProxy(false); - } - if (iter->first.compare("Content-Type") == 0) - { - has_content_type = true; - } - if (iter->first.compare("Accept") == 0) - { - has_accept = true; - } - - std::ostringstream header; - header << iter->first << ": " << iter->second.asString(); - headers_vector.push_back(header.str()); - } - } - - if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) - { - if (!has_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. - headers_vector.push_back(llformat("Content-Type: %s", body_injector->contentType())); - } - } - else - { - // 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 (!has_accept) - { - headers_vector.push_back("Accept: application/llsd+xml"); - } - } - if (method == LLURLRequest::HTTP_POST && gMessageSystem) - { - headers_vector.push_back(llformat("X-SecondLife-UDP-Listen-Port: %d", gMessageSystem->mPort)); - } - - if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) - { - //AIFIXME: - chain.push_back(LLIOPipe::ptr_t(body_injector)); - } - - //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req)); - - AICurlEasyRequest_wat buffered_easy_request_w(*req->mCurlEasyRequest); - AICurlResponderBuffer_wat buffer_w(*req->mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, headers_vector, responder); - req->setRequestTimeOut(timeout); - //AIFIXME: theClientPump->addChain(chain, timeout); + req->run(); } - -void LLHTTPClient::getByteRange( - const std::string& url, - S32 offset, - S32 bytes, - ResponderPtr responder, - const LLSD& hdrs, - const F32 timeout) +void LLHTTPClient::getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - LLSD headers = hdrs; if(offset > 0 || bytes > 0) { - std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1); - headers["Range"] = range; + headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1)); } - request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers); + request(url, LLURLRequest::HTTP_GET, NULL, responder, headers, timeout); } -void LLHTTPClient::head( - const std::string& url, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers); + request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers, timeout); } -void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout) +void LLHTTPClient::get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers); -} -void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout) -{ - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers); -} -void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout) -{ - getHeaderOnly(url, responder, LLSD(), timeout); + request(url, LLURLRequest::HTTP_GET, NULL, responder, headers, timeout); } -void LLHTTPClient::get(const std::string& url, const LLSD& query, ResponderPtr responder, const LLSD& headers, const F32 timeout) +void LLHTTPClient::getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +{ + request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers, timeout); +} + +void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { LLURI uri; uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query); - get(uri.asString(), responder, headers, timeout); + get4(uri.asString(), responder, headers, timeout); } // A simple class for managing data returned from a curl http request. @@ -426,18 +290,18 @@ private: @returns an LLSD map: {status: integer, body: map} */ static LLSD blocking_request( - const std::string& url, + std::string const& url, LLURLRequest::ERequestAction method, - const LLSD& body, - const LLSD& headers = LLSD(), - const F32 timeout = 5 -) + LLSD const& body, + AIHTTPHeaders& headers, + F32 timeout = 5) { lldebugs << "blockingRequest of " << url << llendl; S32 http_status = 499; LLSD response = LLSD::emptyMap(); +#if 0 // AIFIXME: rewrite to use AICurlEasyRequestStateMachine try { AICurlEasyRequest easy_request(false); @@ -508,6 +372,7 @@ static LLSD blocking_request( { response["body"] = error.what(); } +#endif response["status"] = http_status; return response; @@ -515,104 +380,50 @@ static LLSD blocking_request( LLSD LLHTTPClient::blockingGet(const std::string& url) { - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD()); + AIHTTPHeaders empty_headers; + return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers); } LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { - return blocking_request(url, LLURLRequest::HTTP_POST, body); + AIHTTPHeaders empty_headers; + return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers); } -void LLHTTPClient::put( - const std::string& url, - const LLSD& body, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); + request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers, timeout); } -void LLHTTPClient::post( - const std::string& url, - const LLSD& body, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers); + request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers, timeout); } -void LLHTTPClient::postRaw( - const std::string& url, - const U8* data, - S32 size, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::postRaw4(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers); + request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers, timeout); } -void LLHTTPClient::postFile( - const std::string& url, - const std::string& filename, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers); + request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers, timeout); } -void LLHTTPClient::postFile( - const std::string& url, - const LLUUID& uuid, - LLAssetType::EType asset_type, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::postFile4(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers); + request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers, timeout); } // static -void LLHTTPClient::del( - const std::string& url, - ResponderPtr responder, - const LLSD& headers, - const F32 timeout) +void LLHTTPClient::del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers); + request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers, timeout); } // static -void LLHTTPClient::move( - const std::string& url, - const std::string& destination, - ResponderPtr responder, - const LLSD& hdrs, - const F32 timeout) +void LLHTTPClient::move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) { - LLSD headers = hdrs; - headers["Destination"] = destination; - request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers); -} - - -//static -void LLHTTPClient::setPump(LLPumpIO& pump) -{ - theClientPump = &pump; -} - -//static -bool LLHTTPClient::hasPump() -{ - return theClientPump != NULL; -} - -//static -LLPumpIO& LLHTTPClient::getPump() -{ - return *theClientPump; + headers.addHeader("Destination", destination); + request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers, timeout); } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index e49a4a66b..0f8cca0be 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -33,23 +33,19 @@ #include -#include #include "llassettype.h" #include "llcurl.h" -#include "lliopipe.h" +#include "aihttpheaders.h" -extern const F32 HTTP_REQUEST_EXPIRY_SECS; +extern F32 const 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; @@ -59,57 +55,51 @@ public: /** @name non-blocking API */ //@{ - static void head( - const std::string& url, - ResponderPtr, - const LLSD& headers = LLSD(), - const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); - static void getByteRange(const std::string& url, S32 offset, S32 bytes, ResponderPtr, const LLSD& headers=LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); - static void get(const std::string& url, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); - static void get(const std::string& url, const LLSD& query, ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + static void head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void head4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; head4(url, responder, headers, timeout); } - static void put( - const std::string& url, - const LLSD& body, - ResponderPtr, - const LLSD& headers = LLSD(), - const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); - static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); - static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; getByteRange4(url, offset, bytes, responder, headers, timeout); } + + static void get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void get4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; get4(url, responder, headers, timeout); } + + static void get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void get4(std::string const& url, LLSD const& query, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; get4(url, query, responder, headers, timeout); } + + static void put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void put4(std::string const& url, LLSD const& body, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; put4(url, body, responder, headers, timeout); } + + static void getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void getHeaderOnly4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; getHeaderOnly4(url, responder, headers, timeout); } + + static void post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void post4(std::string const& url, LLSD const& body, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; post4(url, body, responder, headers, timeout); } - 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 postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; postRaw4(url, data, size, responder, headers, timeout); } + + static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; postFile4(url, filename, responder, headers, timeout); } + + static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; postFile4(url, uuid, asset_type, responder, headers, timeout); } + + static void del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void del4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; del4(url, responder, headers, timeout); } - 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++ /** @@ -121,12 +111,9 @@ public: * @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); + static void move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); + static void move4(std::string const& url, std::string const& destination, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + { AIHTTPHeaders headers; move4(url, destination, responder, headers, timeout); } //@} @@ -136,7 +123,7 @@ public: * @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); + static LLSD blockingGet(std::string const& url); /** * @brief Blocking HTTP POST that returns an LLSD map of status and body. @@ -145,17 +132,7 @@ public: * @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(); - ///< for testing - static LLPumpIO &getPump(); - ///< Hippo special -#ifdef AI_UNUSED -#endif // AI_UNUSED + static LLSD blockingPost(std::string const& url, LLSD const& body); }; #endif // LL_LLHTTPCLIENT_H diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index f5d7a9abb..d1c42a665 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -33,23 +33,21 @@ 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 turnning off proxying - empty_pragma_header["Pragma"] = " "; - LLHTTPClient::get(url, responder, empty_pragma_header); + AIHTTPHeaders empty_pragma_header("Pragma", " "); + LLHTTPClient::get4(url, responder, empty_pragma_header); } void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) { - LLSD empty_pragma_header = headers; // as above - empty_pragma_header["Pragma"] = " "; - LLHTTPClient::get(url, responder, empty_pragma_header); + AIHTTPHeaders empty_pragma_header("Pragma", " "); + LLHTTPClient::get4(url, responder, empty_pragma_header); } void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) { - LLHTTPClient::put(url, body, responder); + LLHTTPClient::put4(url, body, responder); } diff --git a/indra/llmessage/llhttpsender.cpp b/indra/llmessage/llhttpsender.cpp index c48cbc42a..195548abe 100644 --- a/indra/llmessage/llhttpsender.cpp +++ b/indra/llmessage/llhttpsender.cpp @@ -55,7 +55,7 @@ void LLHTTPSender::send(const LLHost& host, const std::string& name, std::ostringstream stream; stream << "http://" << host << "/trusted-message/" << name; llinfos << "LLHTTPSender::send: POST to " << stream.str() << llendl; - LLHTTPClient::post(stream.str(), body, response); + LLHTTPClient::post4(stream.str(), body, response); } //static diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 67da908b7..a46c2835f 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -83,11 +83,10 @@ bool LLSDMessage::httpListener(const LLSD& request) { timeout = HTTP_REQUEST_EXPIRY_SECS; } - LLHTTPClient::post(url, payload, + LLHTTPClient::post4(url, payload, new LLSDMessage::EventResponder(LLEventPumps::instance(), request, url, "POST", reply, error), - LLSD(), // headers (F32)timeout); return false; } diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 16a973d2e..af22a1722 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -46,6 +46,7 @@ #include "llapr.h" #include "llscopedvolatileaprpool.h" #include "llfasttimer.h" +#include "message.h" static const U32 HTTP_STATUS_PIPE_ERROR = 499; /** @@ -112,10 +113,75 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) } // This might throw AICurlNoEasyHandle. -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url) : AICurlEasyRequestStateMachine(true), mAction(action), mURL(url) +LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers) : + AICurlEasyRequestStateMachine(true), mAction(action), mURL(url), mBody(body), mResponder(responder), mHeaders(headers) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); - run(); +} + +void LLURLRequest::initialize_impl(void) +{ + if (mHeaders.hasHeader("Cookie")) + { + allowCookies(); + } + + // 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. + std::string pragma_value; + if (mHeaders.getValue("Pragma", pragma_value) && pragma_value.empty()) + { + useProxy(false); + } + + if (mAction == HTTP_PUT || mAction == HTTP_POST) + { + // If the Content-Type header was passed in we defer to the caller's wisdom, + // but if they did not specify a Content-Type, then ask the injector. + mHeaders.addHeader("Content-Type", mBody->contentType(), AIHTTPHeaders::keep_existing_header); + } + else + { + // 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. + mHeaders.addHeader("Accept", "application/llsd+xml", AIHTTPHeaders::keep_existing_header); + } + + if (mAction == HTTP_POST && gMessageSystem) + { + mHeaders.addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", gMessageSystem->mPort)); + } + + bool success = false; + try + { + AICurlEasyRequest_wat buffered_easy_request_w(*mCurlEasyRequest); + AICurlResponderBuffer_wat buffer_w(*mCurlEasyRequest); + buffer_w->prepRequest(buffered_easy_request_w, mHeaders, mResponder); + + if (mBody) + { + // This might throw AICurlNoBody. + mBodySize = mBody->get_body(buffer_w->sChannels, buffer_w->getInput()); + } + + success = configure(buffered_easy_request_w); + } + catch (AICurlNoBody const& error) + { + llwarns << "Injector::get_body() failed: " << error.what() << llendl; + } + + if (success) + { + // Continue to initialize base class. + AICurlEasyRequestStateMachine::initialize_impl(); + } + else + { + abort(); + } } #if 0 @@ -132,18 +198,10 @@ std::string LLURLRequest::getURL2() const void LLURLRequest::addHeader(const char* header) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->addHeader(header); } -void LLURLRequest::checkRootCertificate(bool check) -{ - AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); - curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, check ? 1L : 0L); - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, ""); -} - #ifdef AI_UNUSED void LLURLRequest::setBodyLimit(U32 size) { @@ -153,7 +211,6 @@ void LLURLRequest::setBodyLimit(U32 size) void LLURLRequest::setCallback(LLURLRequestComplete* callback) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); mCompletionCallback = callback; AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->setHeaderCallback(&headerCallback, (void*)callback); @@ -237,7 +294,6 @@ LLIOPipe::EStatus LLURLRequest::handleError( LLPumpIO* pump) { DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ")"); - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); if (LL_LIKELY(!mDetail->mStateMachine->isBuffered())) // Currently always true. { @@ -283,12 +339,12 @@ LLIOPipe::EStatus LLURLRequest::process_impl( { LLFastTimer t(FTM_PROCESS_URL_REQUEST); PUMP_DEBUG; - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); //llinfos << "LLURLRequest::process_impl()" << llendl; if (!buffer) return STATUS_ERROR; if (!mDetail) return STATUS_ERROR; //Seems to happen on occasion. Need to hunt down why. + //AIFIXME: implement this again: // we're still waiting or processing, check how many // bytes we have accumulated. const S32 MIN_ACCUMULATION = 100000; @@ -433,22 +489,10 @@ LLIOPipe::EStatus LLURLRequest::process_impl( } #endif // AI_UNUSED -S32 LLURLRequest::bytes_to_send(void) const +bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) { - //AIFIXME: how to get the number of bytes to send? - llassert_always(false); - return 0; -} - -static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure"); -bool LLURLRequest::configure() -{ - LLFastTimer t(FTM_URL_REQUEST_CONFIGURE); - - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); bool rv = false; { - AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); switch(mAction) { case HTTP_HEAD: @@ -472,20 +516,15 @@ bool LLURLRequest::configure() // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. curlEasyRequest_w->addHeader("Expect:"); - S32 bytes = bytes_to_send(); curlEasyRequest_w->setopt(CURLOPT_UPLOAD, 1); - curlEasyRequest_w->setopt(CURLOPT_INFILESIZE, bytes); + curlEasyRequest_w->setopt(CURLOPT_INFILESIZE, mBodySize); rv = true; break; } case HTTP_POST: { // Set the handle for an http post - S32 bytes = bytes_to_send(); - curlEasyRequest_w->setPost(bytes); - - // Set Accept-Encoding to allow response compression - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, ""); + curlEasyRequest_w->setPost(mBodySize); rv = true; break; } @@ -498,7 +537,6 @@ bool LLURLRequest::configure() case HTTP_MOVE: // Set the handle for an http post curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE"); - // *NOTE: should we check for the Destination header? rv = true; break; @@ -522,7 +560,6 @@ size_t LLURLRequest::downCallback( size_t nmemb, void* user) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); LLURLRequest* req = (LLURLRequest*)user; if(STATE_WAITING_FOR_RESPONSE == req->mState) { @@ -558,7 +595,6 @@ size_t LLURLRequest::upCallback( size_t nmemb, void* user) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); LLURLRequest* req = (LLURLRequest*)user; S32 bytes = llmin( (S32)(size * nmemb), @@ -649,13 +685,11 @@ static size_t headerCallback(char* header_line, size_t size, size_t nmemb, void* LLURLRequestComplete::LLURLRequestComplete() : mRequestStatus(LLIOPipe::STATUS_ERROR) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); } // virtual LLURLRequestComplete::~LLURLRequestComplete() { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); } //virtual @@ -694,7 +728,6 @@ void LLURLRequestComplete::noResponse() void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status) { - LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); mRequestStatus = status; } diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index e35a7ec71..1c078b907 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -37,6 +37,15 @@ #include #include "aicurleasyrequeststatemachine.h" +#include "aihttpheaders.h" + +class Injector +{ + public: + typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t; + virtual char const* contentType(void) const = 0; + virtual U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) = 0; +}; class LLURLRequest : public AICurlEasyRequestStateMachine { public: @@ -66,7 +75,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { * @param action One of the ERequestAction enumerations. * @param url The url of the request. It should already be encoded. */ - LLURLRequest(ERequestAction action, std::string const& url); + LLURLRequest(ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers); /** * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE. @@ -89,33 +98,27 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { */ void addHeader(char const* 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 checkRootCertificate(bool check); - private: /** * @brief Handle action specific url request configuration. * * @return Returns true if this is configured. */ - bool configure(void); - - /** - * @ brief Return the number of bytes to POST or PUT to the server. - * - * @return Returns the number of bytes we're about to upload. - */ - S32 bytes_to_send(void) const; + bool configure(AICurlEasyRequest_wat const& curlEasyRequest_w); private: ERequestAction mAction; std::string mURL; + Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT. + U32 mBodySize; + AICurlInterface::ResponderPtr mResponder; + AIHTTPHeaders mHeaders; + + protected: + // Handle initializing the object. + /*virtual*/ void initialize_impl(void); }; + #if 0 extern const std::string CONTEXT_REQUEST; extern const std::string CONTEXT_RESPONSE; diff --git a/indra/newview/floatervoicelicense.cpp b/indra/newview/floatervoicelicense.cpp index 753c4bee6..fd9a7a649 100644 --- a/indra/newview/floatervoicelicense.cpp +++ b/indra/newview/floatervoicelicense.cpp @@ -130,7 +130,7 @@ BOOL FloaterVoiceLicense::postBuild() std::string url = getString( "real_url" ); if(url.substr(0,4) == "http") { gResponsePtr = LLIamHereVoice::build( this ); - LLHTTPClient::get( url, gResponsePtr ); + LLHTTPClient::get4( url, gResponsePtr ); } else { setSiteIsAlive(false); } diff --git a/indra/newview/hgfloatertexteditor.cpp b/indra/newview/hgfloatertexteditor.cpp index 12342b4ba..61ea390bf 100644 --- a/indra/newview/hgfloatertexteditor.cpp +++ b/indra/newview/hgfloatertexteditor.cpp @@ -364,7 +364,7 @@ void HGFloaterTextEditor::onClickSave(void* user_data) if(caps) { - LLHTTPClient::post(url, body, + LLHTTPClient::post4(url, body, new LLUpdateAgentInventoryResponder(body, fake_asset_id, item->getType())); } } diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp index 71228bee1..9d65dc987 100644 --- a/indra/newview/hipporestrequest.cpp +++ b/indra/newview/hipporestrequest.cpp @@ -13,7 +13,6 @@ #include "llhttpclient.h" #include "llurlrequest.h" #include "llxmltree.h" -#include "llpumpio.h" // LLPumpIO::chain_t #include #ifdef DEBUG_CURLIO @@ -136,40 +135,25 @@ void HippoRestHandlerXml::handle(int status, const std::string &reason, // ******************************************************************** - -class BodyData : public LLIOPipe +class BodyDataRaw : public Injector { public: - virtual ~BodyData() { } - virtual const char *getContentMimeType() const = 0; -}; - -class BodyDataRaw : public BodyData -{ - public: - explicit BodyDataRaw(const std::string &data) : - mData(data) - { - } - virtual ~BodyDataRaw() { } + explicit BodyDataRaw(const std::string &data) : mData(data) { } - const char *getContentMimeType() const { return "application/octet-stream"; } + /*virtual*/ char const* contentType(void) const { return "application/octet-stream"; } - EStatus process_impl(const LLChannelDescriptors &channels, - buffer_ptr_t &buffer, bool &eos, - LLSD &context, LLPumpIO *pump) + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { LLBufferStream ostream(channels, buffer.get()); ostream.write(mData.data(), mData.size()); - eos = true; - return STATUS_DONE; + return mData.size(); } private: std::string mData; }; -class BodyDataXml : public BodyData +class BodyDataXml : public Injector { public: explicit BodyDataXml(const LLXmlTree *tree) : @@ -182,18 +166,15 @@ class BodyDataXml : public BodyData if (mTree) delete mTree; } - const char *getContentMimeType() const { return "application/xml"; } + /*virtual*/ char const* contentType(void) const { return "application/xml"; } - EStatus process_impl(const LLChannelDescriptors &channels, - buffer_ptr_t &buffer, bool &eos, - LLSD &context, LLPumpIO *pump) + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { std::string data; mTree->write(data); LLBufferStream ostream(channels, buffer.get()); ostream.write(data.data(), data.size()); - eos = true; - return STATUS_DONE; + return data.size(); } private: @@ -206,40 +187,40 @@ class BodyDataXml : public BodyData static void request(const std::string &url, LLURLRequest::ERequestAction method, - BodyData *body, + Injector *body, HippoRestHandler *handler, float timeout); // static -void HippoRestRequest::get(const std::string &url, +void HippoRestRequest::get5(const std::string &url, HippoRestHandler *handler, float timeout) { request(url, LLURLRequest::HTTP_GET, 0, handler, timeout); } // static -void HippoRestRequest::put(const std::string &url, const std::string &body, +void HippoRestRequest::put5(const std::string &url, const std::string &body, HippoRestHandler *handler, float timeout) { request(url, LLURLRequest::HTTP_PUT, new BodyDataRaw(body), handler, timeout); } // static -void HippoRestRequest::put(const std::string &url, const LLXmlTree *body, +void HippoRestRequest::put5(const std::string &url, const LLXmlTree *body, HippoRestHandler *handler, float timeout) { request(url, LLURLRequest::HTTP_PUT, new BodyDataXml(body), handler, timeout); } // static -void HippoRestRequest::post(const std::string &url, const std::string &body, +void HippoRestRequest::post5(const std::string &url, const std::string &body, HippoRestHandler *handler, float timeout) { request(url, LLURLRequest::HTTP_POST, new BodyDataRaw(body), handler, timeout); } // static -void HippoRestRequest::post(const std::string &url, const LLXmlTree *body, +void HippoRestRequest::post5(const std::string &url, const LLXmlTree *body, HippoRestHandler *handler, float timeout) { request(url, LLURLRequest::HTTP_POST, new BodyDataXml(body), handler, timeout); @@ -251,27 +232,21 @@ void HippoRestRequest::post(const std::string &url, const LLXmlTree *body, static void request(const std::string &url, LLURLRequest::ERequestAction method, - BodyData *body, + Injector *body, HippoRestHandler *handler, float timeout) { - if (!LLHTTPClient::hasPump()) - { - // !!! responder->completed(U32_MAX, "No pump", LLSD()); - return; - } - LLPumpIO::chain_t chain; - LLURLRequest *req; try { - req = new LLURLRequest(method, url); + AIHTTPHeaders empty_headers; + //AIFIXME (doesn't compile): req = new LLURLRequest(method, url, body, handler, empty_headers); } catch(AICurlNoEasyHandle const& error) { llwarns << "Failed to create LLURLRequest: " << error.what() << llendl; return; } - req->checkRootCertificate(true); + // Already done by default. req->checkRootCertificate(true); /* // Insert custom headers if the caller sent any @@ -310,13 +285,13 @@ static void request(const std::string &url, if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) { std::string content = "Content-Type: "; - content += body->getContentMimeType(); + content += body->contentType(); req->addHeader(content.c_str()); - chain.push_back(LLIOPipe::ptr_t(body)); + //AIFIXME: chain.push_back(LLIOPipe::ptr_t(body)); } //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req)); - LLHTTPClient::getPump().addChain(chain, timeout); + //LLHTTPClient::getPump().addChain(chain, timeout); } diff --git a/indra/newview/hipporestrequest.h b/indra/newview/hipporestrequest.h index 727dbf733..99f85929c 100644 --- a/indra/newview/hipporestrequest.h +++ b/indra/newview/hipporestrequest.h @@ -1,7 +1,6 @@ #ifndef __HIPPO_REST_REQUEST_H__ #define __HIPPO_REST_REQUEST_H__ - #include #include @@ -11,12 +10,9 @@ class LLBufferArray; class LLChannelDescriptors; class LLXmlTree; - #define HIPPO_REST_TIMEOUT 60.f - // ******************************************************************** - class HippoRestHandler { @@ -40,7 +36,6 @@ class HippoRestHandler friend class HippoRestComplete; }; - class HippoRestHandlerRaw : public HippoRestHandler { public: @@ -59,7 +54,6 @@ class HippoRestHandlerRaw : public HippoRestHandler const boost::shared_ptr &body); }; - class HippoRestHandlerXml : public HippoRestHandler { public: @@ -77,28 +71,25 @@ class HippoRestHandlerXml : public HippoRestHandler const boost::shared_ptr &body); }; - // ******************************************************************** - class HippoRestRequest { public: // asynchronous interface - static void get(const std::string &url, + static void get5(const std::string &url, HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void put(const std::string &url, const std::string &body, + static void put5(const std::string &url, const std::string &body, HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void put(const std::string &url, const LLXmlTree *body, + static void put5(const std::string &url, const LLXmlTree *body, HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void post(const std::string &url, const std::string &body, + static void post5(const std::string &url, const std::string &body, HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void post(const std::string &url, const LLXmlTree *body, + static void post5(const std::string &url, const LLXmlTree *body, HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); // synchronous interface static int getBlocking(const std::string &url, std::string *result); }; - #endif diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index 03a83aff0..cc3e49c39 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -59,7 +59,7 @@ public: U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + const buffer_ptr_t& buffer); private: lggDicDownloadFloater* panel; std::string name; @@ -131,8 +131,8 @@ void lggDicDownloadFloater::onClickDownload(void* data) if (!comboBox->getSelectedItemLabel().empty()) { std::string newDict(self->sNames[comboBox->getCurrentIndex()]); - LLHTTPClient::get(gSavedSettings.getString("SpellDownloadURL")+newDict+".aff", new EmeraldDicDownloader(self,newDict+".aff")); - LLHTTPClient::get(gSavedSettings.getString("SpellDownloadURL")+newDict+".dic", new EmeraldDicDownloader(NULL,newDict+".dic")); + LLHTTPClient::get4(gSavedSettings.getString("SpellDownloadURL")+newDict+".aff", new EmeraldDicDownloader(self,newDict+".aff")); + LLHTTPClient::get4(gSavedSettings.getString("SpellDownloadURL")+newDict+".dic", new EmeraldDicDownloader(NULL,newDict+".dic")); LLButton* button = self->getChild("Emerald_dic_download"); if (button) @@ -163,7 +163,7 @@ EmeraldDicDownloader::EmeraldDicDownloader(lggDicDownloadFloater* spanel, std::s } -void EmeraldDicDownloader::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) +void EmeraldDicDownloader::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) { if (status < 200 || status >= 300) { diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 982b9df0d..4971cdb9e 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -137,7 +137,7 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, const st LLSD dataToPost = LLSD::emptyMap(); dataToPost[keystr.c_str()] = objectList; - LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList )); + LLHTTPClient::post4( url, dataToPost, new LLAccountingCostResponder( objectList )); } } else diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 99b0e92f7..c614f2772 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2377,7 +2377,7 @@ bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity) body["access_prefs"] = access_prefs; llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: " << url << llendl; - LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); // Ignore response + LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); // Ignore response return true; } return false; diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp index 4dbc7eb70..dbcd7e5a0 100644 --- a/indra/newview/llagentlanguage.cpp +++ b/indra/newview/llagentlanguage.cpp @@ -61,7 +61,7 @@ bool LLAgentLanguage::update() body["language"] = language; body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); - LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); } return true; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b6ae0f120..66b1e4e9b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1046,7 +1046,6 @@ bool LLAppViewer::mainLoop() // Create IO Pump to use for HTTP Requests. gServicePump = new LLPumpIO; - LLHTTPClient::setPump(*gServicePump); LLCurl::setCAFile(gDirUtilp->getCAFile()); // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 083166553..e7af36b6a 100644 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -47,7 +47,7 @@ public: LLAssetUploadChainResponder(const LLSD& post_data, const std::string& file_name, const LLUUID& queue_id, - U8* data, + char* data, U32 data_size, std::string script_name, LLAssetUploadQueueSupplier *supplier) : @@ -110,7 +110,7 @@ public: llinfos << "Compiling " << llendl; // postRaw takes ownership of mData and will delete it. - LLHTTPClient::postRaw(uploader, mData, mDataSize, this); + LLHTTPClient::postRaw4(uploader, mData, mDataSize, this); mData = NULL; mDataSize = 0; } @@ -137,7 +137,7 @@ public: } LLAssetUploadQueueSupplier *mSupplier; - U8* mData; + char* mData; U32 mDataSize; std::string mScriptName; }; @@ -174,7 +174,7 @@ void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier) if (object) { url = object->getRegion()->getCapability("UpdateScriptTask"); - LLHTTPClient::post(url, body, + LLHTTPClient::post4(url, body, new LLAssetUploadChainResponder( body, data.mFilename, data.mQueueId, data.mData, data.mDataSize, data.mScriptName, *supplier)); @@ -189,7 +189,7 @@ void LLAssetUploadQueue::queue(const std::string& filename, BOOL is_running, BOOL is_target_mono, const LLUUID& queue_id, - U8* script_data, + char* script_data, U32 data_size, std::string script_name) { diff --git a/indra/newview/llassetuploadqueue.h b/indra/newview/llassetuploadqueue.h index 930dc72a7..eaee9f424 100644 --- a/indra/newview/llassetuploadqueue.h +++ b/indra/newview/llassetuploadqueue.h @@ -54,7 +54,7 @@ public: BOOL is_running, BOOL is_target_mono, const LLUUID& queue_id, - U8* data, + char* data, U32 data_size, std::string script_name); @@ -72,7 +72,7 @@ private: BOOL mIsRunning; BOOL mIsTargetMono; LLUUID mQueueId; - U8* mData; + char* mData; U32 mDataSize; std::string mScriptName; }; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index a9ff6e3f7..47f8eba37 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -283,11 +283,11 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content) std::string uploader = content["uploader"]; if (mFileName.empty()) { - LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); + LLHTTPClient::postFile4(uploader, mVFileID, mAssetType, this); } else { - LLHTTPClient::postFile(uploader, mFileName, this); + LLHTTPClient::postFile4(uploader, mFileName, this); } } @@ -946,7 +946,7 @@ public: if ( getFilename().empty() ) { // we have no filename, use virtual file ID instead - LLHTTPClient::postFile( + LLHTTPClient::postFile4( confirmation_url, getVFileID(), getAssetType(), @@ -954,7 +954,7 @@ public: } else { - LLHTTPClient::postFile( + LLHTTPClient::postFile4( confirmation_url, getFilename(), responder); diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp index ef9b910ae..9ff6d9f8f 100644 --- a/indra/newview/llcapabilitylistener.cpp +++ b/indra/newview/llcapabilitylistener.cpp @@ -106,12 +106,11 @@ bool LLCapabilityListener::capListener(const LLSD& request) if (! url.empty()) { // This capability is supported by the region to which we're talking. - LLHTTPClient::post(url, payload, + LLHTTPClient::post4(url, payload, new LLSDMessage::EventResponder(LLEventPumps::instance(), request, mProvider.getDescription(), cap, reply, error), - LLSD(), // headers timeout); } else diff --git a/indra/newview/llcaphttpsender.cpp b/indra/newview/llcaphttpsender.cpp index 1127f4342..952d72314 100644 --- a/indra/newview/llcaphttpsender.cpp +++ b/indra/newview/llcaphttpsender.cpp @@ -50,5 +50,5 @@ void LLCapHTTPSender::send(const LLHost& host, const std::string& message, LLSD llsd; llsd["message"] = message; llsd["body"] = body; - LLHTTPClient::post(mCap, llsd, response); + LLHTTPClient::post4(mCap, llsd, response); } diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 5cf8b7fdc..50aceb389 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -437,8 +437,8 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, { // Read script source in to buffer. U32 script_size = file.getSize(); - U8* script_data = new U8[script_size]; - file.read(script_data, script_size); + char* script_data = new char[script_size]; + file.read(reinterpret_cast(script_data), script_size); queue->mUploadQueue->queue(filename, data->mTaskId, data->mItemId, is_running, queue->mMono, queue->getID(), diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 3114f2914..3345eb301 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -76,7 +76,7 @@ namespace virtual void completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + const buffer_ptr_t& buffer); private: bool mDone; @@ -160,7 +160,7 @@ namespace void LLEventPollResponder::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + const buffer_ptr_t& buffer) { if (status == HTTP_BAD_GATEWAY) { @@ -182,7 +182,7 @@ namespace lldebugs << "LLEventPollResponder::makeRequest <" << mCount << "> ack = " << LLSDXMLStreamer(mAcknowledge) << llendl; - LLHTTPClient::post(mPollURL, request, this); + LLHTTPClient::post4(mPollURL, request, this); } void LLEventPollResponder::handleMessage(const LLSD& content) diff --git a/indra/newview/llfloateractivespeakers.cpp b/indra/newview/llfloateractivespeakers.cpp index f0f856ef0..7a5d83bdc 100644 --- a/indra/newview/llfloateractivespeakers.cpp +++ b/indra/newview/llfloateractivespeakers.cpp @@ -888,7 +888,7 @@ void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data LLUUID mSessionID; }; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new MuteVoiceResponder(self->mSpeakerMgr->getSessionID())); @@ -953,7 +953,7 @@ void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data) LLUUID mSessionID; }; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new MuteTextResponder(self->mSpeakerMgr->getSessionID())); @@ -991,7 +991,7 @@ void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_da } }; - LLHTTPClient::post(url, data, new ModerationModeResponder()); + LLHTTPClient::post4(url, data, new ModerationModeResponder()); } // diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 70466afd0..07a183256 100644 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -53,7 +53,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() if (!url.empty()) { llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <getText()), new ConsoleResponder(mOutput)); @@ -217,7 +217,7 @@ void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param) else { // Using SimConsoleAsync - LLHTTPClient::post( + LLHTTPClient::post4( url, LLSD(input->getText()), new AsyncConsoleResponder); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 162414041..eb3ef90ec 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -760,7 +760,7 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate() body["allow_parcel_changes"] = childGetValue("allow_parcel_changes_check"); body["block_parcel_search"] = childGetValue("block_parcel_search_check"); - LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); } else { @@ -2356,7 +2356,7 @@ bool LLPanelEstateInfo::commitEstateInfoCaps() body["owner_abuse_email"] = childGetValue("abuse_email_address").asString(); // we use a responder so that we can re-get the data after committing to the database - LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder((void*)this)); + LLHTTPClient::post4(url, body, new LLEstateChangeInfoResponder((void*)this)); return true; } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 5888bb80f..48cee545c 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -877,14 +877,14 @@ void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url if(childGetValue("screen_check").asBoolean() && !sshot_url.empty()) { // try to upload screenshot - LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report, + LLHTTPClient::post4(sshot_url, report, new LLUserReportScreenshotResponder(report, mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType)); } else { // screenshot not wanted or we don't have screenshot cap - LLHTTPClient::post(url, report, new LLUserReportResponder()); + LLHTTPClient::post4(url, report, new LLUserReportResponder); } } diff --git a/indra/newview/llfloaterteleport.cpp b/indra/newview/llfloaterteleport.cpp index a4a88bfd0..ae4ef5a3a 100644 --- a/indra/newview/llfloaterteleport.cpp +++ b/indra/newview/llfloaterteleport.cpp @@ -299,7 +299,7 @@ void LLFloaterTeleport::onClickTeleport(void* userdata) args["public_region_seed_capability"] = text; args["position"] = ll_sd_from_vector3(LLVector3(128, 128, 50)); // default to middle of region above base terrain LL_INFOS("OGPX") << " args to placeavatar cap " << placeAvatarCap << " on teleport: " << LLSDOStreamer(args) << LL_ENDL; - LLHTTPClient::post(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder()); + LLHTTPClient::post4(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder()); gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["requesting"]); gViewerWindow->setShowProgress(TRUE); diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index d83dab9fd..3ae58c14f 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -167,7 +167,7 @@ BOOL LLFloaterTOS::postBuild() { web_browser->addObserver(this); gResponsePtr = LLIamHere::build( this ); - LLHTTPClient::get( getString( "real_url" ), gResponsePtr ); + LLHTTPClient::get4( getString( "real_url" ), gResponsePtr ); } return TRUE; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index c56e49206..4b0e5accf 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -231,7 +231,7 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) // Discover the MIME type only for "http" scheme. if(scheme == "http" || scheme == "https") { - LLHTTPClient::getHeaderOnly( media_url, + LLHTTPClient::getHeaderOnly4( media_url, new LLMediaTypeResponder(self->getHandle())); } else diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 27774273a..bcd04e89b 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -271,7 +271,7 @@ bool send_start_session_messages( data["params"] = agents; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new LLStartConferenceChatResponder( @@ -715,7 +715,7 @@ void LLVoiceChannelGroup::getChannelInfo() LLSD data; data["method"] = "call"; data["session-id"] = mSessionID; - LLHTTPClient::post(url, + LLHTTPClient::post4(url, data, new LLVoiceCallCapResponder(mSessionID)); } @@ -1593,7 +1593,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) data["method"] = "invite"; data["session-id"] = mSessionUUID; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new LLSessionInviteResponder( diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ba794068a..d00c8703d 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -400,7 +400,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLSD data; data["method"] = "accept invitation"; data["session-id"] = session_id; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new LLViewerChatterBoxInvitationAcceptResponder( @@ -438,7 +438,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLSD data; data["method"] = "decline invitation"; data["session-id"] = session_id; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, NULL); @@ -1720,7 +1720,7 @@ public: LLSD data; data["method"] = "accept invitation"; data["session-id"] = session_id; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new LLViewerChatterBoxInvitationAcceptResponder( diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 50234039e..1122712bc 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -572,7 +572,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, request["payload"] = body; // viewer_region->getCapAPI().post(request); - LLHTTPClient::post( + LLHTTPClient::post4( url, body, new LLCreateInventoryCategoryResponder(this, callback, user_data) ); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 5e855e144..619722b70 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -699,14 +699,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch() if (folder_request_body["folders"].size()) { LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); - LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); + LLHTTPClient::post4(url, folder_request_body, fetcher, 300.0); } if (folder_request_body_lib["folders"].size()) { std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); - LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); + LLHTTPClient::post4(url_lib, folder_request_body_lib, fetcher, 300.0); } } if (item_count) @@ -723,7 +723,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() body["agent_id"] = gAgent.getID(); body["items"] = item_request_body; - LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); + LLHTTPClient::post4(url, body, new LLInventoryModelFetchItemResponder(body)); } //else //{ @@ -750,7 +750,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() body["agent_id"] = gAgent.getID(); body["items"] = item_request_body_lib; - LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); + LLHTTPClient::post4(url, body, new LLInventoryModelFetchItemResponder(body)); } } } diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 887f0a474..07427c396 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -235,7 +235,7 @@ void fetch_items_from_llsd(const LLSD& items_llsd) if (!url.empty()) { body[i]["agent_id"] = gAgent.getID(); - LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); + LLHTTPClient::post4(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); continue; } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 13949eee4..60d3d9fca 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -766,14 +766,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - std::vector headers; - headers.push_back("Accept: application/octet-stream"); + AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange(http_url, headers, offset, size, + mCurlRequest->getByteRange2(http_url, headers, offset, size, new LLMeshSkinInfoResponder(mesh_id, offset, size)); LLMeshRepository::sHTTPRequestCount++; } @@ -841,14 +840,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - std::vector headers; - headers.push_back("Accept: application/octet-stream"); + AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange(http_url, headers, offset, size, + mCurlRequest->getByteRange2(http_url, headers, offset, size, new LLMeshDecompositionResponder(mesh_id, offset, size)); LLMeshRepository::sHTTPRequestCount++; } @@ -916,14 +914,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - std::vector headers; - headers.push_back("Accept: application/octet-stream"); + AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange(http_url, headers, offset, size, + mCurlRequest->getByteRange2(http_url, headers, offset, size, new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); LLMeshRepository::sHTTPRequestCount++; } @@ -966,8 +963,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c } //either cache entry doesn't exist or is corrupt, request header from simulator - std::vector headers; - headers.push_back("Accept: application/octet-stream"); + AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_params.getSculptID()); if (!http_url.empty()) @@ -976,7 +972,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c //within the first 4KB //NOTE -- this will break of headers ever exceed 4KB // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + mCurlRequest->getByteRange2(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); LLMeshRepository::sHTTPRequestCount++; count++; } @@ -1031,14 +1027,13 @@ void LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, } //reading from VFS failed for whatever reason, fetch from sim - std::vector headers; - headers.push_back("Accept: application/octet-stream"); + AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + mCurlRequest->getByteRange2(constructUrl(mesh_id), headers, offset, size, new LLMeshLODResponder(mesh_params, lod, offset, size)); LLMeshRepository::sHTTPRequestCount++; count++; @@ -1612,9 +1607,9 @@ void LLMeshUploadThread::doWholeModelUpload() wholeModelToLLSD(full_model_data, true); LLSD body = full_model_data["asset_resources"]; dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num)); - LLCurlRequest::headers_t headers; + AIHTTPHeaders headers; // This might throw AICurlNoEasyHandle. - mCurlRequest->post(mWholeModelUploadURL, headers, body, + mCurlRequest->post2(mWholeModelUploadURL, headers, body, new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle), mMeshUploadTimeOut); do { @@ -1646,9 +1641,9 @@ void LLMeshUploadThread::requestWholeModelFee() dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num)); mPendingUploads++; - LLCurlRequest::headers_t headers; + AIHTTPHeaders headers; // This might throw AICurlNoEasyHandle. - mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, + mCurlRequest->post2(mWholeModelFeeCapability, headers, model_data, new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle), mMeshUploadTimeOut); do diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 5421cd886..acb691c62 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -587,7 +587,7 @@ void LLPanelClassified::sendClassifiedInfoRequest() if (!url.empty()) { llinfos << "Classified stat request via capability" << llendl; - LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(((LLView*)this)->getHandle(), mClassifiedID)); + LLHTTPClient::post4(url, body, new LLClassifiedStatsResponder(((LLView*)this)->getHandle(), mClassifiedID)); } } } @@ -999,7 +999,7 @@ void LLPanelClassified::sendClassifiedClickMessage(const std::string& type) std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); llinfos << "LLPanelClassified::sendClassifiedClickMessage via capability" << llendl; - LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); } //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelgroupvoting.cpp b/indra/newview/llpanelgroupvoting.cpp index b4bee1522..b7a1ddd7e 100644 --- a/indra/newview/llpanelgroupvoting.cpp +++ b/indra/newview/llpanelgroupvoting.cpp @@ -778,7 +778,7 @@ void LLPanelGroupVoting::impl::sendStartGroupProposal() body["duration"] = duration_seconds; body["proposal-text"] = mProposalText->getText(); - LLHTTPClient::post( + LLHTTPClient::post4( url, body, new LLStartGroupVoteResponder(mGroupID), @@ -825,7 +825,7 @@ void LLPanelGroupVoting::impl::sendGroupProposalBallot(const std::string& vote) body["group-id"] = mGroupID; body["vote"] = vote; - LLHTTPClient::post( + LLHTTPClient::post4( url, body, new LLGroupProposalBallotResponder(mGroupID), diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 3483f2577..c5163c3a5 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -892,7 +892,7 @@ void LLPanelLogin::refreshLoginPage() std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage(); if (!login_page.empty()) { - LLHTTPClient::head(login_page, gResponsePtr); + LLHTTPClient::head4(login_page, gResponsePtr); } else { sInstance->setSiteIsAlive(false); } diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp index 4f687099f..59ce810b3 100644 --- a/indra/newview/llpanelplace.cpp +++ b/indra/newview/llpanelplace.cpp @@ -391,7 +391,7 @@ void LLPanelPlace::displayParcelInfo(const LLVector3& pos_region, U64 region_handle = to_region_handle(pos_global); body["region_handle"] = ll_sd_from_U64(region_handle); } - LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(this->getHandle())); + LLHTTPClient::post4(url, body, new LLRemoteParcelRequestResponder(this->getHandle())); } else { diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 48775693a..0653111e3 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -364,7 +364,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b llassert(!navMeshStatusURL.empty()); navMeshPtr->handleNavMeshCheckVersion(); LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); - LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); + LLHTTPClient::get4(navMeshStatusURL, navMeshStatusResponder); } } @@ -398,12 +398,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); - LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); + LLHTTPClient::get4(objectLinksetsURL, objectLinksetsResponder); if (doRequestTerrain) { LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); - LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); + LLHTTPClient::get4(terrainLinksetsURL, terrainLinksetsResponder); } } } @@ -447,13 +447,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP if (!objectPostData.isUndefined()) { LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); - LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); + LLHTTPClient::put4(objectLinksetsURL, objectPostData, objectLinksetsResponder); } if (!terrainPostData.isUndefined()) { LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); - LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); + LLHTTPClient::put4(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); } } } @@ -486,7 +486,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_ pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); - LLHTTPClient::get(charactersURL, charactersResponder); + LLHTTPClient::get4(charactersURL, charactersResponder); } } } @@ -519,7 +519,7 @@ void LLPathfindingManager::requestGetAgentState() std::string agentStateURL = getAgentStateURLForRegion(currentRegion); llassert(!agentStateURL.empty()); LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); - LLHTTPClient::get(agentStateURL, responder); + LLHTTPClient::get4(agentStateURL, responder); } } } @@ -543,7 +543,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak LLSD postData; postData["command"] = "rebuild"; LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); - LLHTTPClient::post(navMeshStatusURL, postData, responder); + LLHTTPClient::post4(navMeshStatusURL, postData, responder); } } @@ -567,7 +567,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); LLSD postData; - LLHTTPClient::post(navMeshURL, postData, responder); + LLHTTPClient::post4(navMeshURL, postData, responder); } } } diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index ecb260704..32da50942 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -1183,7 +1183,7 @@ void LLPreviewGesture::saveIfNeeded() // Saving into agent inventory LLSD body; body["item_id"] = mItemUUID; - LLHTTPClient::post(agent_url, body, + LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); delayedUpload = TRUE; } @@ -1193,7 +1193,7 @@ void LLPreviewGesture::saveIfNeeded() LLSD body; body["task_id"] = mObjectUUID; body["item_id"] = mItemUUID; - LLHTTPClient::post(task_url, body, + LLHTTPClient::post4(task_url, body, new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); } else if (gAssetStorage) diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 45de56e14..5de155536 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -569,7 +569,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) body["item_id"] = mItemUUID; llinfos << "Saving notecard " << mItemUUID << " into agent inventory via " << agent_url << llendl; - LLHTTPClient::post(agent_url, body, + LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else if (!mObjectUUID.isNull() && !task_url.empty()) @@ -582,7 +582,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) body["item_id"] = mItemUUID; llinfos << "Saving notecard " << mItemUUID << " into task " << mObjectUUID << " via " << task_url << llendl; - LLHTTPClient::post(task_url, body, + LLHTTPClient::post4(task_url, body, new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else if (gAssetStorage) diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index baf963d68..de49d1488 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1494,7 +1494,7 @@ void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, { body["target"] = "lsl2"; } - LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); + LLHTTPClient::post4(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, @@ -2393,7 +2393,7 @@ void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, body["item_id"] = item_id; body["is_script_running"] = is_running; body["target"] = monoChecked() ? "mono" : "lsl2"; - LLHTTPClient::post(url, body, + LLHTTPClient::post4(url, body, new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index eda8cb659..65f53822b 100644 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -65,7 +65,7 @@ void LLProductInfoRequestManager::initSingleton() std::string url = gAgent.getRegion()->getCapability("ProductInfoRequest"); if (!url.empty()) { - LLHTTPClient::get(url, new LLProductInfoRequestResponder()); + LLHTTPClient::get4(url, new LLProductInfoRequestResponder()); } } diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 2b6195521..5a825cb60 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -541,7 +541,7 @@ void LLTexLayerSetBuffer::doUpload() { LLSD body = LLSD::emptyMap(); // The responder will call LLTexLayerSetBuffer::onTextureUploadComplete() - LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); + LLHTTPClient::post4(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl; } else diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index fde412508..4580a2ff8 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -149,7 +149,7 @@ public: // void relese() { --mActiveCount; } S32 callbackHttpGet(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer, + const LLHTTPClient::Responder::buffer_ptr_t& buffer, bool partial, bool success); void callbackCacheRead(bool success, LLImageFormatted* image, S32 imagesize, BOOL islocal); @@ -303,7 +303,7 @@ public: virtual void completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + const buffer_ptr_t& buffer) { static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); @@ -1319,11 +1319,10 @@ bool LLTextureFetchWorker::doWork(S32 param) #endif // Will call callbackHttpGet when curl request completes - std::vector headers; - headers.push_back("Accept: image/x-j2c"); + AIHTTPHeaders headers("Accept", "image/x-j2c"); try { - res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize, + res = mFetcher->mCurlGetRequest->getByteRange2(mUrl, headers, offset, mRequestedSize, new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true)); } catch(AICurlNoEasyHandle const& error) @@ -1806,7 +1805,7 @@ bool LLTextureFetchWorker::processSimulatorPackets() ////////////////////////////////////////////////////////////////////////////// S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer, + const LLHTTPClient::Responder::buffer_ptr_t& buffer, bool partial, bool success) { S32 data_size = 0 ; diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp index 7f14a4254..722e31b65 100644 --- a/indra/newview/lltexturestatsuploader.cpp +++ b/indra/newview/lltexturestatsuploader.cpp @@ -47,7 +47,7 @@ void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_ca { if ( texture_cap_url != "" ) { - LLHTTPClient::post(texture_cap_url, texture_stats, NULL); + LLHTTPClient::post4(texture_cap_url, texture_stats, NULL); } else { diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 5a537ae95..7d0528d8c 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -47,7 +47,7 @@ const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services const char* LLTranslate::m_GoogleLangSpec = "&langpair="; float LLTranslate::m_GoogleTimeout = 10; -LLSD LLTranslate::m_Header; +AIHTTPHeaders LLTranslate::m_Header; // These constants are for the GET header. const char* LLTranslate::m_AcceptHeader = "Accept"; const char* LLTranslate::m_AcceptType = "text/plain"; @@ -68,13 +68,13 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std std::string user_agent = gCurrentVersion; // - if (!m_Header.size()) + if (m_Header.empty()) { - m_Header.insert(m_AcceptHeader, LLSD(m_AcceptType)); - m_Header.insert(m_AgentHeader, LLSD(user_agent)); + m_Header.addHeader(m_AcceptHeader, m_AcceptType); + m_Header.addHeader(m_AgentHeader, user_agent); } - LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout); + LLHTTPClient::get4(url, result, m_Header, m_GoogleTimeout); } //static diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 5fd85f534..a646efa87 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -109,7 +109,7 @@ private: static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to); static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage); - static LLSD m_Header; + static AIHTTPHeaders m_Header; static const char* m_GoogleURL; static const char* m_GoogleLangSpec; static const char* m_AcceptHeader; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index f4f23c85a..9b80ed2c7 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -82,8 +82,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // People API can return localized error messages. Indicate our // language preference via header. - LLSD headers; - headers["Accept-Language"] = LLUI::getLanguage(); + AIHTTPHeaders headers("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 @@ -110,7 +109,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // communicates with the back-end. LLSD body; body["display_name"] = change_array; - LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); + LLHTTPClient::post4(cap_url, body, new LLSetDisplayNameResponder, headers); } class LLSetDisplayNameReply : public LLHTTPNode diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index c932de258..436bb3e97 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -256,7 +256,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const body["items"][0]["owner_id"] = mPermissions.getOwner(); body["items"][0]["item_id"] = mUUID; - LLHTTPClient::post(url, body, new LLInventoryModel::fetchInventoryResponder(body)); + LLHTTPClient::post4(url, body, new LLInventoryModel::fetchInventoryResponder(body)); } else { diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 5b13d747b..a1bbab295 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -645,17 +645,17 @@ void LLViewerMedia::setOpenIDCookie() getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); // Do a web profile get so we can store the cookie - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); + AIHTTPHeaders headers; + headers.addHeader("Accept", "*/*"); + headers.addHeader("Cookie", sOpenIDCookie); + headers.addHeader("User-Agent", getCurrentUserAgent()); std::string profile_url = getProfileURL(""); LLURL raw_profile_url( profile_url.c_str() ); LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << llendl; LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << llendl; - LLHTTPClient::get(profile_url, + LLHTTPClient::get4(profile_url, new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), headers); } @@ -676,18 +676,18 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. sOpenIDCookie.clear(); - LLSD headers = LLSD::emptyMap(); + AIHTTPHeaders headers; // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header - headers["Accept"] = "*/*"; + headers.addHeader("Accept", "*/*"); // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" - headers["Content-Type"] = "application/x-www-form-urlencoded"; + headers.addHeader("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]; + char* data = new char[size]; memcpy(data, openid_token.data(), size); - LLHTTPClient::postRaw( + LLHTTPClient::postRaw4( openid_url, data, size, @@ -1278,7 +1278,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi { if(mime_type.empty()) { - LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); + LLHTTPClient::getHeaderOnly4( url, new LLMimeDiscoveryResponder(this)); } else if(initializeMedia(mime_type) && (plugin = getMediaPlugin())) { diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 8f3019121..faa43eb43 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1201,7 +1201,7 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty body["everyone_mask"] = LLSD::Integer(everyone_perms); body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost); - LLHTTPClient::post(url, body, + LLHTTPClient::post4(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); } else @@ -1370,7 +1370,7 @@ void NewResourceItemCallback::fire(const LLUUID& new_item_id) } if(agent_url.empty()) return; - LLHTTPClient::post(agent_url, body, + LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, vfile_id, new_item->getType())); } // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6b1ffbdfd..73586b551 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3604,7 +3604,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string authUrl = mesg.substr(8); authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; authUrl += gAuthString; - HippoRestRequest::get(authUrl, new AuthHandler()); + HippoRestRequest::get5(authUrl, new AuthHandler()); return; } } diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index 138916f79..01810c271 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -1213,7 +1213,7 @@ void myupload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ LLSDSerialize::toXML(body, llsdxml); LL_DEBUGS("ObjectBackup") << "posting body to capability: " << llsdxml.str() << LL_ENDL; //LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); - LLHTTPClient::post(url, body, new importResponder(body, uuid, asset_type)); + LLHTTPClient::post4(url, body, new importResponder(body, uuid, asset_type)); } else { diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index b1810eeed..dd9d5bcc7 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1109,7 +1109,7 @@ void LLViewerObjectList::fetchObjectCosts() LLSD post_data = LLSD::emptyMap(); post_data["object_ids"] = id_list; - LLHTTPClient::post( + LLHTTPClient::post4( url, post_data, new LLObjectCostResponder(id_list)); @@ -1165,7 +1165,7 @@ void LLViewerObjectList::fetchPhysicsFlags() LLSD post_data = LLSD::emptyMap(); post_data["object_ids"] = id_list; - LLHTTPClient::post( + LLHTTPClient::post4( url, post_data, new LLPhysicsFlagsResponder(id_list)); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 49cd7a1a3..474978af1 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -467,7 +467,7 @@ 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::ResponderIgnore); + LLHTTPClient::post4(region_url, body, new LLHTTPClient::ResponderIgnore); } else { diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 9ed016d71..4c21dc236 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1310,7 +1310,7 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag parcel->packMessage(body); llinfos << "Sending parcel properties update via capability to: " << url << llendl; - LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); } else { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 11e47bd77..adb3e25ad 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1661,9 +1661,9 @@ void LLViewerRegion::setSeedCapability(const std::string& url) llinfos << "posting to seed " << url << llendl; S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, + LLHTTPClient::post4(url, capabilityNames, BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); + CAP_REQUEST_TIMEOUT); } S32 LLViewerRegion::getNumSeedCapRetries() @@ -1697,9 +1697,9 @@ void LLViewerRegion::failedSeedCapability() << mImpl->mSeedCapAttempts << ")" << llendl; S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, + LLHTTPClient::post4(url, capabilityNames, BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); + CAP_REQUEST_TIMEOUT); } else { @@ -1743,7 +1743,7 @@ private: { mAttempt++; LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); + LLHTTPClient::get4(mRetryURL, new SimulatorFeaturesReceived(*this), CAP_REQUEST_TIMEOUT); } } @@ -1769,7 +1769,7 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // kick off a request for simulator features - LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); + LLHTTPClient::get4(url, new SimulatorFeaturesReceived(url, getHandle()), CAP_REQUEST_TIMEOUT); } else { diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 98962a0fa..8202bd3a8 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -874,6 +874,6 @@ void send_stats() body["MinimalSkin"] = false; LLViewerStats::getInstance()->addToMessage(body); - LLHTTPClient::post(url, body, new ViewerStatsResponder()); + LLHTTPClient::post4(url, body, new ViewerStatsResponder); } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 0362adaf4..b43b4fe29 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -1364,7 +1364,7 @@ void LLVoiceClient::requestVoiceAccountProvision(S32 retries) if ( url == "" ) return; - LLHTTPClient::post( + LLHTTPClient::post4( url, LLSD(), new LLViewerVoiceAccountProvisionResponder(retries)); @@ -5061,7 +5061,7 @@ void LLVoiceClient::parcelChanged() std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest"); LLSD data; - LLHTTPClient::post( + LLHTTPClient::post4( url, data, new LLVoiceClientCapResponder); diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 307edffdd..069398964 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -284,7 +284,7 @@ bool LLWaterParamManager::savePresetToNotecard(const std::string & name) file.write((U8*)buffer.c_str(), size); LLSD body; body["item_id"] = item->getUUID(); - LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); + LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else { diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 0495d9c51..b1ca3ab82 100644 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -88,7 +88,7 @@ bool LLEnvironmentRequest::doRequest() } LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; - LLHTTPClient::get(url, new LLEnvironmentRequestResponder()); + LLHTTPClient::get4(url, new LLEnvironmentRequestResponder()); return true; } @@ -160,7 +160,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL; LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL; - LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder()); + LLHTTPClient::post4(url, content, new LLEnvironmentApplyResponder()); return true; } diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 284da40cd..72177a3e7 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -943,7 +943,7 @@ bool LLWLParamManager::savePresetToNotecard(const std::string & name) file.write((U8*)buffer.c_str(), size); LLSD body; body["item_id"] = item->getUUID(); - LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); + LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else { diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 7672cca2f..1bb7c43b9 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -441,7 +441,7 @@ void LLWorldMap::sendMapLayerRequest() if (!url.empty()) { llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl; - LLHTTPClient::post(url, body, new LLMapLayerResponder()); + LLHTTPClient::post4(url, body, new LLMapLayerResponder); } else { From f1c635d103c6cbc326a923cc82127e8b36f022e6 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 4 Sep 2012 23:34:11 +0200 Subject: [PATCH 10/64] Cherry pick from curlthreading2 --- indra/llimage/llpngwrapper.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 7def0c713..276709d1a 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -32,7 +32,12 @@ #ifndef LL_LLPNGWRAPPER_H #define LL_LLPNGWRAPPER_H +#ifdef LL_STANDALONE +#include +#else +// Workaround for wrongly packaged prebuilt. #include "libpng15/png.h" +#endif #include "llimage.h" class LLPngWrapper From 3a3605b812ce1a6329e5d4955544f4212f47d6fc Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 4 Sep 2012 23:34:56 +0200 Subject: [PATCH 11/64] Cherry pick from curlthreading2 --- indra/plugins/webkit/media_plugin_webkit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/plugins/webkit/media_plugin_webkit.cpp b/indra/plugins/webkit/media_plugin_webkit.cpp index 9809a9e5e..e64a89d88 100644 --- a/indra/plugins/webkit/media_plugin_webkit.cpp +++ b/indra/plugins/webkit/media_plugin_webkit.cpp @@ -25,8 +25,8 @@ * $/LicenseInfo$ * @endcond */ -#include "llqtwebkit.h" #include "linden_common.h" +#include "llqtwebkit.h" #include "indra_constants.h" // for indra keyboard codes #include "lltimer.h" From 1d5a63c180b7529cf2a231bd2fc904ba5ebcf9ba Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 18 Sep 2012 23:59:09 +0200 Subject: [PATCH 12/64] Fixed showing TOS floater. This creates a separate events interface structure for CurlResponderBuffer (AICurlResponderBufferEvents) for dealing with received HTTP headers. The headers are passed to the Responder, but only if the class derived from Responder implements completedHeaders (otherwise it makes little sense to even decode the headers). Basically this is a reimplementation of the functionality of the old LLHTTPClientURLAdaptor class. --- indra/aistatemachine/aicurl.cpp | 63 ++++++++++++++----- indra/aistatemachine/aicurl.h | 42 +++++++++++-- .../aicurleasyrequeststatemachine.cpp | 5 -- .../aicurleasyrequeststatemachine.h | 3 - indra/aistatemachine/aicurlprivate.h | 16 +++-- indra/llmessage/aihttpheaders.h | 5 +- indra/llmessage/llavatarnamecache.cpp | 19 +++--- indra/llmessage/llavatarnamecache.h | 4 +- indra/llmessage/llhttpclient.cpp | 46 -------------- indra/newview/hipporestrequest.cpp | 4 +- indra/newview/llfloaterurlentry.cpp | 7 ++- indra/newview/llviewerdisplayname.cpp | 3 +- indra/newview/llviewermedia.cpp | 38 ++++++----- 13 files changed, 142 insertions(+), 113 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index b9d832c2f..84e584282 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -445,9 +445,10 @@ void Responder::setURL(std::string const& url) // Called with HTML header. // virtual -void Responder::completedHeader(U32, std::string const&, LLSD const&) +void Responder::completedHeaders(U32, std::string const&, AIHTTPHeaders const&) { - // Nothing. + // This should not be called unless a derived class implemented it. + llerrs << "Unexpected call to completedHeaders()." << llendl; } // Called with HTML body. @@ -1242,12 +1243,6 @@ void CurlEasyRequest::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_req mEventsTarget->added_to_multi_handle(curl_easy_request_w); } -void CurlEasyRequest::decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) -{ - if (mEventsTarget) - mEventsTarget->decoded_header(curl_easy_request_w, key, value); -} - void CurlEasyRequest::finished(AICurlEasyRequest_wat& curl_easy_request_w) { if (mEventsTarget) @@ -1268,7 +1263,7 @@ static S32 const CURL_REQUEST_TIMEOUT = 30; // Seconds per operation. LLChannelDescriptors const CurlResponderBuffer::sChannels; -CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0) +CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mEventsTarget(NULL) { ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); AICurlEasyRequest_wat curl_easy_request_w(*lockobj); @@ -1358,6 +1353,11 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w // Keep responder alive. mResponder = responder; + // Send header events to responder if needed. + if (mResponder->needsHeaders()) + { + send_events_to(mResponder.get()); + } // Add extra headers. curl_easy_request_w->addHeaders(headers); @@ -1444,7 +1444,11 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n reason = "Header parse error."; llwarns << "Received broken header line from server: \"" << header << "\"" << llendl; } - AICurlResponderBuffer_wat(*lockobj)->setStatusAndReason(status, reason); + { + AICurlResponderBuffer_wat curl_responder_buffer_w(*lockobj); + curl_responder_buffer_w->received_HTTP_header(); + curl_responder_buffer_w->setStatusAndReason(status, reason); + } return header_len; } @@ -1458,7 +1462,7 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n key = utf8str_tolower(utf8str_trim(key)); value = utf8str_trim(value); - AICurlResponderBuffer_wat(*lockobj)->decoded_header(buffered_easy_request_w, key, value); + AICurlResponderBuffer_wat(*lockobj)->received_header(key, value); } else { @@ -1472,19 +1476,20 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n return header_len; } -void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) +void CurlResponderBuffer::setStatusAndReason(U32 status, std::string const& reason) { - Dout(dc::curl, "Calling CurlResponderBuffer::added_to_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); + mStatus = status; + mReason = reason; } -void CurlResponderBuffer::decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) +void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) { - Dout(dc::curl, "Calling CurlResponderBuffer::decoded_header(@" << (void*)&*curl_easy_request_w << ", \"" << key << "\", \"" << value << "\") for this = " << (void*)this); + llerrs << "Unexpected call to added_to_multi_handle()." << llendl; } void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w) { - Dout(dc::curl, "Calling CurlResponderBuffer::finished(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); + llerrs << "Unexpected call to finished()." << llendl; } void CurlResponderBuffer::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) @@ -1534,6 +1539,14 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request if (mResponder) { + if (mEventsTarget) + { + // Only the responder registers for these events. + llassert(mEventsTarget == mResponder.get()); + // Allow clients to parse headers before we attempt to parse + // the body and provide completed/result/error calls. + mEventsTarget->completed_headers(responseCode, responseReason); + } mResponder->completedRaw(responseCode, responseReason, sChannels, mOutput); mResponder = NULL; } @@ -1541,6 +1554,24 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request resetState(curl_easy_request_w); } +void CurlResponderBuffer::received_HTTP_header(void) +{ + if (mEventsTarget) + mEventsTarget->received_HTTP_header(); +} + +void CurlResponderBuffer::received_header(std::string const& key, std::string const& value) +{ + if (mEventsTarget) + mEventsTarget->received_header(key, value); +} + +void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason) +{ + if (mEventsTarget) + mEventsTarget->completed_headers(status, reason); +} + //----------------------------------------------------------------------------- // CurlMultiHandle diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 4cdf57c68..0ae2c0786 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -52,6 +52,7 @@ #include "stdtypes.h" // U32 #include "llatomic.h" // LLAtomicU32 #include "aithreadsafe.h" +#include "aihttpheaders.h" class LLSD; class LLBufferArray; @@ -86,6 +87,13 @@ class AICurlNoBody : public AICurlError { // End Exceptions. //----------------------------------------------------------------------------- +// Events generated by AICurlPrivate::CurlResponderBuffer. +struct AICurlResponderBufferEvents { + virtual void received_HTTP_header(void) = 0; // For example "HTTP/1.0 200 OK", the first header of a reply. + virtual void received_header(std::string const& key, std::string const& value) = 0; // Subsequent headers. + virtual void completed_headers(U32 status, std::string const& reason) = 0; // Transaction completed. +}; + // Things defined in this namespace are called from elsewhere in the viewer code. namespace AICurlInterface { @@ -153,7 +161,7 @@ void setCAPath(std::string const& file); // destructed. Also, if any of those are destructed then the Responder is automatically // destructed too. // -class Responder { +class Responder : public AICurlResponderBufferEvents { public: typedef boost::shared_ptr buffer_ptr_t; @@ -165,17 +173,42 @@ class Responder { // Associated URL, used for debug output. std::string mURL; + // Headers received from the server. + AIHTTPHeaders mReceivedHeaders; + public: // Called to set the URL of the current request for this Responder, // used only when printing debug output regarding activity of the Responder. void setURL(std::string const& url); - public: - // Called from LLHTTPClientURLAdaptor::complete(): + protected: + // Called when the "HTTP/1.0 " header is received. + /*virual*/ void received_HTTP_header(void) + { + // It's possible that this page was moved (302), so we already saw headers + // from the 302 page and are starting over on the new page now. + mReceivedHeaders.clear(); + } + + // Called for all remaining headers. + /*virtual*/ void received_header(std::string const& key, std::string const& value) + { + mReceivedHeaders.addHeader(key, value); + } + + // Called when the whole transaction is completed (also the body was received), but before the body is processed. + /*virtual*/ void completed_headers(U32 status, std::string const& reason) + { + completedHeaders(status, reason, mReceivedHeaders); + } // Derived classes can override this to get the HTML header that was received, when the message is completed. // The default does nothing. - virtual void completedHeader(U32 status, std::string const& reason, LLSD const& content); + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers); + + public: + // Derived classes that implement completedHeaders() should return true here. + virtual bool needsHeaders(void) const { return false; } // Derived classes can override this to get the raw data of the body of the HTML message that was received. // The default is to interpret the content as LLSD and call completed(). @@ -251,7 +284,6 @@ typedef AIAccess AICurlEasyRequest_wat; struct AICurlEasyHandleEvents { // Events. virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0; - virtual void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value) = 0; virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0; virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0; // Avoid compiler warning. diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index b4e98a22b..9060779ee 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -77,11 +77,6 @@ void AICurlEasyRequestStateMachine::added_to_multi_handle(AICurlEasyRequest_wat& set_state(AICurlEasyRequestStateMachine_added); } -// CURL-THREAD -void AICurlEasyRequestStateMachine::decoded_header(AICurlEasyRequest_wat&, std::string const& key, std::string const& value) -{ -} - // CURL-THREAD void AICurlEasyRequestStateMachine::finished(AICurlEasyRequest_wat&) { diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.h b/indra/aistatemachine/aicurleasyrequeststatemachine.h index b3aae1c2e..ec46c43bc 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.h +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.h @@ -81,9 +81,6 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa // Called when this curl easy handle was added to a multi handle. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&); - // Called for each received HTTP header key/value pair. - /*virtual*/ void decoded_header(AICurlEasyRequest_wat&, std::string const& key, std::string const& value); - // Called when this curl easy handle finished processing (right before it is removed from the multi handle). /*virtual*/ void finished(AICurlEasyRequest_wat&); diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index d271234c2..60835ab70 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -308,7 +308,6 @@ class CurlEasyRequest : public CurlEasyHandle { protected: // Pass events to parent. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); - /*virtual*/ void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); }; @@ -328,7 +327,7 @@ class CurlEasyRequest : public CurlEasyHandle { // is created which only happens by creating a AICurlEasyRequest(true) instance, // and when the last AICurlEasyRequest is deleted, then the ThreadSafeBufferedCurlEasyRequest // is deleted and the CurlResponderBuffer destructed. -class CurlResponderBuffer : protected AICurlEasyHandleEvents { +class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AICurlEasyHandleEvents { public: typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t; @@ -347,9 +346,17 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { // Do not write more than this amount. //void setBodyLimit(U32 size) { mBodyLimit = size; } + // Post-initialization, set the parent to pass the events to. + void send_events_to(AICurlResponderBufferEvents* target) { mEventsTarget = target; } + protected: + // Events from this class. + /*virtual*/ void received_HTTP_header(void); + /*virtual*/ void received_header(std::string const& key, std::string const& value); + /*virtual*/ void completed_headers(U32 status, std::string const& reason); + + // CurlEasyHandle events. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); - /*virtual*/ void decoded_header(AICurlEasyRequest_wat& curl_easy_request_w, std::string const& key, std::string const& value); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); @@ -363,6 +370,7 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { std::string mReason; // The "reason" from the same header line. S32 mRequestTransferedBytes; S32 mResponseTransferedBytes; + AICurlResponderBufferEvents* mEventsTarget; public: static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()). @@ -380,7 +388,7 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents { static size_t curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data); // Called from curlHeaderCallback. - void setStatusAndReason(U32 status, std::string const& reason) { mStatus = status; mReason = reason; } + void setStatusAndReason(U32 status, std::string const& reason); public: // Return pointer to the ThreadSafe (wrapped) version of this object. diff --git a/indra/llmessage/aihttpheaders.h b/indra/llmessage/aihttpheaders.h index 671584f6c..3fdce0582 100644 --- a/indra/llmessage/aihttpheaders.h +++ b/indra/llmessage/aihttpheaders.h @@ -54,6 +54,9 @@ class AIHTTPHeaders { // Construct a container with a single header. AIHTTPHeaders(std::string const& key, std::string const& value); + // Clear all headers. + void clear(void) { if (mContainer) mContainer->mKeyValuePairs.clear(); } + // Add a header. Returns true if the header already existed. bool addHeader(std::string const& key, std::string const& value, op_type op = new_header); @@ -63,7 +66,7 @@ class AIHTTPHeaders { // Return true if the header already exists. bool hasHeader(std::string const& key) const; - // Return true if key exists and full value_out with the value. Return false otherwise. + // Return true if key exists and fill value_out with the value. Return false otherwise. bool getValue(std::string const& key, std::string& value_out) const; // Append the headers to slist. diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 5903af76a..852b192ea 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -129,7 +129,7 @@ namespace LLAvatarNameCache // Erase expired names from cache void eraseUnrefreshed(); - bool expirationFromCacheControl(LLSD headers, F64 *expires); + bool expirationFromCacheControl(AIHTTPHeaders const& headers, F64* expires); } /* Sample response: @@ -179,16 +179,14 @@ private: std::vector mAgentIDs; // Need the headers to look up Expires: and Retry-After: - LLSD mHeaders; + AIHTTPHeaders mHeaders; public: LLAvatarNameResponder(const std::vector& agent_ids) - : mAgentIDs(agent_ids), - mHeaders() + : mAgentIDs(agent_ids) { } - /*virtual*/ void completedHeader(U32 status, const std::string& reason, - const LLSD& headers) + /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) { mHeaders = headers; } @@ -788,7 +786,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na sCache[agent_id] = av_name; } -F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) +F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPHeaders const& headers) { F64 expires = 0.0; if (expirationFromCacheControl(headers, &expires)) @@ -804,16 +802,15 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) } } -bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) +bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPHeaders const& headers, F64* expires) { bool fromCacheControl = false; F64 now = LLFrameTimer::getTotalSeconds(); // Allow the header to override the default - LLSD cache_control_header = headers["cache-control"]; - if (cache_control_header.isDefined()) + std::string cache_control; + if (headers.getValue("cache-control", cache_control)) { S32 max_age = 0; - std::string cache_control = cache_control_header.asString(); if (max_age_from_cache_control(cache_control, &max_age)) { *expires = now + (F64)max_age; diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 3846463f1..268133b02 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -32,8 +32,8 @@ #include -class LLSD; class LLUUID; +class AIHTTPHeaders; namespace LLAvatarNameCache { @@ -98,7 +98,7 @@ namespace LLAvatarNameCache // Compute name expiration time from HTTP Cache-Control header, // or return default value, in seconds from epoch. - F64 nameExpirationFromHeaders(LLSD headers); + F64 nameExpirationFromHeaders(AIHTTPHeaders const& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index da5ad61af..2b56d1b89 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -37,52 +37,6 @@ F32 const HTTP_REQUEST_EXPIRY_SECS = 60.0f; //////////////////////////////////////////////////////////////////////////// -#if 0 -class LLHTTPClientURLAdaptor : public LLURLRequestComplete -{ -public: - LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder) - : LLURLRequestComplete(), mResponder(responder), mStatus(499), - mReason("LLURLRequest complete w/no status") - { - } - - ~LLHTTPClientURLAdaptor() - { - } - - virtual void httpStatus(U32 status, const std::string& reason) - { - LLURLRequestComplete::httpStatus(status,reason); - - mStatus = status; - mReason = reason; - } - - virtual void complete(const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) - { - if (mResponder.get()) - { - // Allow clients to parse headers before we attempt to parse - // the body and provide completed/result/error calls. - mResponder->completedHeader(mStatus, mReason, mHeaderOutput); - mResponder->completedRaw(mStatus, mReason, channels, buffer); - } - } - virtual void header(const std::string& header, const std::string& value) - { - mHeaderOutput[header] = value; - } - -private: - LLCurl::ResponderPtr mResponder; - U32 mStatus; - std::string mReason; - LLSD mHeaderOutput; -}; -#endif - class LLSDInjector : public Injector { public: diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp index 9d65dc987..e3c5e0f82 100644 --- a/indra/newview/hipporestrequest.cpp +++ b/indra/newview/hipporestrequest.cpp @@ -278,7 +278,7 @@ static void request(const std::string &url, if ((method != LLURLRequest::HTTP_PUT) && (method != LLURLRequest::HTTP_POST)) { std::string accept = "Accept: "; accept += handler->getAcceptMimeType(); - req->addHeader(accept.c_str()); + //AIFIXME req is not defined: req->addHeader(accept.c_str()); } //AIFIXME: req->setCallback(new HippoRestComplete(handler)); @@ -286,7 +286,7 @@ static void request(const std::string &url, if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) { std::string content = "Content-Type: "; content += body->contentType(); - req->addHeader(content.c_str()); + //AIFIXME req is not defined: req->addHeader(content.c_str()); //AIFIXME: chain.push_back(LLIOPipe::ptr_t(body)); } diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 4b0e5accf..a8479e895 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -59,10 +59,13 @@ public: LLHandle mParent; + virtual bool needsHeaders(void) const { return true; } - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) { - std::string media_type = content["content-type"].asString(); + std::string media_type; + bool content_type_found = headers.getValue("content-type", media_type); + llassert_always(content_type_found); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); completeAny(status, mime_type); diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index 9b80ed2c7..3d8b5e017 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -178,9 +178,8 @@ class LLDisplayNameUpdate : public LLHTTPNode // default value // *TODO: get actual headers out of ResponsePtr //LLSD headers = response->mHeaders; - LLSD headers; av_name.mExpires = - LLAvatarNameCache::nameExpirationFromHeaders(headers); + LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPHeaders()); LLAvatarNameCache::insert(agent_id, av_name); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 168d248d7..750180608 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -75,11 +75,13 @@ public: mInitialized(false) {} + virtual bool needsHeaders(void) const { return true; } - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) { - std::string media_type = content["content-type"].asString(); + std::string media_type; + bool content_type_found = headers.getValue("content-type", media_type); + llassert_always(content_type_found); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); completeAny(status, mime_type); @@ -114,13 +116,17 @@ public: { } - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ bool needsHeaders(void) const { return true; } + + /* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) { LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_DEBUGS("MediaAuth") << content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::openIDCookieResponse(cookie); + LL_DEBUGS("MediaAuth") << headers << LL_ENDL; + std::string cookie; + if (headers.getValue("set-cookie", cookie)) + { + LLViewerMedia::openIDCookieResponse(cookie); + } } /* virtual */ void completedRaw( @@ -148,14 +154,18 @@ public: { } - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + /* virtual */ bool needsHeaders(void) const { return true; } + + /* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) { - LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_WARNS("MediaAuth") << content << LL_ENDL; + LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_INFOS("MediaAuth") << headers << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + std::string cookie; + if (headers.getValue("set-cookie", cookie)) + { + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + } } void completedRaw( From c5d9dc4732295ffae30f5441b4d9d3c3b628f821 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Sep 2012 04:48:03 +0200 Subject: [PATCH 13/64] Bug fix --- indra/llmessage/llbuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 58208dbe1..437674775 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -377,7 +377,7 @@ LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address) // We have the location and the segment. U8* base = (*it).data(); S32 size = (*it).size(); - if(address == (base + size)) + if(address == (base + size - 1)) { // No need to split, since this is the last byte of the // segment. We do not want to have zero length segments, since From 2d12a82a54390728205278a08813f690babca73f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Sep 2012 04:49:43 +0200 Subject: [PATCH 14/64] Always flush LLBufferStream objects. --- indra/llmessage/llcurlrequest.cpp | 2 ++ indra/llmessage/llfiltersd2xmlrpc.cpp | 10 ++++---- indra/llmessage/llhttpclient.cpp | 35 ++++++++++++++++++--------- indra/llmessage/lliohttpserver.cpp | 9 ++++--- indra/newview/hipporestrequest.cpp | 2 ++ 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/indra/llmessage/llcurlrequest.cpp b/indra/llmessage/llcurlrequest.cpp index fffddcd46..702904a42 100644 --- a/indra/llmessage/llcurlrequest.cpp +++ b/indra/llmessage/llcurlrequest.cpp @@ -129,6 +129,8 @@ bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD c LLBufferStream buffer_stream(buffer_w->sChannels, buffer_w->getInput().get()); LLSDSerialize::toXML(data, buffer_stream); + // Need to flush the LLBufferStream or countAfter() returns more than the written data. + buffer_stream << std::flush; S32 bytes = buffer_w->getInput()->countAfter(buffer_w->sChannels.out(), NULL); buffered_easy_request_w->setPost(bytes); buffered_easy_request_w->addHeader("Content-Type: application/llsd+xml"); diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index e0ca056a5..9828a3e30 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -332,7 +332,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( // we have everyting in the buffer, so turn the structure data rpc // response into an xml rpc response. LLBufferStream stream(channels, buffer.get()); - stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER; + stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER << std::flush; // Flush, or buffer->count() returns too much! LLSD sd; LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); @@ -484,7 +484,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( break; } - stream << XMLRPC_REQUEST_FOOTER; + stream << XMLRPC_REQUEST_FOOTER << std::flush; return STATUS_DONE; } @@ -647,7 +647,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( fault_string.assign(fault_str); } stream << "'" << LLSDNotationFormatter::escapeString(fault_string) - << "'" < 0 && ostream.count_in() == 0); + // Need to flush the LLBufferStream or count_out() returns more than the written data. + ostream << std::flush; return ostream.count_out(); } @@ -68,6 +68,7 @@ class RawInjector : public Injector { LLBufferStream ostream(channels, buffer.get()); ostream.write(mData, mSize); + ostream << std::flush; // Always flush a LLBufferStream when done writing to it. return mSize; } @@ -84,21 +85,32 @@ class FileInjector : public Injector /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { - LLBufferStream ostream(channels, buffer.get()); - llifstream fstream(mFilename, std::iostream::binary | std::iostream::out); if (!fstream.is_open()) throw AICurlNoBody(llformat("Failed to open \"%s\".", mFilename.c_str())); - + LLBufferStream ostream(channels, buffer.get()); + char tmpbuf[4096]; +#ifdef SHOW_ASSERT + size_t total_len = 0; fstream.seekg(0, std::ios::end); - U32 fileSize = fstream.tellg(); + size_t file_size = fstream.tellg(); fstream.seekg(0, std::ios::beg); - std::vector fileBuffer(fileSize); - fstream.read(&fileBuffer[0], fileSize); - ostream.write(&fileBuffer[0], fileSize); +#endif + while (fstream) + { + std::streamsize len = fstream.readsome(tmpbuf, sizeof(tmpbuf)); + if (len > 0) + { + ostream.write(tmpbuf, len); +#ifdef SHOW_ASSERT + total_len += len; +#endif + } + } fstream.close(); - - return fileSize; + ostream << std::flush; + llassert(total_len == file_size && total_len == ostream.count_out()); + return ostream.count_out(); } std::string const mFilename; @@ -120,6 +132,7 @@ public: std::vector fileBuffer(fileSize); vfile.read(&fileBuffer[0], fileSize); ostream.write((char*)&fileBuffer[0], fileSize); + ostream << std::flush; return fileSize; } diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 9c1a6677e..6e2ec7f9b 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -272,6 +272,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; LLBufferStream ostr(channels, buffer.get()); LLSDSerialize::toXML(mGoodResult, ostr); + ostr << std::flush; return STATUS_DONE; } @@ -284,7 +285,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage; LLBufferStream ostr(channels, buffer.get()); - ostr << mStatusMessage; + ostr << mStatusMessage << std::flush; return STATUS_DONE; } @@ -293,7 +294,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = mHeaders; context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; LLBufferStream ostr(channels, buffer.get()); - ostr << mStatusMessage; + ostr << mStatusMessage << std::flush; return STATUS_DONE; } @@ -633,7 +634,7 @@ void LLHTTPResponder::markBad( LLBufferStream out(channels, buffer.get()); out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n\n" << "Bad Request\n\nBad Request.\n" - << "\n\n"; + << "\n\n" << std::flush; } static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_RESPONDER("HTTP Responder"); @@ -926,7 +927,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( mState = STATE_SHORT_CIRCUIT; str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n\n" << "Not Found\n\nNode '" << mAbsPathAndQuery - << "' not found.\n\n\n"; + << "' not found.\n\n\n" << std::flush; } } diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp index e3c5e0f82..e36c081d7 100644 --- a/indra/newview/hipporestrequest.cpp +++ b/indra/newview/hipporestrequest.cpp @@ -146,6 +146,7 @@ class BodyDataRaw : public Injector { LLBufferStream ostream(channels, buffer.get()); ostream.write(mData.data(), mData.size()); + ostream << std::flush; return mData.size(); } @@ -174,6 +175,7 @@ class BodyDataXml : public Injector mTree->write(data); LLBufferStream ostream(channels, buffer.get()); ostream.write(data.data(), data.size()); + ostream << std::flush; return data.size(); } From 27090c541ff30404e30e87c98c5cab9bb1850b9f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Sep 2012 05:36:11 +0200 Subject: [PATCH 15/64] Remove inconsistent dll linkage (missing LL_COMMON_API) --- indra/newview/statemachine/aistatemachine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/newview/statemachine/aistatemachine.cpp b/indra/newview/statemachine/aistatemachine.cpp index a6a646ec9..d6b7c620f 100644 --- a/indra/newview/statemachine/aistatemachine.cpp +++ b/indra/newview/statemachine/aistatemachine.cpp @@ -38,8 +38,6 @@ #include "aithreadsafe.h" #include "aistatemachine.h" -extern F64 calc_clock_frequency(void); - extern LLControlGroup gSavedSettings; // Local variables. From f3780998ed38d156a0ddc5694a8668e9136f76f5 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 20 Sep 2012 16:50:03 +0200 Subject: [PATCH 16/64] Always reset stream state after using std::hex --- indra/llmessage/aicurl.cpp | 4 ++-- indra/llmessage/llpartdata.cpp | 6 +++--- indra/llrender/llgl.cpp | 6 +++--- indra/llrender/llimagegl.cpp | 2 +- indra/llrender/llrendertarget.cpp | 2 +- indra/newview/llfloatermodelpreview.cpp | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 8237fcaa4..bfffd5a1d 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -247,7 +247,7 @@ void ssl_init(void) CRYPTO_set_dynlock_destroy_callback(&ssl_dyn_destroy_function); need_renegotiation_hack = (0x10001000UL <= ssleay); llinfos << "Successful initialization of " << - SSLeay_version(SSLEAY_VERSION) << " (0x" << std::hex << SSLeay() << ")." << llendl; + SSLeay_version(SSLEAY_VERSION) << " (0x" << std::hex << SSLeay() << std::dec << ")." << llendl; } // Cleanup OpenSSL library thread-safety. @@ -316,7 +316,7 @@ void initCurl(void (*flush_hook)()) } llinfos << "Successful initialization of libcurl " << - version_info->version << " (0x" << std::hex << version_info->version_num << "), (" << + version_info->version << " (0x" << std::hex << version_info->version_num << std::dec << "), (" << version_info->ssl_version; if (version_info->libz_version) { diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index 26cafa025..de369dc3c 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -238,14 +238,14 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp) std::ostream& operator<<(std::ostream& s, const LLPartSysData &data) { - s << "Flags: " << std::hex << data.mFlags; - s << " Pattern: " << std::hex << (U32) data.mPattern << "\n"; + s << "Flags: " << std::hex << data.mFlags << std::dec; + s << " Pattern: " << std::hex << (U32) data.mPattern << std::dec << "\n"; s << "Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n"; s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n"; s << "Burst Rate: " << data.mBurstRate << "\n"; s << "Burst Radius: " << data.mBurstRadius << "\n"; s << "Burst Speed: [" << data.mBurstSpeedMin << ", " << data.mBurstSpeedMax << "]\n"; - s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << "\n"; + s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << std::dec << "\n"; s << "Angular Velocity: " << data.mAngularVelocity << "\n"; s << "Accel: " << data.mPartAccel; return s; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 762571adc..eba807ece 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -97,9 +97,9 @@ void APIENTRY gl_debug_callback(GLenum source, { llwarns << "----- GL WARNING -------" << llendl; } - llwarns << "Type: " << std::hex << type << llendl; - llwarns << "ID: " << std::hex << id << llendl; - llwarns << "Severity: " << std::hex << severity << llendl; + llwarns << "Type: " << std::hex << type << std::dec << llendl; + llwarns << "ID: " << std::hex << id << std::dec<< llendl; + llwarns << "Severity: " << std::hex << severity << std::dec << llendl; llwarns << "Message: " << message << llendl; llwarns << "-----------------------" << llendl; if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index dfac4c2af..210ea7167 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1196,7 +1196,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt intformat = GL_COMPRESSED_ALPHA; break; default: - llwarns << "Could not compress format: " << std::hex << intformat << llendl; + llwarns << "Could not compress format: " << std::hex << intformat << std::dec << llendl; break; } } diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 6454f92d9..d770e67c9 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -49,7 +49,7 @@ void check_framebuffer_status() case GL_FRAMEBUFFER_COMPLETE: break; default: - llwarns << "check_framebuffer_status failed -- " << std::hex << status << llendl; + llwarns << "check_framebuffer_status failed -- " << std::hex << status << std::dec << llendl; ll_fail("check_framebuffer_status failed"); break; } diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 004d11646..89d34dea3 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -344,7 +344,7 @@ BOOL stop_gloderror() if (error != GLOD_NO_ERROR) { llwarns << "GLOD error detected, cannot generate LOD: " << std::hex - << error << llendl; + << error << std::dec << llendl; return TRUE; } From 81bc6b49f8afec7ba3de03258e59236a1d1a707d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 21 Sep 2012 01:28:26 +0200 Subject: [PATCH 17/64] Debug code bug fix; removal of CurlEasyHandle::getErrorString() CurlEasyHandle::mErrorBuffer (CURLOPT_ERRORBUFFER) can NOT be used to retrieve information about an error returned by curl_multi_info_read in CURLMsg::data::result. This buffer is only initialized when a curl_easy_* call returns an error, and those errors are already printed automagically. Initialize the buffer with an empty string upon invokation of an curl_easy_* call, so we are sure the error belongs to the last call. --- indra/llmessage/aicurl.cpp | 14 +++++--------- indra/llmessage/aicurlprivate.h | 13 ++++--------- indra/llmessage/llhttpclient.cpp | 1 - indra/newview/llxmlrpctransaction.cpp | 4 ++-- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index bfffd5a1d..fe743effa 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -653,6 +653,10 @@ void CurlEasyHandle::setErrorBuffer(void) mErrorBuffer = NULL; } } + if (mErrorBuffer) + { + mErrorBuffer[0] = '\0'; + } } CURLcode CurlEasyHandle::getinfo_priv(CURLINFO info, void* data) @@ -1448,15 +1452,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request else { responseCode = 499; - responseReason = AICurlInterface::strerror(code) + " : "; - if (code == CURLE_FAILED_INIT) - { - responseReason += "Curl Easy Handle initialization failed."; - } - else - { - responseReason += curl_easy_request_w->getErrorString(); - } + responseReason = AICurlInterface::strerror(code); curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); } diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index 1acf08e14..ab5045fe7 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -160,10 +160,6 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven // Returns true if this easy handle was added to a curl multi handle. bool active(void) const { return mActiveMultiHandle; } - // If there was an error code as result, then this returns a human readable error string. - // Only valid when setErrorBuffer was called and the curl_easy function returned an error. - std::string getErrorString(void) const { return mErrorBuffer ? mErrorBuffer : "(null)"; } - // Returns true when it is expected that the parent will revoke callbacks before the curl // easy handle is removed from the multi handle; that usually happens when an external // error demands termination of the request (ie, an expiration). @@ -203,8 +199,7 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven // to set the options on a curl easy handle. // // Calling sendRequest() will then connect to the given URL and perform -// the data exchange. If an error occurs related to this handle, it can -// be read by calling getErrorString(). +// the data exchange. Use getResult() to determine if an error occurred. // // Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest: // a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest, @@ -264,13 +259,13 @@ class CurlEasyRequest : public CurlEasyHandle { // This actually adds the headers that were collected with addHeader. void finalizeRequest(std::string const& url); - // Store result code that is returned by getResult. + // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. void store_result(CURLcode result) { mResult = result; } - // Called when the curl easy handle is done. + // Called by MultiHandle::check_run_count() when the curl easy handle is done. void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } - // Fill info with the transfer info. + // Called by MultiHandle::check_run_count() to fill info with the transfer info. void getTransferInfo(AICurlInterface::TransferInfo* info); // If result != CURLE_FAILED_INIT then also info was filled. diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index c04bad5e4..2f6a40050 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -480,7 +480,6 @@ static LLSD blocking_request( llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl; llwarns << "CURL REQ BODY: " << ostr.str() << llendl; llwarns << "CURL HTTP_STATUS: " << http_status << llendl; - llwarns << "CURL ERROR: " << curlEasyRequest_w->getErrorString() << llendl; llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl; response["body"] = http_buffer.asString(); } diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 227904f90..2b967a1a2 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -340,8 +340,8 @@ void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success) if (result != CURLE_OK) { setCurlStatus(result); - llwarns << "LLXMLRPCTransaction CURL error " - << mCurlCode << ": " << curlEasyRequest_w->getErrorString() << llendl; + llwarns << "LLXMLRPCTransaction CURL error: " + << AICurlInterface::strerror(mCurlCode) << llendl; llwarns << "LLXMLRPCTransaction request URI: " << mURI << llendl; From 5bcb350d89c48b6e4c32b59eb8e3e45c73a9b533 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 21 Sep 2012 01:48:21 +0200 Subject: [PATCH 18/64] Always print '(CURL*)' in front of CURL*'s in debug output. --- indra/llmessage/aicurlthread.cpp | 2 +- indra/llmessage/debug_libcurl.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 0b1b85c0a..71302accb 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1382,7 +1382,7 @@ char const* action_str(int action) //static int MultiHandle::socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp) { - DoutEntering(dc::curl, "MultiHandle::socket_callback(" << (void*)easy << ", " << s << ", " << action_str(action) << ", " << (void*)userp << ", " << (void*)socketp << ")"); + DoutEntering(dc::curl, "MultiHandle::socket_callback((CURL*)" << (void*)easy << ", " << s << ", " << action_str(action) << ", " << (void*)userp << ", " << (void*)socketp << ")"); MultiHandle& self = *static_cast(userp); CurlSocketInfo* sock_info = static_cast(socketp); if (action == CURL_POLL_REMOVE) diff --git a/indra/llmessage/debug_libcurl.cpp b/indra/llmessage/debug_libcurl.cpp index 40b75d200..0610344f9 100644 --- a/indra/llmessage/debug_libcurl.cpp +++ b/indra/llmessage/debug_libcurl.cpp @@ -548,7 +548,7 @@ char* debug_curl_easy_escape(CURL* curl, char* url, int length) { char* ret; ret = curl_easy_escape(curl, url, length); - Dout(dc::curl, "curl_easy_escape(" << curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"'); + Dout(dc::curl, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"'); return ret; } @@ -569,23 +569,23 @@ CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...) ret = curl_easy_getinfo(curl, info, param.some_ptr); if (info == CURLINFO_PRIVATE) { - Dout(dc::curl, "curl_easy_getinfo(" << curl << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret); + Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret); } else { switch((info & CURLINFO_TYPEMASK)) { case CURLINFO_STRING: - Dout(dc::curl, "curl_easy_getinfo(" << curl << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " ") << "\" }) = " << ret); + Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " ") << "\" }) = " << ret); break; case CURLINFO_LONG: - Dout(dc::curl, "curl_easy_getinfo(" << curl << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret); + Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret); break; case CURLINFO_DOUBLE: - Dout(dc::curl, "curl_easy_getinfo(" << curl << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret); + Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret); break; case CURLINFO_SLIST: - Dout(dc::curl, "curl_easy_getinfo(" << curl << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret); + Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret); break; } } @@ -755,7 +755,7 @@ char* debug_curl_easy_unescape(CURL* curl, char* url, int inlength, int* outleng { char* ret; ret = curl_easy_unescape(curl, url, inlength, outlength); - Dout(dc::curl, "curl_easy_unescape(" << curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"'); + Dout(dc::curl, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"'); return ret; } From fb5ec1d1f5cc9082ddc05dbd39204fa4495d4698 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 21 Sep 2012 19:26:40 +0200 Subject: [PATCH 19/64] Implement curl connection throttling (CurlConcurrentConnections) --- indra/llmessage/aicurl.h | 2 +- indra/llmessage/aicurlthread.cpp | 38 ++++++++++++++++++------- indra/llmessage/aicurlthread.h | 7 ++++- indra/newview/app_settings/settings.xml | 11 +++++++ indra/newview/llappviewer.cpp | 2 +- 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index 26491da67..2402da224 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -99,7 +99,7 @@ struct TransferInfo { void initCurl(void (*)(void) = NULL); // Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread. -void startCurlThread(void); +void startCurlThread(U32 CurlConcurrentConnections); // Called once at end of application (from newview/llappviewer.cpp by main thread), // with purpose to stop curl threads, free curl resources and deinitialize curl. diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 71302accb..a75b1f0a0 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1440,18 +1440,27 @@ CURLMsg const* MultiHandle::info_read(int* msgs_in_queue) const return ret; } -CURLMcode MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) +static U32 curl_concurrent_connections = 8; // Initialized on start up by startCurlThread(). + +void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) { - std::pair res = mAddedEasyRequests.insert(easy_request); - llassert(res.second); // May not have been added before. - CURLMcode ret; + if (mAddedEasyRequests.size() < curl_concurrent_connections) // Not throttled? { - AICurlEasyRequest_wat curl_easy_request_w(*easy_request); - ret = curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle); + CURLMcode ret; + { + AICurlEasyRequest_wat curl_easy_request_w(*easy_request); + ret = curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle); + } + if (ret == CURLM_OK) + { + mHandleAddedOrRemoved = true; + std::pair res = mAddedEasyRequests.insert(easy_request); + llassert(res.second); // May not have been added before. + Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); + return; + } } - mHandleAddedOrRemoved = true; - Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); - return ret; + mQueuedRequests.push_back(easy_request); } CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request, bool as_per_command) @@ -1470,6 +1479,14 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request mAddedEasyRequests.erase(iter); mHandleAddedOrRemoved = true; Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)easy_request.get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); + + // Attempt to add a queued request, if any. + if (!mQueuedRequests.empty()) + { + add_easy_request(mQueuedRequests.front()); + mQueuedRequests.pop_front(); + } + return res; } @@ -1697,11 +1714,12 @@ void AICurlEasyRequest::removeRequest(void) namespace AICurlInterface { -void startCurlThread(void) +void startCurlThread(U32 CurlConcurrentConnections) { using namespace AICurlPrivate::curlthread; llassert(is_main_thread()); + curl_concurrent_connections = CurlConcurrentConnections; // Debug Setting. AICurlThread::sInstance = new AICurlThread; AICurlThread::sInstance->start(); } diff --git a/indra/llmessage/aicurlthread.h b/indra/llmessage/aicurlthread.h index a2bd36352..839c8339e 100644 --- a/indra/llmessage/aicurlthread.h +++ b/indra/llmessage/aicurlthread.h @@ -33,6 +33,7 @@ #include "aicurl.h" #include +#include #undef AICurlPrivate @@ -59,7 +60,7 @@ class MultiHandle : public CurlMultiHandle ~MultiHandle(); // Add/remove an easy handle to/from a multi session. - CURLMcode add_easy_request(AICurlEasyRequest const& easy_request); + void add_easy_request(AICurlEasyRequest const& easy_request); CURLMcode remove_easy_request(AICurlEasyRequest const& easy_request, bool as_per_command = false); // Reads/writes available data from a particular socket (non-blocking). @@ -100,6 +101,10 @@ class MultiHandle : public CurlMultiHandle PollSet* mReadPollSet; PollSet* mWritePollSet; + + private: + // Temporary throttling hack. + std::deque mQueuedRequests; // Waiting (throttled) requests. }; } // namespace curlthread diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c0ec36c53..7d9482424 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4205,6 +4205,17 @@ Value 0 + CurlConcurrentConnections + + Comment + Maximum number of simultaneous curl connections (requires restart) + Persist + 1 + Type + U32 + Value + 16 + CurlMaximumNumberOfHandles Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2fcf37fdb..0e55784cc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1817,7 +1817,7 @@ bool LLAppViewer::initThreads() LLWatchdog::getInstance()->init(watchdog_killer_callback); } - AICurlInterface::startCurlThread(); + AICurlInterface::startCurlThread(gSavedSettings.getU32("CurlConcurrentConnections")); LLImage::initClass(); From 4744839a088c474cd3845667b87367e27641f448 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 23 Sep 2012 17:31:41 +0200 Subject: [PATCH 20/64] Bug fix for curl request queue of last commit. In debug mode an assertion was triggered when a queued request was being removed by the main thread; and rightfully so: we should remove such request from the queue in that case. --- indra/llmessage/aicurl.h | 4 ++++ indra/llmessage/aicurlthread.cpp | 30 +++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index 2402da224..7e1f7c78d 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -310,6 +310,10 @@ class AICurlEasyRequest { // destruct it while another thread still needs it, concurrent or not. AICurlEasyRequest& operator=(AICurlEasyRequest const&) { return *this; } + public: + // Instead of assignment, it might be helpful to use swap. + void swap(AICurlEasyRequest& cer) { mCurlEasyRequest.swap(cer.mCurlEasyRequest); } + public: // The more exotic member functions of this class, to deal with passing this class // as CURLOPT_PRIVATE pointer to a curl handle and afterwards restore it. diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index a75b1f0a0..c29092271 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1461,13 +1461,41 @@ void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) } } mQueuedRequests.push_back(easy_request); +#ifdef SHOW_ASSERT + // Not active yet, but it's no longer an error if next we try to remove the request. + AICurlEasyRequest_wat(*easy_request)->mRemovedPerCommand = false; +#endif } CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request, bool as_per_command) { addedEasyRequests_type::iterator iter = mAddedEasyRequests.find(easy_request); if (iter == mAddedEasyRequests.end()) - return (CURLMcode)-2; // Was already removed before. + { + // The request could be queued. + std::deque::iterator const end = mQueuedRequests.end(); + std::deque::iterator cur = std::find(mQueuedRequests.begin(), end, easy_request); + if (cur != end) + { + // We can't use erase because that uses assignment to move elements, which is private because it isn't thread-safe for AICurlEasyRequest. + // Therefore, move the element that we found to the back with swap (could just swap with the end immediately, + // but I don't want to break the order in which requests where added). Swap is also not thread-safe, but OK here + // because it only touches the AICurlEasyRequest objects in the deque, and the deque is protected by the + // lock on MultiHandle. + std::deque::iterator prev = cur; + while (++cur != end) + { + prev->swap(*cur); + prev = cur; + } +#ifdef SHOW_ASSERT + // Now a second remove command would be an error again. + AICurlEasyRequest_wat(**prev)->mRemovedPerCommand = true; +#endif + mQueuedRequests.pop_back(); + } + return (CURLMcode)-2; // Was already removed before, or never added (queued). + } CURLMcode res; { AICurlEasyRequest_wat curl_easy_request_w(**iter); From 48702b1ed9772c8a4b16520fdf56904b25c4a7ac Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 24 Sep 2012 16:55:34 +0200 Subject: [PATCH 21/64] Various stuff Comment fixes Added some more debug support, not used yet (linux/libcwd only), I used it, but won't commit the code that did. Pass time_time parameter from post2() to prepRequest; only used by mesh uploading at the moment. --- indra/aistatemachine/aicurl.cpp | 5 ++- indra/cwdebug/debug.cc | 63 +++++++++++++++++++++++++++ indra/cwdebug/debug.h | 72 +++++++++++++++++++++++++++++-- indra/llmessage/llcurlrequest.cpp | 4 +- 4 files changed, 137 insertions(+), 7 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 9d6627054..4cc845e68 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1185,7 +1185,7 @@ void CurlEasyRequest::applyDefaultOptions(void) void CurlEasyRequest::finalizeRequest(std::string const& url) { llassert(!mRequestFinalized); - mResult = CURLE_FAILED_INIT; // General error code, the final code is written here in MultiHandle::check_run_count when msg is CURLMSG_DONE. + mResult = CURLE_FAILED_INIT; // General error code; the final result code is stored here by MultiHandle::check_run_count when msg is CURLMSG_DONE. lldebugs << url << llendl; #ifdef SHOW_ASSERT // Do a sanity check on the headers. @@ -1266,7 +1266,8 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy // CurlResponderBuffer static int const HTTP_REDIRECTS_DEFAULT = 10; -static S32 const CURL_REQUEST_TIMEOUT = 30; // Seconds per operation. +static S32 const CURL_REQUEST_TIMEOUT = 30; // The minimum value of the CURLOPT_TIMEOUT option (which is the maximum + // time in seconds that we allow a libcurl transfer operation to take). LLChannelDescriptors const CurlResponderBuffer::sChannels; diff --git a/indra/cwdebug/debug.cc b/indra/cwdebug/debug.cc index 06723f8ae..de14fa99f 100644 --- a/indra/cwdebug/debug.cc +++ b/indra/cwdebug/debug.cc @@ -49,6 +49,8 @@ namespace debug { #if CWDEBUG_LOCATION +ll_thread_local size_t BackTrace::S_number; + void BackTrace::dump_backtrace(void) const { for (int frame = 0; frame < frames(); ++frame) @@ -67,6 +69,67 @@ void BackTrace::dump_backtrace(void) const Dout(dc::finish, mangled_function_name); } } + +void BackTraces::store_trace(size_t trace) +{ + mBackTraces.push_back(trace); +} + +void BackTraces::remove_trace(size_t trace) +{ + trace_container_type::iterator iter = mBackTraces.begin(); + while (iter != mBackTraces.end()) + { + if (*iter == trace) + { + *iter = mBackTraces.back(); + mBackTraces.pop_back(); + return; + } + ++iter; + } + DoutFatal(dc::core, "Trace doesn't exist!"); +} + +void BackTraces::dump(void) const +{ + Dout(dc::backtrace|continued_cf, "Dump for (BackTraces*)" << (void*)this << " (" << mBackTraces.size() << " backtraces): "); + for (trace_container_type::const_iterator iter = mBackTraces.begin(); iter != mBackTraces.end(); ++iter) + { + Dout(dc::continued|nonewline_cf, *iter << ' '); + } + Dout(dc::finish, ""); +} + +BackTraceTracker::BackTraceTracker(BackTraces* back_traces) : mBackTraces(back_traces) +{ + BACKTRACE; + mTrace = BackTrace::S_number; + mBackTraces->store_trace(mTrace); +} + +BackTraceTracker::~BackTraceTracker() +{ + mBackTraces->remove_trace(mTrace); +} + +BackTraceTracker::BackTraceTracker(BackTraceTracker const& orig) : mBackTraces(orig.mBackTraces) +{ + BACKTRACE; + mTrace = BackTrace::S_number; + mBackTraces->store_trace(mTrace); +} + +BackTraceTracker& BackTraceTracker::operator=(BackTraceTracker const& orig) +{ + mBackTraces->remove_trace(mTrace); + mBackTraces = orig.mBackTraces; + BACKTRACE; + mTrace = BackTrace::S_number; + mBackTraces->store_trace(mTrace); + return *this; +} + #endif // CWDEBUG_LOCATION #if CWDEBUG_ALLOC && CWDEBUG_LOCATION diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h index a52837411..1deed2efb 100644 --- a/indra/cwdebug/debug.h +++ b/indra/cwdebug/debug.h @@ -173,7 +173,9 @@ extern LL_COMMON_API fake_channel const notice; #include #if CWDEBUG_LOCATION #include // Needed for 'backtrace'. +#include "llpreprocessor.h" #endif +#include #define CWD_API __attribute__ ((visibility("default"))) @@ -273,6 +275,8 @@ class BackTrace { private: boost::shared_array M_buffer; int M_frames; + public: + static ll_thread_local size_t S_number; public: BackTrace(void** buffer, int frames) : M_buffer(new void* [frames]), M_frames(frames) { std::memcpy(M_buffer.get(), buffer, sizeof(void*) * frames); } @@ -299,19 +303,81 @@ extern pthread_mutex_t backtrace_mutex; using namespace debug; \ void* buffer[32]; \ int frames = backtrace(buffer, 32); \ - size_t size; \ { \ pthread_mutex_lock(&backtrace_mutex); \ backtraces.push_back(BackTrace(buffer, frames)); \ - size = backtraces.size(); \ + BackTrace::S_number = backtraces.size(); \ pthread_mutex_unlock(&backtrace_mutex); \ } \ - Dout(dc::backtrace, "Stored backtrace #" << size); \ + Dout(dc::backtrace, "Stored backtrace #" << BackTrace::S_number); \ } while(0) + +class LL_COMMON_API BackTraces { + private: + typedef std::vector trace_container_type; + trace_container_type mBackTraces; + + public: + void store_trace(size_t trace); + void remove_trace(size_t trace); + + void dump(void) const; +}; + +class LL_COMMON_API BackTraceTracker { + private: + BackTraces* mBackTraces; + size_t mTrace; + + public: + BackTraceTracker(BackTraces* back_traces); + ~BackTraceTracker(); + + BackTraceTracker(BackTraceTracker const&); + BackTraceTracker& operator=(BackTraceTracker const&); + + void dump(void) const { mBackTraces->dump(); } +}; + #else #define BACKTRACE do { } while(0) #endif // CWDEBUG_LOCATION +template +class LL_COMMON_API InstanceTracker { + private: + T const* mInstance; + static pthread_mutex_t sInstancesMutex; + static std::set sInstances; + static void remember(T const* instance) { pthread_mutex_lock(&sInstancesMutex); sInstances.insert(instance); pthread_mutex_unlock(&sInstancesMutex); } + static void forget(T const* instance) { pthread_mutex_lock(&sInstancesMutex); sInstances.erase(instance); pthread_mutex_unlock(&sInstancesMutex); } + public: + InstanceTracker(T const* instance) : mInstance(instance) { remember(mInstance); } + ~InstanceTracker() { forget(mInstance); } + InstanceTracker& operator=(InstanceTracker const& orig) { forget(mInstance); mInstance = orig.mInstance; remember(mInstance); return *this; } + static void dump(void); + private: + // Non-copyable. Instead of copying, call InstanceTracker(T const*) with the this pointer of the new instance. + InstanceTracker(InstanceTracker const& orig); +}; + +template +pthread_mutex_t InstanceTracker::sInstancesMutex = PTHREAD_MUTEX_INITIALIZER; + +template +std::set InstanceTracker::sInstances; + +template +void InstanceTracker::dump(void) +{ + pthread_mutex_lock(&sInstancesMutex); + for (typename std::set::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + std::cout << *iter << std::endl; + } + pthread_mutex_unlock(&sInstancesMutex); +} + } // namespace debug //! Debugging macro. diff --git a/indra/llmessage/llcurlrequest.cpp b/indra/llmessage/llcurlrequest.cpp index 702904a42..9911335ee 100644 --- a/indra/llmessage/llcurlrequest.cpp +++ b/indra/llmessage/llcurlrequest.cpp @@ -95,7 +95,7 @@ bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::s AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, headers, responder); + buffer_w->prepRequest(buffered_easy_request_w, headers, responder, time_out); U32 bytes = data.size(); bool success = buffer_w->getInput()->append(buffer_w->sChannels.out(), (U8 const*)data.data(), bytes); @@ -125,7 +125,7 @@ bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD c AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, headers, responder); + buffer_w->prepRequest(buffered_easy_request_w, headers, responder, time_out); LLBufferStream buffer_stream(buffer_w->sChannels, buffer_w->getInput().get()); LLSDSerialize::toXML(data, buffer_stream); From 70c36716c9ff306f056fc2c649ee74bc7ba02692 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 24 Sep 2012 17:05:23 +0200 Subject: [PATCH 22/64] Disable SSL/TLS session caching. Fixes: VWR-28039, VWR-28629 --- indra/llmessage/aicurl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index fe743effa..0ef864a9c 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -1158,6 +1158,8 @@ void CurlEasyRequest::applyDefaultOptions(void) setopt(CURLOPT_NOSIGNAL, 1); // The old code did this for the 'buffered' version, but I think it's nonsense. //setopt(CURLOPT_DNS_CACHE_TIMEOUT, 0); + // Disable SSL/TLS session caching; some servers (aka id.secondlife.com) refuse connections when session ids are enabled. + setopt(CURLOPT_SSL_SESSIONID_CACHE, 0); // Set the CURL options for either SOCKS or HTTP proxy. applyProxySettings(); // Cause libcurl to print all it's I/O traffic on the debug channel. From 8430328043c140fa8ccafee21c57856238e2d257 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 29 Sep 2012 17:47:15 +0200 Subject: [PATCH 23/64] Add support for uploading JP2 files. Recognizes .jp2, .j2c and .j2k extensions. Adds image/jp2 files to file picker image filter (windows and Mac, windows apparently already showed them). Show preview for jpeg 2000 files. Fixes error reporting for failed image uploads. Enforces a power-of-two size for jpeg 2000 files (seemed to make sense to do that). --- indra/llimage/llimage.cpp | 1 + indra/newview/llfloaterimagepreview.cpp | 16 +++++++++ indra/newview/llviewermenufile.cpp | 34 ++++++++++++------- indra/newview/llviewertexturelist.cpp | 40 ++++++++++++++++++----- indra/newview/llviewertexturelist.h | 1 + indra/plugins/filepicker/llfilepicker.cpp | 10 ++++-- 6 files changed, 80 insertions(+), 22 deletions(-) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index c3f4878ee..66217f902 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1239,6 +1239,7 @@ file_extensions[] = { { "bmp", IMG_CODEC_BMP }, { "tga", IMG_CODEC_TGA }, + { "j2k", IMG_CODEC_J2C }, { "j2c", IMG_CODEC_J2C }, { "jp2", IMG_CODEC_J2C }, { "texture", IMG_CODEC_J2C }, diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index d32e08847..edb961685 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -38,6 +38,7 @@ #include "llimagetga.h" #include "llimagejpeg.h" #include "llimagepng.h" +#include "llimagej2c.h" #include "llagent.h" #include "llbutton.h" @@ -423,6 +424,21 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename) } } break; + case IMG_CODEC_J2C: + { + LLPointer j2c_image = new LLImageJ2C; + + if (!j2c_image->load(src_filename)) + { + return false; + } + + if (!j2c_image->decode(raw_image, 0.0f)) + { + return false; + } + } + break; default: return false; } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 11c15d9d1..fc795f8fb 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -651,9 +651,10 @@ void upload_new_resource(const std::string& src_filename, std::string name, LLAssetStorage::LLStoreAssetCallback callback, S32 expected_upload_cost, void *userdata) -{ +{ // Generate the temporary UUID. std::string filename = gDirUtilp->getTempFilename(); + bool created_temp_file = false; LLTransactionID tid; LLAssetID uuid; @@ -678,10 +679,25 @@ void upload_new_resource(const std::string& src_filename, std::string name, upload_error(error_message, "NofileExtension", filename, args); return; } + else if (codec == IMG_CODEC_J2C) + { + asset_type = LLAssetType::AT_TEXTURE; + if (!LLViewerTextureList::verifyUploadFile(src_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; + } + filename = src_filename; + } else if (codec != IMG_CODEC_INVALID) { // It's an image file, the upload procedure is the same for all asset_type = LLAssetType::AT_TEXTURE; + created_temp_file = true; if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec)) { error_message = llformat( "Problem with file %s:\n\n%s\n", @@ -700,6 +716,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, llinfos << "Attempting to encode wav as an ogg file" << llendl; encode_result = encode_vorbis_file(src_filename, filename); + created_temp_file = true; if (LLVORBISENC_NOERR != encode_result) { @@ -815,6 +832,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, // copy the file's data segment into another file for uploading LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ + created_temp_file = true; if (out) { while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ @@ -854,11 +872,6 @@ void upload_new_resource(const std::string& src_filename, std::string name, asset_type = LLAssetType::AT_ANIMATION; filename = src_filename; } - else if(exten == "j2k" || exten == "jp2" || exten == "j2c") - { - asset_type = LLAssetType::AT_TEXTURE; - filename = src_filename; - } // else { @@ -934,11 +947,10 @@ void upload_new_resource(const std::string& src_filename, std::string name, LLSD args; args["ERROR_MESSAGE"] = error_message; LLNotificationsUtil::add("ErrorMessage", args); - if(LLFile::remove(filename) == -1) - { - lldebugs << "unable to remove temp file" << llendl; - } - //AIFIXME? LLFilePicker::instance().reset(); + } + if (created_temp_file && LLFile::remove(filename) == -1) + { + lldebugs << "unable to remove temp file" << llendl; } } // diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index d685b951e..3c89714c0 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1036,54 +1036,78 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) BOOL LLViewerTextureList::createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec) -{ +{ // Load the image LLPointer image = LLImageFormatted::createFromType(codec); if (image.isNull()) { - image->setLastError("Couldn't open the image to be uploaded."); + LLImage::setLastError("Couldn't open the image to be uploaded."); return FALSE; } if (!image->load(filename)) { - image->setLastError("Couldn't load the image to be uploaded."); + LLImage::setLastError("Couldn't load the image to be uploaded."); return FALSE; } // Decompress or expand it in a raw image structure LLPointer raw_image = new LLImageRaw; if (!image->decode(raw_image, 0.0f)) { - image->setLastError("Couldn't decode the image to be uploaded."); + LLImage::setLastError("Couldn't decode the image to be uploaded."); return FALSE; } // Check the image constraints if ((image->getComponents() != 3) && (image->getComponents() != 4)) { - image->setLastError("Image files with less than 3 or more than 4 components are not supported."); + LLImage::setLastError("Image files with less than 3 or more than 4 components are not supported."); return FALSE; } // Convert to j2c (JPEG2000) and save the file locally LLPointer compressedImage = convertToUploadFile(raw_image); if (compressedImage.isNull()) { - image->setLastError("Couldn't convert the image to jpeg2000."); + LLImage::setLastError("Couldn't convert the image to jpeg2000."); llinfos << "Couldn't convert to j2c, file : " << filename << llendl; return FALSE; } if (!compressedImage->save(out_filename)) { - image->setLastError("Couldn't create the jpeg2000 image for upload."); + LLImage::setLastError("Couldn't create the jpeg2000 image for upload."); llinfos << "Couldn't create output file : " << out_filename << llendl; return FALSE; } + return verifyUploadFile(out_filename, codec); +} + +static bool positive_power_of_two(int dim) +{ + return dim > 0 && !(dim & (dim - 1)); +} + +BOOL LLViewerTextureList::verifyUploadFile(const std::string& out_filename, const U8 codec) +{ // Test to see if the encode and save worked LLPointer integrity_test = new LLImageJ2C; if (!integrity_test->loadAndValidate( out_filename )) { - image->setLastError("The created jpeg2000 image is corrupt."); + LLImage::setLastError(std::string("The ") + ((codec == IMG_CODEC_J2C) ? "" : "created ") + "jpeg2000 image is corrupt: " + LLImage::getLastError()); llinfos << "Image file : " << out_filename << " is corrupt" << llendl; return FALSE; } + if (codec == IMG_CODEC_J2C) + { + if (integrity_test->getComponents() < 3 || integrity_test->getComponents() > 4) + { + LLImage::setLastError("Image files with less than 3 or more than 4 components are not supported."); + return FALSE; + } + else if (!positive_power_of_two(integrity_test->getWidth()) || + !positive_power_of_two(integrity_test->getHeight())) + { + LLImage::setLastError("The width or height is not a (positive) power of two."); + return FALSE; + } + } return TRUE; } diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index fa414ad5f..043a48cbd 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -68,6 +68,7 @@ class LLViewerTextureList public: static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec); + static BOOL verifyUploadFile(const std::string& out_filename, const U8 codec); static LLPointer convertToUploadFile(LLPointer raw_image); static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data ); static S32 calcMaxTextureRAM(); diff --git a/indra/plugins/filepicker/llfilepicker.cpp b/indra/plugins/filepicker/llfilepicker.cpp index 8342882c8..ed86e0f6e 100644 --- a/indra/plugins/filepicker/llfilepicker.cpp +++ b/indra/plugins/filepicker/llfilepicker.cpp @@ -729,12 +729,15 @@ Boolean LLFilePickerBase::navOpenFilterProc(AEDesc *theItem, void *info, void *c if (fileInfo.filetype != 'JPEG' && fileInfo.filetype != 'JPG ' && fileInfo.filetype != 'BMP ' && fileInfo.filetype != 'TGA ' && fileInfo.filetype != 'BMPf' && fileInfo.filetype != 'TPIC' && - fileInfo.filetype != 'PNG ' && + fileInfo.filetype != 'PNG ' && fileInfo.filetype != 'JP2' && (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("jpeg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("jpg"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("bmp"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && CFStringCompare(fileInfo.extension, CFSTR("tga"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && - CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + CFStringCompare(fileInfo.extension, CFSTR("png"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("jp2"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("j2k"), kCFCompareCaseInsensitive) != kCFCompareEqualTo && + CFStringCompare(fileInfo.extension, CFSTR("j2c"), kCFCompareCaseInsensitive) != kCFCompareEqualTo)) ) { result = false; @@ -1353,7 +1356,8 @@ static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker) gtk_file_filter_add_mime_type(gfilter, "image/jpeg"); gtk_file_filter_add_mime_type(gfilter, "image/png"); gtk_file_filter_add_mime_type(gfilter, "image/bmp"); - std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png)"; + gtk_file_filter_add_mime_type(gfilter, "image/jp2"); + std::string filtername = LLTrans::getString("image_files") + " (*.tga; *.bmp; *.jpg; *.png; *.jp2; *.j2k; *.j2c)"; add_common_filters_to_gtkchooser(gfilter, picker, filtername); return filtername; } From 3f1fb9a66e0fd4b4ad5aacea07b4bbb4833777c1 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 5 Oct 2012 15:53:29 +0200 Subject: [PATCH 24/64] Add improved timeout handling for HTTP transactions. Introduces AIHTTPTimeoutPolicy objects which do not just specify a single "timeout" in seconds, but a plethora of timings related to the life cycle of the average HTTP transaction. This knowledge is that moved to the Responder being used instead of floating constants hardcoded in the callers of http requests. This assumes that the same timeout policy is wanted for each transaction that uses the same Responder, which can be enforced is needed. I added a AIHTTPTimeoutPolicy for EVERY responder, only to make it easier later to tune timeout values and/or to get feedback about which responder runs into HTTP errors in debug output (especially time outs), so that they can be tuned later. If we already understood exactly what we were doing then most responders could have been left alone and just return the default timeout policy: by far most timeout policies are just a copy of the default policy, currently. This commit is not finished... It's a work in progress (viewer runs fine with it though). --- indra/aistatemachine/aicurl.cpp | 279 ++++++- indra/aistatemachine/aicurl.h | 4 + .../aicurleasyrequeststatemachine.cpp | 22 +- .../aicurleasyrequeststatemachine.h | 9 +- indra/aistatemachine/aicurlprivate.h | 46 +- indra/aistatemachine/aicurlthread.cpp | 16 +- indra/llcrashlogger/llcrashlogger.cpp | 13 +- indra/llcrashlogger/llcrashlogger.h | 4 +- indra/llmessage/CMakeLists.txt | 2 + indra/llmessage/aihttptimeoutpolicy.cpp | 733 ++++++++++++++++++ indra/llmessage/aihttptimeoutpolicy.h | 114 +++ indra/llmessage/llavatarnamecache.cpp | 5 + indra/llmessage/llcurl.cpp | 1 - indra/llmessage/llcurlrequest.cpp | 14 +- indra/llmessage/llcurlrequest.h | 4 +- indra/llmessage/llhttpclient.cpp | 63 +- indra/llmessage/llhttpclient.h | 79 +- indra/llmessage/llregionpresenceverifier.h | 7 + indra/llmessage/llsdmessage.cpp | 5 +- indra/llmessage/llsdmessage.h | 4 + indra/llmessage/llurlrequest.cpp | 6 +- indra/llmessage/message.cpp | 5 + indra/newview/app_settings/settings.xml | 74 +- indra/newview/floatervoicelicense.cpp | 5 +- indra/newview/hippogridmanager.cpp | 2 - indra/newview/hipporestrequest.cpp | 2 +- indra/newview/lggdicdownload.cpp | 3 + indra/newview/llaccountingcostmanager.cpp | 5 + indra/newview/llappviewer.cpp | 14 +- indra/newview/llassetuploadresponders.cpp | 6 +- indra/newview/llassetuploadresponders.h | 6 + indra/newview/llcapabilitylistener.cpp | 5 +- indra/newview/llclassifiedstatsresponder.h | 4 + indra/newview/lleventpoll.cpp | 4 + indra/newview/llfloateractivespeakers.cpp | 10 + indra/newview/llfloaterregiondebugconsole.cpp | 9 + indra/newview/llfloaterregiondebugconsole.h | 4 + indra/newview/llfloaterregioninfo.cpp | 6 + indra/newview/llfloaterreporter.cpp | 6 +- indra/newview/llfloaterteleport.cpp | 4 + indra/newview/llfloatertos.cpp | 4 + indra/newview/llfloaterurlentry.cpp | 5 + indra/newview/llhomelocationresponder.h | 4 + indra/newview/llimpanel.cpp | 10 + indra/newview/llimview.cpp | 6 +- indra/newview/llinventorymodel.cpp | 5 + indra/newview/llinventorymodel.h | 6 +- .../llinventorymodelbackgroundfetch.cpp | 12 +- indra/newview/llmapresponders.h | 4 + indra/newview/llmeshrepository.cpp | 17 + indra/newview/llpanelgroupvoting.cpp | 18 +- indra/newview/llpanellogin.cpp | 5 + indra/newview/llpathfindingmanager.cpp | 41 +- indra/newview/llproductinforequest.cpp | 5 + indra/newview/llremoteparcelrequest.h | 4 + indra/newview/lltexturefetch.cpp | 11 +- indra/newview/lltranslate.h | 5 + indra/newview/lluploadfloaterobservers.h | 5 + indra/newview/llviewerdisplayname.cpp | 5 + indra/newview/llviewermedia.cpp | 12 +- indra/newview/llviewerobjectlist.cpp | 9 +- indra/newview/llviewerregion.cpp | 19 +- indra/newview/llviewerstats.cpp | 4 + indra/newview/llvoavatar.cpp | 1 + indra/newview/llvoiceclient.cpp | 8 +- indra/newview/llwlhandlers.h | 7 + indra/newview/llxmlrpctransaction.cpp | 16 +- 67 files changed, 1654 insertions(+), 198 deletions(-) create mode 100644 indra/llmessage/aihttptimeoutpolicy.cpp create mode 100644 indra/llmessage/aihttptimeoutpolicy.h diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index c20983f16..453098801 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -56,8 +56,22 @@ #include "llproxy.h" #include "llhttpstatuscodes.h" #include "aihttpheaders.h" +#include "aihttptimeoutpolicy.h" +#include "aicurleasyrequeststatemachine.h" #ifdef CWDEBUG #include +#include +#define DoutCurlEasy(x) do { \ + using namespace libcwd; \ + std::ostringstream marker; \ + marker << (void*)this->get_lockobj(); \ + libcw_do.push_marker(); \ + libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ + Dout(dc::curl, x); \ + libcw_do.pop_marker(); \ + } while(0) +#else +#define DoutCurlEasy(x) Dout(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') #endif //================================================================================== @@ -446,6 +460,11 @@ void Responder::setURL(std::string const& url) mURL = url; } +AIHTTPTimeoutPolicy const& Responder::getHTTPTimeoutPolicy(void) const +{ + return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); +} + // Called with HTML header. // virtual void Responder::completedHeaders(U32, std::string const&, AIHTTPHeaders const&) @@ -778,9 +797,9 @@ DEFINE_FUNCTION_SETOPT1(curl_debug_callback, CURLOPT_DEBUGFUNCTION) DEFINE_FUNCTION_SETOPT4(curl_write_callback, CURLOPT_HEADERFUNCTION, CURLOPT_WRITEFUNCTION, CURLOPT_INTERLEAVEFUNCTION, CURLOPT_READFUNCTION) //DEFINE_FUNCTION_SETOPT1(curl_read_callback, CURLOPT_READFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_ssl_ctx_callback, CURLOPT_SSL_CTX_FUNCTION) +DEFINE_FUNCTION_SETOPT1(curl_progress_callback, CURLOPT_PROGRESSFUNCTION) DEFINE_FUNCTION_SETOPT3(curl_conv_callback, CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPT_CONV_FROM_UTF8_FUNCTION) #if 0 // Not used by the viewer. -DEFINE_FUNCTION_SETOPT1(curl_progress_callback, CURLOPT_PROGRESSFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_seek_callback, CURLOPT_SEEKFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_ioctl_callback, CURLOPT_IOCTLFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_sockopt_callback, CURLOPT_SOCKOPTFUNCTION) @@ -805,7 +824,7 @@ void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size) { llassert_always(postdata->data()); - Dout(dc::curl, "POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\"."); + DoutCurlEasy("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\"."); setPostField(postdata); // Make sure the data stays around until we don't need it anymore. setPost_raw(size, postdata->data()); @@ -816,7 +835,7 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data) if (!data) { // data == NULL when we're going to read the data using CURLOPT_READFUNCTION. - Dout(dc::curl, "POST size is " << size << " bytes."); + DoutCurlEasy("POST size is " << size << " bytes."); } // Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)). @@ -906,6 +925,24 @@ void CurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* us setopt(CURLOPT_SSL_CTX_DATA, this); } +//static +int CurlEasyRequest::progressCallback(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) +{ + CurlEasyRequest* self = static_cast(userdata); + ThreadSafeCurlEasyRequest* lockobj = self->get_lockobj(); + AICurlEasyRequest_wat lock_self(*lockobj); + return self->mProgressCallback(self->mProgressCallbackUserData, dltotal, dlnow, ultotal, ulnow); +} + +void CurlEasyRequest::setProgressCallback(curl_progress_callback callback, void* userdata) +{ + mProgressCallback = callback; + mProgressCallbackUserData = userdata; + setopt(CURLOPT_PROGRESSFUNCTION, callback ? &CurlEasyRequest::progressCallback : NULL); + setopt(CURLOPT_PROGRESSDATA, userdata ? this : NULL); + setopt(CURLOPT_NOPROGRESS, callback ? 0L: 1L); +} + #define llmaybewarns lllog(LLApp::isExiting() ? LLError::LEVEL_INFO : LLError::LEVEL_WARN, NULL, NULL, false, true) static size_t noHeaderCallback(char* ptr, size_t size, size_t nmemb, void* userdata) @@ -932,12 +969,19 @@ static CURLcode noSSLCtxCallback(CURL* curl, void* sslctx, void* parm) return CURLE_ABORTED_BY_CALLBACK; } +static int noProgressCallback(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) +{ + llmaybewarns << "Calling noProgressCallback(); curl session aborted." << llendl; + return CURLE_ABORTED_BY_CALLBACK; +} + void CurlEasyRequest::revokeCallbacks(void) { if (mHeaderCallback == &noHeaderCallback && mWriteCallback == &noWriteCallback && mReadCallback == &noReadCallback && - mSSLCtxCallback == &noSSLCtxCallback) + mSSLCtxCallback == &noSSLCtxCallback && + mProgressCallback == &noProgressCallback) { // Already revoked. return; @@ -946,6 +990,7 @@ void CurlEasyRequest::revokeCallbacks(void) mWriteCallback = &noWriteCallback; mReadCallback = &noReadCallback; mSSLCtxCallback = &noSSLCtxCallback; + mProgressCallback = &noProgressCallback; if (active() && !no_warning()) { llwarns << "Revoking callbacks on a still active CurlEasyRequest object!" << llendl; @@ -954,6 +999,7 @@ void CurlEasyRequest::revokeCallbacks(void) curl_easy_setopt(getEasyHandle(), CURLOPT_WRITEHEADER, &noWriteCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_READFUNCTION, &noReadCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_SSL_CTX_FUNCTION, &noSSLCtxCallback); + curl_easy_setopt(getEasyHandle(), CURLOPT_PROGRESSFUNCTION, &noProgressCallback); } CurlEasyRequest::~CurlEasyRequest() @@ -1167,8 +1213,8 @@ void CurlEasyRequest::applyDefaultOptions(void) setoptString(CURLOPT_CAINFO, CertificateAuthority_r->file); setSSLCtxCallback(&curlCtxCallback, NULL); setopt(CURLOPT_NOSIGNAL, 1); - // The old code did this for the 'buffered' version, but I think it's nonsense. - //setopt(CURLOPT_DNS_CACHE_TIMEOUT, 0); + // Cache DNS look ups an hour. If we set it smaller we risk frequent connect timeouts in cases where DNS look ups are slow. + setopt(CURLOPT_DNS_CACHE_TIMEOUT, 3600); // Disable SSL/TLS session caching; some servers (aka id.secondlife.com) refuse connections when session ids are enabled. setopt(CURLOPT_SSL_SESSIONID_CACHE, 0); // Set the CURL options for either SOCKS or HTTP proxy. @@ -1184,7 +1230,7 @@ void CurlEasyRequest::applyDefaultOptions(void) ); } -void CurlEasyRequest::finalizeRequest(std::string const& url) +void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine) { llassert(!mRequestFinalized); mResult = CURLE_FAILED_INIT; // General error code; the final result code is stored here by MultiHandle::check_run_count when msg is CURLMSG_DONE. @@ -1207,6 +1253,8 @@ void CurlEasyRequest::finalizeRequest(std::string const& url) mRequestFinalized = true; setopt(CURLOPT_HTTPHEADER, mHeaders); setoptString(CURLOPT_URL, url); + mTimeoutPolicy = &policy; + state_machine->setTotalDelayTimeout(policy.getTotalDelay()); // The following line is a bit tricky: we store a pointer to the object without increasing its reference count. // Of course we could increment the reference count, but that doesn't help much: if then this pointer would // get "lost" we'd have a memory leak. Either way we must make sure that it is impossible that this pointer @@ -1224,6 +1272,208 @@ void CurlEasyRequest::finalizeRequest(std::string const& url) setopt(CURLOPT_PRIVATE, get_lockobj()); } +//............................................................................. +// HTTP Timeout stuff + +// url must be of the form +// (see http://www.ietf.org/rfc/rfc3986.txt Appendix A for definitions not given here): +// +// url = sheme ":" hier-part [ "?" query ] [ "#" fragment ] +// hier-part = "//" authority path-abempty +// authority = [ userinfo "@" ] host [ ":" port ] +// path-abempty = *( "/" segment ) +// +// That is, a hier-part of the form '/ path-absolute', '/ path-rootless' or +// '/ path-empty' is NOT allowed here. This should be safe because we only +// call this function for curl access, any file access would use APR. +// +// However, as a special exception, this function allows: +// +// url = authority path-abempty +// +// without the 'sheme ":" "//"' parts. +// +// As follows from the ABNF (see RFC, Appendix A): +// - authority is either terminated by a '/' or by the end of the string because +// neither userinfo, host nor port may contain a '/'. +// - userinfo does not contain a '@', and if it exists, is always terminated by a '@'. +// - port does not contain a ':', and if it exists is always prepended by a ':'. +// +// Only called by CurlEasyRequest::timeout_add_easy_request. +static std::string extract_canonical_hostname(std::string url) +{ + std::string::size_type pos; + std::string::size_type authority = 0; // Default if there is no sheme. + if ((pos = url.find("://")) != url.npos && pos < url.find('/')) authority = pos + 3; // Skip the "sheme://" if any, the second find is to avoid finding a "://" as part of path-abempty. + std::string::size_type host = authority; // Default if there is no userinfo. + if ((pos = url.find('@', authority)) != url.npos) host = pos + 1; // Skip the "userinfo@" if any. + authority = url.length() - 1; // Default last character of host if there is no path-abempty. + if ((pos = url.find('/', host)) != url.npos) authority = pos - 1; // Point to last character of host. + std::string::size_type len = url.find_last_not_of(":0123456789", authority) - host + 1; // Skip trailing ":port", if any. + std::string hostname(url, host, len); +#if APR_CHARSET_EBCDIC +#error Not implemented +#else + // Convert hostname to lowercase in a way that we compare two hostnames equal iff libcurl does. + for (std::string::iterator iter = hostname.begin(); iter != hostname.end(); ++iter) + { + int c = *iter; + if (c >= 'A' && c <= 'Z') + *iter = c + ('a' - 'A'); + } +#endif + return hostname; +} + +// CURL-THREAD +// This is called when the easy handle is actually being added to the multi handle (thus after being queued). +void CurlEasyRequest::timeout_add_easy_request(void) +{ + char* eff_url; + getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); // According to a discussion on IRC with a curl developer, we can rely on this returning the set CURLOPT_URL at this point. + setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(extract_canonical_hostname(eff_url))); + setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); + // We do NOT use CURLOPT_LOW_SPEED_TIME and CURLOPT_LOW_SPEED_LIMIT, + // instead use a progress meter callback. + setProgressCallback(&AICurlPrivate::CurlEasyRequest::timeout_progress, this); + // This boolean is valid (only) if we get a time out event from libcurl. + mTimeoutConnected = false; +} + +// CURL-THREAD +// This is called when the connection succeeded (thus after DNS lookup and connect). +void CurlEasyRequest::timeout_connected(void) +{ + DoutCurlEasy("Calling CurlEasyRequest::timeout_connected(): mTimeoutWaitingForReply = false"); + mTimeoutConnected = true; +#ifdef CWDEBUG + mTimeout_connect_time = get_clock_count(); +#endif + // Now that mTimeoutConnected is set we'll be calling timeout_progress(); initialize the variables used there. + mTimeout_dlnow = 0; + mTimeout_ulnow = 0; + mTimeout_progress_time = 0; + mTimeoutWaitingForReply = false; + mTimeoutNothingReceivedYet = true; +} + +// CURL-THREAD +// This is called when data was sent to the server socket. +void CurlEasyRequest::timeout_data_sent(size_t n) +{ + if (!mTimeoutConnected) + { + // If we can send data (for the first time) then that's our way to know we connected. + timeout_connected(); + } +} + +// CURL-THREAD +// This is called when data was received from the server. +void CurlEasyRequest::timeout_data_received(size_t n) +{ + if (n > 0) + { +#ifdef CWDEBUG + if (mTimeoutNothingReceivedYet) + DoutCurlEasy("CurlEasyRequest::timeout_data_received(): Received data from server: set mTimeoutWaitingForReply = false"); +#endif + // We received something, now switch to getLowSpeedLimit()/getLowSpeedTime(). + mTimeoutWaitingForReply = false; + mTimeoutNothingReceivedYet = false; + } +} + +// CURL_THREAD +//static +int CurlEasyRequest::timeout_progress(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) +{ + CurlEasyRequest* self = static_cast(userdata); + + //AIFIXME: There has to be a better way to determine this (because it feels fuzzy, I only allow it to SET the boolean): +#ifdef CWDEBUG + if (!self->mTimeoutWaitingForReply && (self->mTimeoutNothingReceivedYet && ultotal > 0 && ulnow == ultotal)) + Dout(dc::curl, "CurlEasyRequest::timeout_progress(): uploading data finished: set mTimeoutWaitingForReply = true [" << (void*)self->get_lockobj() << ']'); +#endif + llassert(ulnow == 0 || ultotal > 0); // Do we always know the total upload size? + self->mTimeoutWaitingForReply = self->mTimeoutWaitingForReply || (self->mTimeoutNothingReceivedYet && ultotal > 0 && ulnow == ultotal); + + return self->mTimeoutConnected ? self->timeout_progress(dlnow, ulnow) : 0; +} + +// CURL_THREAD +// dlnow is the number of bytes of the BODY of the message, received from the server. +// ulnow is the number of bytes of the BODY of the message, sent to the server so far. +// +// Note that the algorithm used here is basically the same as libcurl uses +// for CURLOPT_LOW_SPEED_LIMIT / CURLOPT_LOW_SPEED_TIME, but we can't use that +// because we need to change the variables involved during transfer, which isn't +// officially supported by libcurl. +// Libcurl does the progress callback at the exact same point as checking for +// low speed, and the same data is passed (except the time, unfortunately), so +// the functionality is the same. +int CurlEasyRequest::timeout_progress(double dlnow, double ulnow) +{ + static double const clock_frequency = calc_clock_frequency(); + U64 last_time = mTimeout_progress_time; + mTimeout_progress_time = get_clock_count(); + double transfer = (dlnow - mTimeout_dlnow) + (ulnow - mTimeout_ulnow); // Just combine up and download :p. + mTimeout_dlnow = dlnow; + mTimeout_ulnow = ulnow; + if (!last_time || mTimeout_progress_time == last_time) // Is this the first time this function is called (or are we called infinitely fast)? + { + DoutCurlEasy("timeout_progress(" << dlnow << ", " << ulnow << ") called at " << + ((mTimeout_progress_time - mTimeout_connect_time) / clock_frequency) << " seconds after connect" << + (last_time ? "" : " (first time)")); + // Start the timer: we need to have a too low transfer rate, for at least + // mTimeoutPolicy->getLowSpeedTime() seconds, counting from this moment. + mTransferOK = mTimeout_progress_time; + return 0; + } + transfer *= clock_frequency / (mTimeout_progress_time - last_time); // Bytes per second. + U64 timer = mTimeout_progress_time - mTransferOK; // Low speed timer in clock ticks. + U16 lowspeedtime = mTimeoutWaitingForReply ? mTimeoutPolicy->getReplyDelay() : mTimeoutPolicy->getLowSpeedTime(); + U32 lowspeedlimit = mTimeoutWaitingForReply ? (U32)1 : mTimeoutPolicy->getLowSpeedLimit(); + DoutCurlEasy("timeout_progress(" << dlnow << ", " << ulnow << ") called at " << ((mTimeout_progress_time - mTimeout_connect_time) / clock_frequency) << + " seconds after connect (timer = " << (timer / clock_frequency) << " s ; transfer = " << transfer << " bytes/s; lowspeedtime = " << lowspeedtime << + "; lowspeedlimit = " << lowspeedlimit << " (mTimeoutWaitingForReply == " << (mTimeoutWaitingForReply ? "true" : "false") << "))"); + if (transfer >= lowspeedlimit) + { + // Yay! Transfer rate is OK; restart timeout timer. + mTransferOK = mTimeout_progress_time; + } + else if (timer > clock_frequency * lowspeedtime) + { + // We haven't seen a high enough transfer rate for too long. Abort the transfer. + llwarns << +#ifdef CWDEBUG + (void*)get_lockobj() << ": " +#endif + "aborting slow connection (transfer rate below " << lowspeedlimit << + " for more than " << lowspeedtime << " second" << ((lowspeedtime == 1) ? "" : "s") << ")." << llendl; + return 1; + } + return 0; +} + +// CURL-THREAD +// This is called immediately before done() after curl finished, with code. +void CurlEasyRequest::timeout_done(CURLcode code) +{ + if (code == CURLE_OPERATION_TIMEDOUT && !mTimeoutConnected) + { + char* eff_url; + getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); //AIFIXME: cache hostname, cause this might have changed. + AIHTTPTimeoutPolicy::connect_timed_out(extract_canonical_hostname(eff_url)); + // AIFIXME: use return value to change priority + } + // Abuse this boolean to tell any subsequent call to timeout_progress that this certainly can't timeout anymore. + mTimeoutConnected = false; +} + +// End of HTTP Timeout stuff. +//............................................................................. + void CurlEasyRequest::getTransferInfo(AICurlInterface::TransferInfo* info) { // Curl explicitly demands a double for these info's. @@ -1268,8 +1518,6 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy // CurlResponderBuffer static int const HTTP_REDIRECTS_DEFAULT = 10; -static S32 const CURL_REQUEST_TIMEOUT = 30; // The minimum value of the CURLOPT_TIMEOUT option (which is the maximum - // time in seconds that we allow a libcurl transfer operation to take). LLChannelDescriptors const CurlResponderBuffer::sChannels; @@ -1334,7 +1582,7 @@ ThreadSafeBufferedCurlEasyRequest* CurlResponderBuffer::get_lockobj(void) return static_cast(AIThreadSafeSimple::wrapper_cast(this)); } -void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder, S32 time_out) +void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder) { mInput.reset(new LLBufferArray); mInput->setThreaded(true); @@ -1359,8 +1607,6 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w // Don't verify host name so urls with scrubbed host names will work (improves DNS performance). curl_easy_request_w->setopt(CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_request_w->setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT)); - // Keep responder alive. mResponder = responder; // Send header events to responder if needed. @@ -1387,7 +1633,8 @@ size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nm // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); - buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. + buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. + buffered_easy_request_w->timeout_data_received(bytes); // Timeout administration. return bytes; } @@ -1403,7 +1650,8 @@ size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nme S32 bytes = size * nmemb; // The maximum amount to read. AICurlResponderBuffer_wat buffer_w(*lockobj); buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); - buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + buffered_easy_request_w->timeout_data_sent(bytes); // Timeout administration. return bytes; // Return the amount actually read (might be lowered by readAfter()). } @@ -1420,6 +1668,7 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n char const* const header_line = static_cast(data); size_t const header_len = size * nmemb; + buffered_easy_request_w->timeout_data_received(header_len); // Timeout administration. if (!header_len) { @@ -1504,7 +1753,7 @@ void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w) void CurlResponderBuffer::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) { - Dout(dc::curl, "Calling CurlResponderBuffer::removed_from_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); + DoutCurlEasy("Calling CurlResponderBuffer::removed_from_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); // Lock self. ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index e0296f865..e19ae15e0 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -57,6 +57,7 @@ class LLSD; class LLBufferArray; class LLChannelDescriptors; +class AIHTTPTimeoutPolicy; //----------------------------------------------------------------------------- // Exceptions. @@ -210,6 +211,9 @@ class Responder : public AICurlResponderBufferEvents { // Derived classes that implement completedHeaders() should return true here. virtual bool needsHeaders(void) const { return false; } + // Timeout policy to use. + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; + // Derived classes can override this to get the raw data of the body of the HTML message that was received. // The default is to interpret the content as LLSD and call completed(). virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index 9060779ee..868419e91 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -30,6 +30,7 @@ #include "linden_common.h" #include "aicurleasyrequeststatemachine.h" +#include "aihttptimeoutpolicy.h" #include "llcontrol.h" enum curleasyrequeststatemachine_state_type { @@ -61,7 +62,7 @@ void AICurlEasyRequestStateMachine::initialize_impl(void) { { AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); - llassert(curlEasyRequest_w->is_finalized()); // Call finalizeRequest(url) before calling run(). + llassert(curlEasyRequest_w->is_finalized()); // Call finalizeRequest() before calling run(). curlEasyRequest_w->send_events_to(this); } mAdded = false; @@ -116,13 +117,13 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void) // 3) AICurlEasyRequestStateMachine_finished (running) // 4) AICurlEasyRequestStateMachine_removed_after_finished (running) - if (mRequestTimeOut > 0.f) + if (mTotalDelayTimeout > 0.f) { // Set an inactivity timer. // This shouldn't really be necessary, except in the case of a bug // in libcurl; but lets be sure and set a timer for inactivity. mTimer = new AIPersistentTimer; // Do not delete timer upon expiration. - mTimer->setInterval(mRequestTimeOut); + mTimer->setInterval(mTotalDelayTimeout); mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false); } break; @@ -246,7 +247,7 @@ void AICurlEasyRequestStateMachine::finish_impl(void) } AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : - mBuffered(buffered), mCurlEasyRequest(buffered), mTimer(NULL), mRequestTimeOut(sCurlRequestTimeOut) + mBuffered(buffered), mCurlEasyRequest(buffered), mTimer(NULL), mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay()) { Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); if (!mBuffered) @@ -255,18 +256,9 @@ AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : } } -//static -F32 AICurlEasyRequestStateMachine::sCurlRequestTimeOut = 40.f; - -//static -void AICurlEasyRequestStateMachine::setDefaultRequestTimeOut(F32 defaultRequestTimeOut) +void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout) { - sCurlRequestTimeOut = defaultRequestTimeOut; -} - -void AICurlEasyRequestStateMachine::setRequestTimeOut(F32 curlRequestTimeOut) -{ - mRequestTimeOut = curlRequestTimeOut; + mTotalDelayTimeout = totalDelayTimeout; } AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine() diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.h b/indra/aistatemachine/aicurleasyrequeststatemachine.h index ec46c43bc..3878a597e 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.h +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.h @@ -64,16 +64,11 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa bool mFinished; // Set by the curl thread to signal it finished. bool mHandled; // Set when we processed the received data. AITimer* mTimer; // Expiration timer. - F32 mRequestTimeOut; // The time out value for mTimer. - - static F32 sCurlRequestTimeOut; // The default time out value for mTimer (CurlRequestTimeOut debug setting). + F32 mTotalDelayTimeout; // The time out value for mTimer. public: - // Called once to set a different timeout then the default of 40 seconds. - static void setDefaultRequestTimeOut(F32 defaultRequestTimeOut); - // Called to set a specific time out, instead of the default one. - void setRequestTimeOut(F32 requestTimeOut); + void setTotalDelayTimeout(F32 totalDelayTimeout); protected: // AICurlEasyRequest Events. diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index bef49e0f0..59c7d01dd 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -35,6 +35,8 @@ #include "llatomic.h" class AIHTTPHeaders; +class AIHTTPTimeoutPolicy; +class AICurlEasyRequestStateMachine; namespace AICurlPrivate { namespace curlthread { class MultiHandle; } @@ -87,9 +89,9 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven DECLARE_SETOPT(curl_write_callback); //DECLARE_SETOPT(curl_read_callback); Same type as curl_write_callback DECLARE_SETOPT(curl_ssl_ctx_callback); + DECLARE_SETOPT(curl_progress_callback); DECLARE_SETOPT(curl_conv_callback); #if 0 // Not used by the viewer. - DECLARE_SETOPT(curl_progress_callback); DECLARE_SETOPT(curl_seek_callback); DECLARE_SETOPT(curl_ioctl_callback); DECLARE_SETOPT(curl_sockopt_callback); @@ -225,6 +227,7 @@ class CurlEasyRequest : public CurlEasyHandle { static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata); static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata); static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata); + static int progressCallback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow); curl_write_callback mHeaderCallback; void* mHeaderCallbackUserData; @@ -234,12 +237,15 @@ class CurlEasyRequest : public CurlEasyHandle { void* mReadCallbackUserData; curl_ssl_ctx_callback mSSLCtxCallback; void* mSSLCtxCallbackUserData; + curl_progress_callback mProgressCallback; + void* mProgressCallbackUserData; public: void setHeaderCallback(curl_write_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 setProgressCallback(curl_progress_callback callback, void* userdata); // Call this if the set callbacks are about to be invalidated. void revokeCallbacks(void); @@ -260,7 +266,26 @@ class CurlEasyRequest : public CurlEasyHandle { // Prepare the request for adding it to a multi session, or calling perform. // This actually adds the headers that were collected with addHeader. - void finalizeRequest(std::string const& url); + void finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine); + + // Called by MultiHandle::add_easy_request when the easy handle is actually being added to the multi handle. + void timeout_add_easy_request(void); + + // Called when data was written the first time, meaning that the connection succeeded. + void timeout_connected(void); + + // Called when data is sent. + void timeout_data_sent(size_t n); + + // Called when data is received. + void timeout_data_received(size_t n); + + // Called immediately before done() after curl finished, with code. + void timeout_done(CURLcode code); + + // Progress meter callback. + static int timeout_progress(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow); + int timeout_progress(double dlnow, double ulnow); // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. void store_result(CURLcode result) { mResult = result; } @@ -280,12 +305,25 @@ class CurlEasyRequest : public CurlEasyHandle { AICurlEasyHandleEvents* mEventsTarget; CURLcode mResult; + // AIFIXME: put all timeout stuff in it's own class. + AIHTTPTimeoutPolicy const* mTimeoutPolicy; + bool mTimeoutConnected; // Set if we succeeded to connect and are transfering data. +#ifdef CWDEBUG + U64 mTimeout_connect_time; // Time at which mTimeoutConnected was set to true (for debugging purposes only). +#endif + bool mTimeoutWaitingForReply; // Set after we finished sending data to the server and are waiting for the reply. + bool mTimeoutNothingReceivedYet; // Set when connected, reset when the HTML reply header from the server is received. + U64 mTimeout_progress_time; // The (last) time timeout_progress() was called, in microseconds. + U64 mTransferOK; // The last time the transfer rate was OK. + double mTimeout_dlnow; // Number of downloaded bytes so far, as per last call to timeout_progress. + double mTimeout_ulnow; // Number of uploaded bytes so far, as per last call to timeout_progress. + private: // This class may only be created by constructing a ThreadSafeCurlEasyRequest. friend class ThreadSafeCurlEasyRequest; // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : - mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT) + mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL) { applyDefaultOptions(); } public: ~CurlEasyRequest(); @@ -327,7 +365,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t; void resetState(AICurlEasyRequest_wat& curl_easy_request_w); - void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0); + void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder); buffer_ptr_t& getInput(void) { return mInput; } buffer_ptr_t& getOutput(void) { return mOutput; } diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index c29092271..c593ec910 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1382,7 +1382,12 @@ char const* action_str(int action) //static int MultiHandle::socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp) { - DoutEntering(dc::curl, "MultiHandle::socket_callback((CURL*)" << (void*)easy << ", " << s << ", " << action_str(action) << ", " << (void*)userp << ", " << (void*)socketp << ")"); +#ifdef CWDEBUG + ThreadSafeCurlEasyRequest* lockobj = NULL; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, &lockobj); + DoutEntering(dc::curl, "MultiHandle::socket_callback((CURL*)" << (void*)easy << ", " << s << + ", " << action_str(action) << ", " << (void*)userp << ", " << (void*)socketp << ") [CURLINFO_PRIVATE = " << (void*)lockobj << "]"); +#endif MultiHandle& self = *static_cast(userp); CurlSocketInfo* sock_info = static_cast(socketp); if (action == CURL_POLL_REMOVE) @@ -1449,6 +1454,7 @@ void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) CURLMcode ret; { AICurlEasyRequest_wat curl_easy_request_w(*easy_request); + curl_easy_request_w->timeout_add_easy_request(); ret = curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle); } if (ret == CURLM_OK) @@ -1456,7 +1462,7 @@ void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) mHandleAddedOrRemoved = true; std::pair res = mAddedEasyRequests.insert(easy_request); llassert(res.second); // May not have been added before. - Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); + Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get_ptr().get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); return; } } @@ -1506,7 +1512,7 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request } mAddedEasyRequests.erase(iter); mHandleAddedOrRemoved = true; - Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)easy_request.get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); + Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)easy_request.get_ptr().get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); // Attempt to add a queued request, if any. if (!mQueuedRequests.empty()) @@ -1541,8 +1547,10 @@ void MultiHandle::check_run_count(void) #ifdef CWDEBUG char* eff_url; curl_easy_request_w->getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); - Dout(dc::curl, "Finished: " << eff_url << " (" << msg->data.result << ")"); + Dout(dc::curl, "Finished: " << eff_url << " (" << curl_easy_strerror(msg->data.result) << ") [CURLINFO_PRIVATE = " << (void*)ptr << "]"); #endif + // Update timeout administration. + curl_easy_request_w->timeout_done(msg->data.result); // Signal that this easy handle finished. curl_easy_request_w->done(curl_easy_request_w); } diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 5e5010c64..f5e9a1932 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -53,9 +53,14 @@ LLPumpIO* gServicePump; BOOL gBreak = false; BOOL gSent = false; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout; + class LLCrashLoggerResponder : public LLHTTPClient::Responder { public: + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return crashLoggerResponder_timeout; } + LLCrashLoggerResponder() { } @@ -308,14 +313,14 @@ bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior) return true; } -bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout) +bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries) { gBreak = false; std::string status_message; for(int i = 0; i < retries; ++i) { status_message = llformat("%s, try %d...", msg.c_str(), i+1); - LLHTTPClient::post4(host, data, new LLCrashLoggerResponder(), timeout); + LLHTTPClient::post4(host, data, new LLCrashLoggerResponder); while(!gBreak) { updateApplication(status_message); @@ -350,12 +355,12 @@ bool LLCrashLogger::sendCrashLogs() // *TODO: Translate if(mCrashHost != "") { - sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5); + sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3); } if(!sent) { - sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3, 5); + sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3); } mSentCrashLogs = sent; diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index 72c1f3fb8..08e4a5f9f 100644 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -40,6 +40,8 @@ #include "llsd.h" #include "llcontrol.h" +class AIHTTPTimeoutPolicy; + class LLCrashLogger : public LLApp { public: @@ -57,7 +59,7 @@ public: virtual bool cleanup() { return true; } void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } S32 getCrashBehavior() { return mCrashBehavior; } - bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout); + bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries); protected: S32 mCrashBehavior; BOOL mCrashInPreviousExec; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 0c0650330..ec697c4a3 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -21,6 +21,7 @@ include_directories( set(llmessage_SOURCE_FILES aihttpheaders.cpp + aihttptimeoutpolicy.cpp llhttpclient.cpp llares.cpp llareslistener.cpp @@ -106,6 +107,7 @@ set(llmessage_HEADER_FILES CMakeLists.txt aihttpheaders.h + aihttptimeoutpolicy.h llares.h llareslistener.h llassetstorage.h diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp new file mode 100644 index 000000000..55a2e7ad4 --- /dev/null +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -0,0 +1,733 @@ +/** + * @file aihttptimeoutpolicy.cpp + * @brief Implementation of AIHTTPTimeoutPolicy + * + * Copyright (c) 2012, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 24/08/2012 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include "aihttptimeoutpolicy.h" +#include "llerror.h" +#include "lldefs.h" +#include "v3math.h" +#include + +//! +// Timing of a HTML connection. +// +// Request call +// | +// v ... <--low speed time--> ... ... <--low speed time--> ... +// <--request queued--><--DNS lookup--><--connect margin--><--data transfer to server--><--reply delay--><--data transfer from server--> +// <------------------------------------------curl transaction-----------------------------------------------------> +// <--------------------------------------------------------------total delay----------------------------------------------------------> +// | +// v +// finished +// For now, low speed limit is the same for up and download: usually download is (much) higher, but we have to take into account that +// there might also be multiple downloads at the same time, more than simultaneous uploads. + +// Absolute maxima (min/max range): +// These values are intuitively determined and rather arbitrary. + +namespace { + +U16 const ABS_min_DNS_lookup = 0; // Rationale: If a FAST roundtrip is demanded, then setting the DNS lookup grace time + // at 0 seconds will not make a connection fail when the lookup takes 1 second, it + // just means that no EXTRA time is added to the connect time. +U16 const ABS_max_DNS_lookup = 300; // Waiting longer than 5 minutes never makes sense. + +U16 const ABS_min_connect_time = 1; // Can't demand 0 seconds, and we deal with integer numbers here. +U16 const ABS_max_connect_time = 30; // Making a TCP/IP connection should REALLY succeed within 30 seconds or we rather try again. + +U16 const ABS_min_reply_delay = 1; // Can't demand 0 seconds, and we deal with integer numbers here. +U16 const ABS_max_reply_delay = 120; // If the server needs more than 2 minutes to find the reply then something just HAS to be wrong :/. + +U16 const ABS_min_low_speed_time = 4; // Intuitively, I think it makes no sense to average a download speed over less than 4 seconds. +U16 const ABS_max_low_speed_time = 120; // Averaging it over a time considerably larger than the normal timeout periods makes no sense either. + +U32 const ABS_min_low_speed_limit = 1000; // AIFIXME: this should be 1 byte/s, set at 1000 now for debugging purposes. +U32 const ABS_max_low_speed_limit = 1000000; // This limit almost certainly higher than what the maximum speed you get from the server! + +U16 const ABS_min_transaction = 60; // This is an absurd low value for experimentation. In reality, you should control + // termination of really slow connections through the low_speed settings. +U16 const ABS_max_transaction = 1200; // Insane long time. Downloads a texture of 4 MB at 3.5 kB/s. Textures are compressed though ;). + +U16 const ABS_min_total_delay = 60; // This is an absurd low value for experimentation. In reality, you should control + // termination of really slow connections through the low_speed settings. +U16 const ABS_max_total_delay = 3000; // Insane long time, for when someone wants to be ABSOLUTELY sure this isn't the bottleneck. + +using namespace AIHTTPTimeoutPolicyOperators; + +// Default policy values. +U16 const AITP_default_DNS_lookup_grace = 60; // Allow for 60 seconds long DNS look ups. +U16 const AITP_default_maximum_connect_time = 10; // Allow the SSL/TLS connection through a proxy, including handshakes, to take up to 10 seconds. +U16 const AITP_default_maximum_reply_delay = 60; // Allow the server 60 seconds to do whatever it has to do before starting to send data. +U16 const AITP_default_low_speed_time = 30; // If a transfer speed drops below AITP_default_low_speed_limit bytes/s for 30 seconds, terminate the transfer. +U32 const AITP_default_low_speed_limit = 56000; // In bytes per second (use for CURLOPT_LOW_SPEED_LIMIT). +U16 const AITP_default_maximum_curl_transaction = 300; // Allow large files to be transfered over slow connections. +U16 const AITP_default_maximum_total_delay = 600; // Avoid "leaking" by terminating anything that wasn't completed after 10 minutes. + +} // namespace + +AIHTTPTimeoutPolicy& AIHTTPTimeoutPolicy::operator=(AIHTTPTimeoutPolicy const& rhs) +{ + // You're not allowed to assign to a policy that is based on another policy. + llassert(!mBase); + mDNSLookupGrace = rhs.mDNSLookupGrace; + mMaximumConnectTime = rhs.mMaximumConnectTime; + mMaximumReplyDelay = rhs.mMaximumReplyDelay; + mLowSpeedTime = rhs.mLowSpeedTime; + mLowSpeedLimit = rhs.mLowSpeedLimit; + mMaximumCurlTransaction = rhs.mMaximumCurlTransaction; + mMaximumTotalDelay = rhs.mMaximumTotalDelay; + return *this; +} + +AIHTTPTimeoutPolicy::AIHTTPTimeoutPolicy(char const* name, + U16 dns_lookup_grace, U16 subsequent_connects, U16 reply_delay, + U16 low_speed_time, U32 low_speed_limit, + U16 curl_transaction, U16 total_delay) : + mName(name), + mBase(NULL), + mDNSLookupGrace(dns_lookup_grace), + mMaximumConnectTime(subsequent_connects), + mMaximumReplyDelay(reply_delay), + mLowSpeedTime(low_speed_time), + mLowSpeedLimit(low_speed_limit), + mMaximumCurlTransaction(curl_transaction), + mMaximumTotalDelay(total_delay) +{ + sanity_checks(); +} + +struct PolicyOp { + PolicyOp* mNext; + PolicyOp(void) : mNext(NULL) { } + PolicyOp(PolicyOp& op) : mNext(&op) { } + virtual void perform(AIHTTPTimeoutPolicy* policy) const { } + void nextOp(AIHTTPTimeoutPolicy* policy) const { if (mNext) mNext->perform(policy); } +}; + +class AIHTTPTimeoutPolicyBase : public AIHTTPTimeoutPolicy { + private: + std::vector mDerived; // Policies derived from this one. + + public: + AIHTTPTimeoutPolicyBase(U16 dns_lookup_grace, U16 subsequent_connects, U16 reply_delay, + U16 low_speed_time, U32 low_speed_limit, + U16 curl_transaction, U16 total_delay) : + AIHTTPTimeoutPolicy(NULL, dns_lookup_grace, subsequent_connects, reply_delay, low_speed_time, low_speed_limit, curl_transaction, total_delay) { } + + // Derive base from base. + AIHTTPTimeoutPolicyBase(AIHTTPTimeoutPolicyBase& rhs, PolicyOp const& op = PolicyOp()) : AIHTTPTimeoutPolicy(rhs) { op.perform(this); } + + // Called for every derived policy. + void derived(AIHTTPTimeoutPolicy* derived) { mDerived.push_back(derived); } + + // Provide public acces to sDebugSettingsCurlTimeout for this compilation unit. + static AIHTTPTimeoutPolicyBase& getDebugSettingsCurlTimeout(void) { return sDebugSettingsCurlTimeout; } + + protected: + friend void AIHTTPTimeoutPolicy::setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& timeout); + AIHTTPTimeoutPolicyBase& operator=(AIHTTPTimeoutPolicy const& rhs); +}; + +AIHTTPTimeoutPolicy::AIHTTPTimeoutPolicy(AIHTTPTimeoutPolicy& base) : + mName(NULL), + mBase(static_cast(&base)), + mDNSLookupGrace(base.mDNSLookupGrace), + mMaximumConnectTime(base.mMaximumConnectTime), + mMaximumReplyDelay(base.mMaximumReplyDelay), + mLowSpeedTime(base.mLowSpeedTime), + mLowSpeedLimit(base.mLowSpeedLimit), + mMaximumCurlTransaction(base.mMaximumCurlTransaction), + mMaximumTotalDelay(base.mMaximumTotalDelay) +{ +} + +AIHTTPTimeoutPolicyBase& AIHTTPTimeoutPolicyBase::operator=(AIHTTPTimeoutPolicy const& rhs) +{ + AIHTTPTimeoutPolicy::operator=(rhs); + return *this; +} + +AIHTTPTimeoutPolicy::AIHTTPTimeoutPolicy(char const* name, AIHTTPTimeoutPolicyBase& base) : + mName(name), + mBase(&base), + mDNSLookupGrace(mBase->mDNSLookupGrace), + mMaximumConnectTime(mBase->mMaximumConnectTime), + mMaximumReplyDelay(mBase->mMaximumReplyDelay), + mLowSpeedTime(mBase->mLowSpeedTime), + mLowSpeedLimit(mBase->mLowSpeedLimit), + mMaximumCurlTransaction(mBase->mMaximumCurlTransaction), + mMaximumTotalDelay(mBase->mMaximumTotalDelay) +{ + // Register for changes to the base policy. + mBase->derived(this); +} + +//static +void AIHTTPTimeoutPolicy::setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& timeout) +{ + sDebugSettingsCurlTimeout = timeout; + if (sDebugSettingsCurlTimeout.mDNSLookupGrace < AITP_default_DNS_lookup_grace) + { + llwarns << "CurlTimeoutDNSLookup (" << sDebugSettingsCurlTimeout.mDNSLookupGrace << ") is lower than the built-in default value (" << AITP_default_DNS_lookup_grace << ")." << llendl; + } + if (sDebugSettingsCurlTimeout.mMaximumConnectTime < AITP_default_maximum_connect_time) + { + llwarns << "CurlTimeoutConnect (" << sDebugSettingsCurlTimeout.mMaximumConnectTime << ") is lower than the built-in default value (" << AITP_default_maximum_connect_time << ")." << llendl; + } + if (sDebugSettingsCurlTimeout.mMaximumReplyDelay < AITP_default_maximum_reply_delay) + { + llwarns << "CurlTimeoutReplyDelay (" << sDebugSettingsCurlTimeout.mMaximumReplyDelay << ") is lower than the built-in default value (" << AITP_default_maximum_reply_delay << ")." << llendl; + } + if (sDebugSettingsCurlTimeout.mLowSpeedTime < AITP_default_low_speed_time) + { + llwarns << "CurlTimeoutLowSpeedTime (" << sDebugSettingsCurlTimeout.mLowSpeedTime << ") is lower than the built-in default value (" << AITP_default_low_speed_time << ")." << llendl; + } + if (sDebugSettingsCurlTimeout.mLowSpeedLimit > AITP_default_low_speed_limit) + { + llwarns << "CurlTimeoutLowSpeedLimit (" << sDebugSettingsCurlTimeout.mLowSpeedLimit << ") is higher than the built-in default value (" << AITP_default_low_speed_limit << ")." << llendl; + } + if (sDebugSettingsCurlTimeout.mMaximumCurlTransaction < AITP_default_maximum_curl_transaction) + { + llwarns << "CurlTimeoutMaxTransaction (" << sDebugSettingsCurlTimeout.mMaximumCurlTransaction << ") is lower than the built-in default value (" << AITP_default_maximum_curl_transaction<< ")." << llendl; + } + if (sDebugSettingsCurlTimeout.mMaximumTotalDelay < AITP_default_maximum_total_delay) + { + llwarns << "CurlTimeoutMaxTotalDelay (" << sDebugSettingsCurlTimeout.mMaximumTotalDelay << ") is lower than the built-in default value (" << AITP_default_maximum_total_delay << ")." << llendl; + } +} + +//static +AIHTTPTimeoutPolicy const& AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(void) +{ + return sDebugSettingsCurlTimeout; +} + +#ifdef SHOW_ASSERT +#include "aithreadid.h" +static AIThreadID curlthread(AIThreadID::none); // Initialized by getConnectTimeout. +#endif + +static std::set gSeenHostnames; + +U16 AIHTTPTimeoutPolicy::getConnectTimeout(std::string const& hostname) const +{ +#ifdef SHOW_ASSERT + // Only the CURL-THREAD may access gSeenHostnames. + if (curlthread.is_no_thread()) + curlthread.reset(); + llassert(curlthread.equals_current_thread()); +#endif + + U16 connect_timeout = mMaximumConnectTime; + // Add the hostname to the list of seen hostnames, if not already there. + if (gSeenHostnames.insert(hostname).second) + connect_timeout += mDNSLookupGrace; // If the host is not in the list, increase the connect timeout with mDNSLookupGrace. + return connect_timeout; +} + +//static +bool AIHTTPTimeoutPolicy::connect_timed_out(std::string const& hostname) +{ + llassert(curlthread.equals_current_thread()); + + // This is called when a connect to hostname timed out on connect. + // If the hostname is currently in the list, remove it and return true + // so that subsequent connects will get more time to connect. + // Otherwise return false. + return gSeenHostnames.erase(hostname) > 0; +} + +//======================================================================================================= +// Start of policy operation definitions. + +namespace AIHTTPTimeoutPolicyOperators { + +// Note: Policies are applied in the order First(x, Second(y, Third(z))) etc, +// where the last (Third) has the highest priority. +// For example: Transaction(5, Connect(40)) would first enforce a transaction time of 5 seconds, +// and then a connect time of 40 seconds, even if that would mean increasing the transaction +// time again. + +struct DNS : PolicyOp { + int mSeconds; + DNS(int seconds) : mSeconds(seconds) { } + DNS(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } + static void fix(AIHTTPTimeoutPolicy* policy); + static int min(void) { return ABS_min_DNS_lookup; } + static int max(void) { return ABS_max_DNS_lookup; } + virtual void perform(AIHTTPTimeoutPolicy* policy) const; +}; + +struct Connect : PolicyOp { + int mSeconds; + Connect(int seconds) : mSeconds(seconds) { } + Connect(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } + static void fix(AIHTTPTimeoutPolicy* policy); + static int min(void) { return ABS_min_connect_time; } + static int max(void) { return ABS_max_connect_time; } + virtual void perform(AIHTTPTimeoutPolicy* policy) const; +}; + +struct Reply : PolicyOp { + int mSeconds; + Reply(int seconds) : mSeconds(seconds) { } + Reply(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } + static void fix(AIHTTPTimeoutPolicy* policy); + static int min(void) { return ABS_min_reply_delay; } + static int max(void) { return ABS_max_reply_delay; } + virtual void perform(AIHTTPTimeoutPolicy* policy) const; +}; + +struct Speed : PolicyOp { + int mSeconds; + int mRate; + Speed(int seconds, int rate) : mSeconds(seconds), mRate(rate) { } + Speed(int seconds, int rate, PolicyOp& op) : PolicyOp(op), mSeconds(seconds), mRate(rate) { } + static void fix(AIHTTPTimeoutPolicy* policy); + static int min(void) { return ABS_min_low_speed_time; } + static int max(AIHTTPTimeoutPolicy const* policy) { return llmin(ABS_max_low_speed_time, (U16)(policy->mMaximumCurlTransaction / 2)); } + static int lmin(void) { return ABS_min_low_speed_limit; } + static int lmax(void) { return ABS_max_low_speed_limit; } + virtual void perform(AIHTTPTimeoutPolicy* policy) const; +}; + +struct Transaction : PolicyOp { + int mSeconds; + Transaction(int seconds) : mSeconds(seconds) { } + Transaction(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } + static void fix(AIHTTPTimeoutPolicy* policy); + static int min(AIHTTPTimeoutPolicy const* policy) { return llmax((int)ABS_min_transaction, policy->mMaximumConnectTime + policy->mMaximumReplyDelay + 4 * policy->mLowSpeedTime); } + static int max(void) { return ABS_max_transaction; } + virtual void perform(AIHTTPTimeoutPolicy* policy) const; +}; + +struct Total : PolicyOp { + int mSeconds; + Total(int seconds) : mSeconds(seconds) { } + Total(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } + static void fix(AIHTTPTimeoutPolicy* policy); + static int min(AIHTTPTimeoutPolicy const* policy) { return llmax((int)ABS_min_total_delay, policy->mMaximumCurlTransaction + 1); } + static int max(void) { return ABS_max_total_delay; } + virtual void perform(AIHTTPTimeoutPolicy* policy) const; +}; + +void DNS::perform(AIHTTPTimeoutPolicy* policy) const +{ + policy->mDNSLookupGrace = mSeconds; + fix(policy); + nextOp(policy); +} + +void Connect::perform(AIHTTPTimeoutPolicy* policy) const +{ + policy->mMaximumConnectTime = mSeconds; + fix(policy); + nextOp(policy); +} + +void Reply::perform(AIHTTPTimeoutPolicy* policy) const +{ + policy->mMaximumReplyDelay = mSeconds; + fix(policy); + nextOp(policy); +} + +void Speed::perform(AIHTTPTimeoutPolicy* policy) const +{ + policy->mLowSpeedTime = mSeconds; + policy->mLowSpeedLimit = mRate; + fix(policy); + nextOp(policy); +} + +void Transaction::perform(AIHTTPTimeoutPolicy* policy) const +{ + policy->mMaximumCurlTransaction = mSeconds; + fix(policy); + nextOp(policy); +} + +void Total::perform(AIHTTPTimeoutPolicy* policy) const +{ + policy->mMaximumTotalDelay = mSeconds; + fix(policy); + nextOp(policy); +} + +void DNS::fix(AIHTTPTimeoutPolicy* policy) +{ + if (policy->mDNSLookupGrace > max()) + { + policy->mDNSLookupGrace = max(); + } + else if (policy->mDNSLookupGrace < min()) + { + policy->mDNSLookupGrace = min(); + } +} + +void Connect::fix(AIHTTPTimeoutPolicy* policy) +{ + bool changed = false; + if (policy->mMaximumConnectTime > max()) + { + policy->mMaximumConnectTime = max(); + changed = true; + } + else if (policy->mMaximumConnectTime < min()) + { + policy->mMaximumConnectTime = min(); + changed = true; + } + if (changed) + { + // Transaction limits depend on Connect. + Transaction::fix(policy); + } +} + +void Reply::fix(AIHTTPTimeoutPolicy* policy) +{ + bool changed = false; + if (policy->mMaximumReplyDelay > max()) + { + policy->mMaximumReplyDelay = max(); + changed = true; + } + else if (policy->mMaximumReplyDelay < min()) + { + policy->mMaximumReplyDelay = min(); + changed = true; + } + if (changed) + { + // Transaction limits depend on Reply. + Transaction::fix(policy); + } +} + +void Speed::fix(AIHTTPTimeoutPolicy* policy) +{ + bool changed = false; + if (policy->mLowSpeedTime > ABS_max_low_speed_time) + { + policy->mLowSpeedTime = ABS_max_low_speed_time; + changed = true; + } + else if (policy->mLowSpeedTime != 0 && policy->mLowSpeedTime < min()) + { + policy->mLowSpeedTime = min(); + changed = true; + } + if (changed) + { + // Transaction limits depend on Speed time. + Transaction::fix(policy); + } + if (policy->mLowSpeedTime > max(policy)) + { + policy->mLowSpeedTime = max(policy); + } + if (policy->mLowSpeedLimit > lmax()) + { + policy->mLowSpeedLimit = lmax(); + } + else if (policy->mLowSpeedLimit != 0 && policy->mLowSpeedLimit < lmin()) + { + policy->mLowSpeedLimit = lmin(); + } +} + +void Transaction::fix(AIHTTPTimeoutPolicy* policy) +{ + bool changed = false; + if (policy->mMaximumCurlTransaction > max()) + { + policy->mMaximumCurlTransaction = max(); + changed = true; + } + else if (policy->mMaximumCurlTransaction < ABS_min_transaction) + { + policy->mMaximumCurlTransaction = ABS_min_transaction; + changed = true; + } + if (changed) + { + // Totals minimum limit depends on Transaction. + Total::fix(policy); + // Transaction limits depend on Connect, Reply and Speed time. + if (policy->mMaximumCurlTransaction < min(policy)) + { + // We need to achieve the following (from Transaction::min()): + // policy->mMaximumCurlTransaction >= policy->mMaximumConnectTime + policy->mMaximumReplyDelay + 4 * policy->mLowSpeedTime + + // There isn't a single way to fix this, so we just do something randomly intuitive. + // We consider the vector space ; + // In other words, we need to compare with the dot product of <1, 1, 4>. + LLVector3 const ref(1, 1, 4); + + // The shortest allowed vector is: + LLVector3 const vec_min(ABS_min_connect_time, ABS_min_reply_delay, ABS_min_low_speed_time); + + // Initialize the result vector to (0, 0, 0) (in the vector space with shifted origin). + LLVector3 vec_res; + + // Check if there is a solution at all: + if (policy->mMaximumCurlTransaction > ref * vec_min) // Is vec_min small enough? + { + // The current point is: + LLVector3 vec_cur(policy->mMaximumConnectTime, policy->mMaximumReplyDelay, policy->mLowSpeedTime); + + // The default point is: + LLVector3 vec_def(AITP_default_maximum_connect_time, AITP_default_maximum_reply_delay, AITP_default_low_speed_time); + + // Move the origin. + vec_cur -= vec_min; + vec_def -= vec_min; + + // Normalize the default vector (we only need it's direction). + vec_def.normalize(); + + // Project the current vector onto the default vector (dp = default projection): + LLVector3 vec_dp = vec_def * (vec_cur * vec_def); + + // Check if the projection is a solution and choose the vectors between which the result lays. + LLVector3 a; // vec_min is too small (a = (0, 0, 0) which corresponds to vec_min). + LLVector3 b = vec_cur; // vec_cur is too large. + if (policy->mMaximumCurlTransaction > ref * (vec_dp + vec_min)) // Is vec_dp small enough too? + { + a = vec_dp; // New lower bound. + } + else + { + b = vec_dp; // New upper bound. + } + // Find vec_res = a + lambda * (b - a), where 0 <= lambda <= 1, such that + // policy->mMaximumCurlTransaction == ref * (vec_res + vec_min). + // + // Note that ref * (b - a) must be non-zero because if it wasn't then changing lambda wouldn't have + // any effect on right-hand side of the equation (ref * (vec_res + vec_min)) which in contradiction + // with the fact that a is a solution and b is not. + F32 lambda = (policy->mMaximumCurlTransaction - ref * (a + vec_min)) / (ref * (b - a)); + vec_res = a + lambda * (b - a); + } + + // Shift origin back and fill in the result. + vec_res += vec_min; + policy->mMaximumConnectTime = vec_res[VX]; + policy->mMaximumReplyDelay = vec_res[VY]; + policy->mLowSpeedTime = vec_res[VZ]; + } + } + if (policy->mMaximumCurlTransaction < min(policy)) + { + policy->mMaximumCurlTransaction = min(policy); + } +} + +void Total::fix(AIHTTPTimeoutPolicy* policy) +{ + bool changed = false; + if (policy->mMaximumTotalDelay > max()) + { + policy->mMaximumTotalDelay = max(); + changed = true; + } + else if (policy->mMaximumTotalDelay < ABS_min_total_delay) + { + policy->mMaximumTotalDelay = ABS_min_total_delay; + changed = true; + } + if (changed) + { + // Totals minimum limit depends on Transaction. + // We have to correct mMaximumCurlTransaction such that (from Total::min) + // mMaximumTotalDelay >= llmax((int)ABS_min_total_delay, policy->mMaximumCurlTransaction + 1) + if (policy->mMaximumTotalDelay < policy->mMaximumCurlTransaction + 1) + { + policy->mMaximumCurlTransaction = policy->mMaximumTotalDelay - 1; + } + } + if (policy->mMaximumTotalDelay < min(policy)) + { + policy->mMaximumTotalDelay = min(policy); + } +} + +} // namespace AIHTTPTimeoutPolicyOperators + +void AIHTTPTimeoutPolicy::sanity_checks(void) const +{ + // Sanity checks. + llassert( DNS::min() <= mDNSLookupGrace && mDNSLookupGrace <= DNS::max()); + llassert( Connect::min() <= mMaximumConnectTime && mMaximumConnectTime <= Connect::max()); + llassert( Reply::min() <= mMaximumReplyDelay && mMaximumReplyDelay <= Reply::max()); + llassert(mLowSpeedTime == 0 || + (Speed::min() <= mLowSpeedTime && mLowSpeedTime <= Speed::max(this))); + llassert(mLowSpeedLimit == 0 || + (Speed::lmin() <= mLowSpeedLimit && mLowSpeedLimit <= Speed::lmax())); + llassert(Transaction::min(this) <= mMaximumCurlTransaction && mMaximumCurlTransaction <= Transaction::max()); + llassert( Total::min(this) <= mMaximumTotalDelay && mMaximumTotalDelay <= Total::max()); +} + +//======================================================================================================= +// Start of policy definitions. + +// AIFIXME: update all policies whenever a CurlTimeout* settings is changed. + +// Policy with hardcoded default values. +AIHTTPTimeoutPolicyBase HTTPTimeoutPolicy_default( + AITP_default_DNS_lookup_grace, + AITP_default_maximum_connect_time, + AITP_default_maximum_reply_delay, + AITP_default_low_speed_time, + AITP_default_low_speed_limit, + AITP_default_maximum_curl_transaction, + AITP_default_maximum_total_delay); + +//static. Initialized here, but shortly overwritten by Debug Settings. +AIHTTPTimeoutPolicyBase AIHTTPTimeoutPolicy::sDebugSettingsCurlTimeout( + AITP_default_DNS_lookup_grace, + AITP_default_maximum_connect_time, + AITP_default_maximum_reply_delay, + AITP_default_low_speed_time, + AITP_default_low_speed_limit, + AITP_default_maximum_curl_transaction, + AITP_default_maximum_total_delay); + +// This used to be '5 seconds'. +AIHTTPTimeoutPolicyBase transfer_5s(AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(), + Transaction(5) + ); + +// This used to be '18 seconds'. +AIHTTPTimeoutPolicyBase transfer_18s(AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(), + Transaction(18) + ); + +// This used to be '300 seconds'. We derive this from the hardcoded result so users can't mess with it. +AIHTTPTimeoutPolicyBase transfer_300s(HTTPTimeoutPolicy_default, + Transaction(300) + ); + +// This used to be a call to setopt(CURLOPT_CONNECTTIMEOUT, 40L) with the remark 'Be a little impatient about establishing connections.' +AIHTTPTimeoutPolicyBase connect_40s(AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(), + Connect(40)); + +// End of policy definitions. +//======================================================================================================= + +//======================================================================================================= +// Start of Responder timeout policy list. + +// Note: to find the actual responder class back, search for the name listed here but with upper case first character. +// For example, if the actual responder class is LLAccountingCostResponder then the name used here is accountingCostResponder. + +#undef P +#define P(n) AIHTTPTimeoutPolicy n##_timeout(#n) +#define P2(n, b) AIHTTPTimeoutPolicy n##_timeout(#n, b) + +// Policy name Policy +P(accountingCostResponder); +P(agentStateResponder); +P(assetUploadResponder); +P(asyncConsoleResponder); +P(avatarNameResponder); +P2(baseCapabilitiesComplete, transfer_18s); +P(blockingGet); +P(blockingPost); +P(charactersResponder); +P(classifiedStatsResponder); +P(consoleResponder); +P2(crashLoggerResponder, transfer_5s); +P(createInventoryCategoryResponder); +P(emeraldDicDownloader); +P(environmentApplyResponder); +P(environmentRequestResponder); +P(estateChangeInfoResponder); +P(eventPollResponder); +P(eventResponder); +P(fetchInventoryResponder); +P(floaterRegionDebugConsole); +P(fnPtrResponder); +P2(groupProposalBallotResponder, transfer_300s); +P(homeLocationResponder); +P(HTTPGetResponder); +P(iamHereLogin); +P(iamHere); +P(iamHereVoice); +P2(inventoryModelFetchDescendentsResponder, transfer_300s); +P(inventoryModelFetchItemResponder); +P(lcl_responder); +P(mapLayerResponder); +P(mediaTypeResponder); +P(meshDecompositionResponder); +P(meshHeaderResponder); +P(meshLODResponder); +P(meshPhysicsShapeResponder); +P(meshSkinInfoResponder); +P(mimeDiscoveryResponder); +P(moderationModeResponder); +P(muteTextResponder); +P(muteVoiceResponder); +P(navMeshRebakeResponder); +P(navMeshResponder); +P(navMeshStatusResponder); +P(newAgentInventoryVariablePriceResponder); +P(objectCostResponder); +P(objectLinksetsResponder); +P(physicsFlagsResponder); +P(placeAvatarTeleportResponder); +P(productInfoRequestResponder); +P(regionResponder); +P(remoteParcelRequestResponder); +P(responderIgnore); +P(sessionInviteResponder); +P(setDisplayNameResponder); +P2(simulatorFeaturesReceived, transfer_18s); +P(startConferenceChatResponder); +P2(startGroupVoteResponder, transfer_300s); +P(terrainLinksetsResponder); +P(translationReceiver); +P(uploadModelPremissionsResponder); +P(userReportResponder); +P(verifiedDestinationResponder); +P(viewerChatterBoxInvitationAcceptResponder); +P(viewerMediaOpenIDResponder); +P(viewerMediaWebProfileResponder); +P(viewerStatsResponder); +P(viewerVoiceAccountProvisionResponder); +P(voiceCallCapResponder); +P(voiceClientCapResponder); +P(wholeModelFeeResponder); +P(wholeModelUploadResponder); +P2(XMLRPCTransaction, connect_40s); + diff --git a/indra/llmessage/aihttptimeoutpolicy.h b/indra/llmessage/aihttptimeoutpolicy.h new file mode 100644 index 000000000..bb11b033a --- /dev/null +++ b/indra/llmessage/aihttptimeoutpolicy.h @@ -0,0 +1,114 @@ +/** + * @file aihttptimeoutpolicy.h + * @brief Store the policy on timing out a HTTP curl transaction. + * + * Copyright (c) 2012, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 24/09/2012 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIHTTPTIMEOUTPOLICY_H +#define AIHTTPTIMEOUTPOLICY_H + +#include "stdtypes.h" +#include + +class AIHTTPTimeoutPolicyBase; + +namespace AIHTTPTimeoutPolicyOperators { + +struct DNS; +struct Connect; +struct Reply; +struct Speed; +struct Transaction; +struct Total; + +} // namespace AIHTTPTimeoutPolicyOperators + +class AIHTTPTimeoutPolicy { + protected: + char const* const mName; // The name of this policy, for debugging purposes. + AIHTTPTimeoutPolicyBase* const mBase; // Policy this policy was based on. + static AIHTTPTimeoutPolicyBase sDebugSettingsCurlTimeout; // CurlTimeout* debug settings. + + private: + U16 mDNSLookupGrace; // Extra connect timeout the first time we connect to a host (this is to allow for DNS lookups). + U16 mMaximumConnectTime; // Connect timeouts any subsequent connects to the same host, assuming the DNS will be cached now. + U16 mMaximumReplyDelay; // Timeout for the period between sending data to the server and the HTTP header of the reply. + U16 mLowSpeedTime; // The time in seconds that a transfer should be below mLowSpeedLimit before to consider it too slow and abort. + U32 mLowSpeedLimit; // Transfer speed in bytes per second that a transfer should be below during mLowSpeedTime seconds to consider it too slow and abort. + U16 mMaximumCurlTransaction; // Timeout for the whole curl transaction (including connect and DNS lookup). + U16 mMaximumTotalDelay; // Timeout from moment of request (including the time a request is/was queued). + + friend struct AIHTTPTimeoutPolicyOperators::DNS; + friend struct AIHTTPTimeoutPolicyOperators::Connect; + friend struct AIHTTPTimeoutPolicyOperators::Reply; + friend struct AIHTTPTimeoutPolicyOperators::Speed; + friend struct AIHTTPTimeoutPolicyOperators::Transaction; + friend struct AIHTTPTimeoutPolicyOperators::Total; + + public: + // Construct a HTTP timeout policy object that mimics base, or Debug Settings if none given. + AIHTTPTimeoutPolicy( + char const* name, + AIHTTPTimeoutPolicyBase& base = sDebugSettingsCurlTimeout); + + // Construct a HTTP timeout policy with exact specifications. + AIHTTPTimeoutPolicy( + char const* name, + U16 dns_lookup_grace, + U16 subsequent_connects, + U16 reply_delay, + U16 low_speed_time, + U32 low_speed_limit, + U16 curl_transaction, + U16 total_delay); + + void sanity_checks(void) const; + + // Accessors. + char const* name(void) const { return mName; } + U16 getConnectTimeout(std::string const& hostname) const; + U16 getReplyDelay(void) const { return mMaximumReplyDelay; } + U16 getLowSpeedTime(void) const { return mLowSpeedTime; } + U32 getLowSpeedLimit(void) const { return mLowSpeedLimit; } + U16 getCurlTransaction(void) const { return mMaximumCurlTransaction; } + U16 getTotalDelay(void) const { return mMaximumTotalDelay; } + static AIHTTPTimeoutPolicy const& getDebugSettingsCurlTimeout(void); + + // Called once at start up of viewer to set a different default timeout policy than HTTPTimeoutPolicy_default. + static void setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& defaultCurlTimeout); + + // Called when a connect to a hostname timed out. + static bool connect_timed_out(std::string const& hostname); + + protected: + // Used by AIHTTPTimeoutPolicyBase::AIHTTPTimeoutPolicyBase(AIHTTPTimeoutPolicyBase&). + AIHTTPTimeoutPolicy(AIHTTPTimeoutPolicy&); + // Abused assigned operator (called by AIHTTPTimeoutPolicyBase::operator=). + AIHTTPTimeoutPolicy& operator=(AIHTTPTimeoutPolicy const&); +}; + +#endif // AIHTTPTIMEOUTPOLICY_H diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 852b192ea..fb4eed79a 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -171,6 +171,9 @@ namespace LLAvatarNameCache */ +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy avatarNameResponder_timeout; + class LLAvatarNameResponder : public LLHTTPClient::Responder { private: @@ -182,6 +185,8 @@ private: AIHTTPHeaders mHeaders; public: + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return avatarNameResponder_timeout; } + LLAvatarNameResponder(const std::vector& agent_ids) : mAgentIDs(agent_ids) { } diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 585e4644b..9db6170c9 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -46,7 +46,6 @@ static const U32 EASY_HANDLE_POOL_SIZE = 5; static const S32 MULTI_PERFORM_CALL_REPEAT = 5; -static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds per operation static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; //static diff --git a/indra/llmessage/llcurlrequest.cpp b/indra/llmessage/llcurlrequest.cpp index 9911335ee..72de85774 100644 --- a/indra/llmessage/llcurlrequest.cpp +++ b/indra/llmessage/llcurlrequest.cpp @@ -76,7 +76,7 @@ bool Request::getByteRange2(std::string const& url, AIHTTPHeaders const& headers buffered_easy_request_w->addHeader(range.c_str()); } - buffered_easy_request_w->finalizeRequest(url); + buffered_easy_request_w->finalizeRequest(url, responder->getHTTPTimeoutPolicy(), buffered_easy_request); } buffered_easy_request->run(); @@ -84,7 +84,7 @@ bool Request::getByteRange2(std::string const& url, AIHTTPHeaders const& headers return true; // We throw in case of problems. } -bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder, S32 time_out) +bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder) { DoutEntering(dc::curl, "Request::post(" << url << ", ...)"); @@ -95,7 +95,7 @@ bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::s AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, headers, responder, time_out); + buffer_w->prepRequest(buffered_easy_request_w, headers, responder); U32 bytes = data.size(); bool success = buffer_w->getInput()->append(buffer_w->sChannels.out(), (U8 const*)data.data(), bytes); @@ -106,7 +106,7 @@ bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::s } buffered_easy_request_w->setPost(bytes); buffered_easy_request_w->addHeader("Content-Type: application/octet-stream"); - buffered_easy_request_w->finalizeRequest(url); + buffered_easy_request_w->finalizeRequest(url, responder->getHTTPTimeoutPolicy(), buffered_easy_request); } buffered_easy_request->run(); @@ -114,7 +114,7 @@ bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::s return true; // We throw in case of problems. } -bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder, S32 time_out) +bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder) { DoutEntering(dc::curl, "Request::post(" << url << ", ...)"); @@ -125,7 +125,7 @@ bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD c AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, headers, responder, time_out); + buffer_w->prepRequest(buffered_easy_request_w, headers, responder); LLBufferStream buffer_stream(buffer_w->sChannels, buffer_w->getInput().get()); LLSDSerialize::toXML(data, buffer_stream); @@ -134,7 +134,7 @@ bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD c S32 bytes = buffer_w->getInput()->countAfter(buffer_w->sChannels.out(), NULL); buffered_easy_request_w->setPost(bytes); buffered_easy_request_w->addHeader("Content-Type: application/llsd+xml"); - buffered_easy_request_w->finalizeRequest(url); + buffered_easy_request_w->finalizeRequest(url, responder->getHTTPTimeoutPolicy(), buffered_easy_request); lldebugs << "POSTING: " << bytes << " bytes." << llendl; } diff --git a/indra/llmessage/llcurlrequest.h b/indra/llmessage/llcurlrequest.h index 54bdb35ed..d30418abd 100644 --- a/indra/llmessage/llcurlrequest.h +++ b/indra/llmessage/llcurlrequest.h @@ -48,8 +48,8 @@ class Request { public: bool get2(std::string const& url, ResponderPtr responder); bool getByteRange2(std::string const& url, AIHTTPHeaders const& headers, S32 offset, S32 length, ResponderPtr responder); - bool post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder, S32 time_out = 0); - bool post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder, S32 time_out = 0); + bool post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder); + bool post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder); }; } // namespace AICurlInterface diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 077d3302d..5ec98b5e3 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -34,7 +34,10 @@ #include "llvfile.h" #include "llurlrequest.h" -F32 const HTTP_REQUEST_EXPIRY_SECS = 60.0f; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy blockingGet_timeout; +extern AIHTTPTimeoutPolicy blockingPost_timeout; + //////////////////////////////////////////////////////////////////////////// class LLSDInjector : public Injector @@ -146,8 +149,7 @@ static void request( LLURLRequest::ERequestAction method, Injector* body_injector, LLCurl::ResponderPtr responder, - AIHTTPHeaders& headers, - F32 timeout = HTTP_REQUEST_EXPIRY_SECS) + AIHTTPHeaders& headers) { if (responder) { @@ -167,40 +169,39 @@ static void request( return ; } - req->setRequestTimeOut(timeout); req->run(); } -void LLHTTPClient::getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers) { if(offset > 0 || bytes > 0) { headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1)); } - request(url, LLURLRequest::HTTP_GET, NULL, responder, headers, timeout); + request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); } -void LLHTTPClient::head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers, timeout); + request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); } -void LLHTTPClient::get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_GET, NULL, responder, headers, timeout); + request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); } -void LLHTTPClient::getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers, timeout); + request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); } -void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers) { LLURI uri; uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query); - get4(uri.asString(), responder, headers, timeout); + get4(uri.asString(), responder, headers); } // A simple class for managing data returned from a curl http request. @@ -261,7 +262,7 @@ static LLSD blocking_request( LLURLRequest::ERequestAction method, LLSD const& body, AIHTTPHeaders& headers, - F32 timeout = 5) + AIHTTPTimeoutPolicy const& timeout) { lldebugs << "blockingRequest of " << url << llendl; @@ -347,49 +348,49 @@ static LLSD blocking_request( LLSD LLHTTPClient::blockingGet(const std::string& url) { AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers); + return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers, blockingGet_timeout); } LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers); + return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers, blockingPost_timeout); } -void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers, timeout); + request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers); } -void LLHTTPClient::post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers, timeout); + request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers); } -void LLHTTPClient::postRaw4(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::postRaw4(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers, timeout); + request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers); } -void LLHTTPClient::postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers, timeout); + request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers); } -void LLHTTPClient::postFile4(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::postFile4(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers, timeout); + request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers); } // static -void LLHTTPClient::del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { - request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers, timeout); + request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers); } // static -void LLHTTPClient::move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout) +void LLHTTPClient::move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers) { headers.addHeader("Destination", destination); - request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers, timeout); + request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers); } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 0f8cca0be..0dcd0767f 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -37,11 +37,12 @@ #include "llcurl.h" #include "aihttpheaders.h" -extern F32 const HTTP_REQUEST_EXPIRY_SECS; - class LLUUID; class LLPumpIO; class LLSD; +class AIHTTPTimeoutPolicy; + +extern AIHTTPTimeoutPolicy responderIgnore_timeout; class LLHTTPClient { @@ -51,54 +52,54 @@ public: typedef LLCurl::ResponderPtr ResponderPtr; // The default actually already ignores responses. - class ResponderIgnore : public Responder { }; + class ResponderIgnore : public Responder { virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} }; /** @name non-blocking API */ //@{ - static void head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void head4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; head4(url, responder, headers, timeout); } + static void head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void head4(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; head4(url, responder, headers); } - static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; getByteRange4(url, offset, bytes, responder, headers, timeout); } + static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers); + static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder) + { AIHTTPHeaders headers; getByteRange4(url, offset, bytes, responder, headers); } - static void get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void get4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; get4(url, responder, headers, timeout); } + static void get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void get4(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; get4(url, responder, headers); } - static void get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void get4(std::string const& url, LLSD const& query, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; get4(url, query, responder, headers, timeout); } + static void get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers); + static void get4(std::string const& url, LLSD const& query, ResponderPtr responder) + { AIHTTPHeaders headers; get4(url, query, responder, headers); } - static void put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void put4(std::string const& url, LLSD const& body, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; put4(url, body, responder, headers, timeout); } + static void put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); + static void put4(std::string const& url, LLSD const& body, ResponderPtr responder) + { AIHTTPHeaders headers; put4(url, body, responder, headers); } - static void getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void getHeaderOnly4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; getHeaderOnly4(url, responder, headers, timeout); } + static void getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void getHeaderOnly4(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; getHeaderOnly4(url, responder, headers); } - static void post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void post4(std::string const& url, LLSD const& body, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; post4(url, body, responder, headers, timeout); } + static void post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); + static void post4(std::string const& url, LLSD const& body, ResponderPtr responder) + { AIHTTPHeaders headers; post4(url, body, responder, headers); } /** Takes ownership of data and deletes it when sent */ - static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; postRaw4(url, data, size, responder, headers, timeout); } + static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers); + static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder) + { AIHTTPHeaders headers; postRaw4(url, data, size, responder, headers); } - static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; postFile4(url, filename, responder, headers, timeout); } + static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers); + static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder) + { AIHTTPHeaders headers; postFile4(url, filename, responder, headers); } - static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; postFile4(url, uuid, asset_type, responder, headers, timeout); } + static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers); + static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder) + { AIHTTPHeaders headers; postFile4(url, uuid, asset_type, responder, headers); } - static void del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void del4(std::string const& url, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; del4(url, responder, headers, timeout); } + static void del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void del4(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; del4(url, responder, headers); } ///< sends a DELETE method, but we can't call it delete in c++ @@ -111,9 +112,9 @@ public: * @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 move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers, F32 timeout = HTTP_REQUEST_EXPIRY_SECS); - static void move4(std::string const& url, std::string const& destination, ResponderPtr responder, F32 timeout = HTTP_REQUEST_EXPIRY_SECS) - { AIHTTPHeaders headers; move4(url, destination, responder, headers, timeout); } + static void move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers); + static void move4(std::string const& url, std::string const& destination, ResponderPtr responder) + { AIHTTPHeaders headers; move4(url, destination, responder, headers); } //@} diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h index 9b45e78b5..20dccb14c 100644 --- a/indra/llmessage/llregionpresenceverifier.h +++ b/indra/llmessage/llregionpresenceverifier.h @@ -34,6 +34,9 @@ #include class LLHTTPClientInterface; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy regionResponder_timeout; +extern AIHTTPTimeoutPolicy verifiedDestinationResponder_timeout; class LLRegionPresenceVerifier { @@ -58,6 +61,8 @@ public: class RegionResponder : public LLHTTPClient::Responder { public: + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return regionResponder_timeout; } + RegionResponder(const std::string& uri, ResponsePtr data, S32 retry_count); virtual ~RegionResponder(); @@ -73,6 +78,8 @@ public: class VerifiedDestinationResponder : public LLHTTPClient::Responder { public: + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return verifiedDestinationResponder_timeout; } + VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content, S32 retry_count); virtual ~VerifiedDestinationResponder(); diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index a46c2835f..441355b3b 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -77,17 +77,18 @@ bool LLSDMessage::httpListener(const LLSD& request) out << "request event without 'url' key to '" << mEventPump.getName() << "'"; throw ArgError(out.str()); } +#if 0 // AIFIXME: ignore this for now // Establish default timeout. This test relies on LLSD::asReal() returning // exactly 0.0 for an undef value. if (! timeout) { timeout = HTTP_REQUEST_EXPIRY_SECS; } +#endif LLHTTPClient::post4(url, payload, new LLSDMessage::EventResponder(LLEventPumps::instance(), request, - url, "POST", reply, error), - (F32)timeout); + url, "POST", reply, error)); return false; } diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 0d34847ff..3d1ae814c 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -37,6 +37,8 @@ #include class LLSD; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy eventResponder_timeout; /** * Class managing the messaging API described in @@ -124,6 +126,8 @@ private: class EventResponder: public LLHTTPClient::Responder { public: + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventResponder_timeout; } + /** * LLHTTPClient::Responder that dispatches via named LLEventPump instances. * We bind LLEventPumps, even though it's an LLSingleton, for testability. diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index af22a1722..1ea9c02ad 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -293,14 +293,14 @@ LLIOPipe::EStatus LLURLRequest::handleError( LLIOPipe::EStatus status, LLPumpIO* pump) { - DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ")"); + DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ") [" << (void*)mCurlEasyRequest.get_ptr().get() << "]"); if (LL_LIKELY(!mDetail->mStateMachine->isBuffered())) // Currently always true. { // The last reference will be deleted when the pump that this chain belongs to // is removed from the running chains vector, upon returning from this function. // This keeps the CurlEasyRequest object alive until the curl thread cleanly removed it. - Dout(dc::curl, "Calling mDetail->mStateMachine->removeRequest()"); + Dout(dc::curl, "Calling mDetail->mStateMachine->removeRequest() [" << (void*)mCurlEasyRequest.get_ptr().get() << "]"); mDetail->mStateMachine->removeRequest(); } else if (!hasNotExpired()) @@ -546,7 +546,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) } if(rv) { - curlEasyRequest_w->finalizeRequest(mURL); + curlEasyRequest_w->finalizeRequest(mURL, mResponder->getHTTPTimeoutPolicy(), this); } } return rv; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 1fe40f6bc..d082c248c 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -83,6 +83,9 @@ #include "llmemtype.h" #include "llpacketring.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy fnPtrResponder_timeout; + // Constants //const char* MESSAGE_LOG_FILENAME = "message.log"; static const F32 CIRCUIT_DUMP_TIMEOUT = 30.f; @@ -133,6 +136,8 @@ namespace if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR); } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fnPtrResponder_timeout; } + private: void (*mCallback)(void **,S32); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7d9482424..2b7064536 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4227,16 +4227,82 @@ Value 256 - CurlRequestTimeOut + CurlTimeoutDNSLookup Comment - Max idle time of a curl request before killed (requires restart) + Extra time in seconds added to CurlTimeoutConnect for the initial connect to a host (requires restart) Persist 1 Type - F32 + U32 Value - 120.0 + 60 + + CurlTimeoutConnect + + Comment + Maximum time allowed until a connection is established (after adding the easy handle) until the server is considered unreachable and the connection is terminated (requires restart) + Persist + 1 + Type + U32 + Value + 10 + + CurlTimeoutReplyDelay + + Comment + Maximum time the viewer will wait between sending data to the server and receiving (a partial) reply (requires restart) + Persist + 1 + Type + U32 + Value + 60 + + CurlTimeoutLowSpeedLimit + + Comment + If a transfer speed drops below this value (in bytes/s) during CurlTimeoutLowSpeedTime seconds, the transfer is considered too slow and is terminated (requires restart) + Persist + 1 + Type + U32 + Value + 56000 + + CurlTimeoutLowSpeedTime + + Comment + If a transfer speed drops below CurlTimeoutLowSpeedLimit (in bytes/s) during this amount of seconds, the transfer is considered too slow and is terminated (requires restart) + Persist + 1 + Type + U32 + Value + 30 + + CurlTimeoutMaxTransaction + + Comment + Maximum total time of a curl transaction, from when the easy handle is added till the transaction has completed. This INCLUDES DNS lookups (CurlTimeoutConnect), connect time (CurlTimeoutConnect) and waiting for the first server reply (CurlTimeoutReply) as well as the actually time needed for data transfer (requires restart) + Persist + 1 + Type + U32 + Value + 300 + + CurlTimeoutMaxTotalDelay + + Comment + Maximum total time of a curl request, from when it is requested till the transaction has completed. This includes queuing due to connection throttling on top of the events covered by CurlTimeoutMaxTransaction (requires restart) + Persist + 1 + Type + U32 + Value + 600 Cursor3D diff --git a/indra/newview/floatervoicelicense.cpp b/indra/newview/floatervoicelicense.cpp index fd9a7a649..8badf0e30 100644 --- a/indra/newview/floatervoicelicense.cpp +++ b/indra/newview/floatervoicelicense.cpp @@ -52,6 +52,8 @@ #include "llvfile.h" #include "message.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy iamHereVoice_timeout; FloaterVoiceLicense::FloaterVoiceLicense(const LLSD& key) : LLModalDialog( std::string(" "), 100, 100 ), @@ -73,7 +75,6 @@ class LLIamHereVoice : public LLHTTPClient::Responder FloaterVoiceLicense* mParent; public: - static boost::intrusive_ptr< LLIamHereVoice > build( FloaterVoiceLicense* parent ) { return boost::intrusive_ptr< LLIamHereVoice >( new LLIamHereVoice( parent ) ); @@ -101,6 +102,8 @@ class LLIamHereVoice : public LLHTTPClient::Responder mParent->setSiteIsAlive( alive ); } }; + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereVoice_timeout; } }; // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index 73dd8d124..fac276e7a 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -19,7 +19,6 @@ #include "hipporestrequest.h" - // ******************************************************************** // Global Variables @@ -860,7 +859,6 @@ void HippoGridManager::loadFromFile() setCurrentGrid(last_grid); } - void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer) { llinfos << "Loading grid info from '" << url << "'." << llendl; diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp index e36c081d7..107310759 100644 --- a/indra/newview/hipporestrequest.cpp +++ b/indra/newview/hipporestrequest.cpp @@ -319,7 +319,7 @@ int HippoRestRequest::getBlocking(const std::string &url, std::string *result) llassert_always(curlp); curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts - curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 5); // seconds + curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 30); // seconds (including DNS lookups) curl_easy_setopt(curlp, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str()); curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, curlWrite); diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index cc3e49c39..7bcaaac49 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -49,6 +49,8 @@ #include "llbufferstream.h" class lggDicDownloadFloater; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy emeraldDicDownloader_timeout; class EmeraldDicDownloader : public LLHTTPClient::Responder { @@ -60,6 +62,7 @@ public: const std::string& reason, const LLChannelDescriptors& channels, const buffer_ptr_t& buffer); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return emeraldDicDownloader_timeout; } private: lggDicDownloadFloater* panel; std::string name; diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 4971cdb9e..d35a80f8b 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -30,6 +30,9 @@ #include "llcurl.h" #include "llhttpclient.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy accountingCostResponder_timeout; + //=============================================================================== LLAccountingCostManager::LLAccountingCostManager() { @@ -85,6 +88,8 @@ public: clearPendingRequests(); } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return accountingCostResponder_timeout; } + private: //List of posted objects LLSD mObjectIDs; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index c371ac072..99f900d3e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -119,6 +119,7 @@ #include "lldelayeduidelete.h" #include "llbuildnewviewsscheduler.h" #include "aicurleasyrequeststatemachine.h" +#include "aihttptimeoutpolicy.h" // // The files below handle dependencies from cleanup. #include "llcalc.h" @@ -642,7 +643,18 @@ bool LLAppViewer::init() mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); AIStateMachine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime")); - AICurlEasyRequestStateMachine::setDefaultRequestTimeOut(gSavedSettings.getF32("CurlRequestTimeOut")); + + AIHTTPTimeoutPolicy::setDefaultCurlTimeout( + AIHTTPTimeoutPolicy( + "CurlTimeout* Debug Settings", + gSavedSettings.getU32("CurlTimeoutDNSLookup"), + gSavedSettings.getU32("CurlTimeoutConnect"), + gSavedSettings.getU32("CurlTimeoutReplyDelay"), + gSavedSettings.getU32("CurlTimeoutLowSpeedTime"), + gSavedSettings.getU32("CurlTimeoutLowSpeedLimit"), + gSavedSettings.getU32("CurlTimeoutMaxTransaction"), + gSavedSettings.getU32("CurlTimeoutMaxTotalDelay") + )); initThreads(); LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 47f8eba37..c50557354 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -192,8 +192,7 @@ void on_new_single_inventory_upload_complete( LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type) -: LLHTTPClient::Responder(), - mPostData(post_data), +: mPostData(post_data), mVFileID(vfile_id), mAssetType(asset_type) { @@ -210,8 +209,7 @@ LLAssetUploadResponder::LLAssetUploadResponder( const LLSD &post_data, const std::string& file_name, LLAssetType::EType asset_type) -: LLHTTPClient::Responder(), - mPostData(post_data), +: mPostData(post_data), mFileName(file_name), mAssetType(asset_type) { diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 0236b08b5..6de99808d 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -36,6 +36,10 @@ #include "llhttpclient.h" #include "llinventory.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy assetUploadResponder_timeout; +extern AIHTTPTimeoutPolicy newAgentInventoryVariablePriceResponder_timeout; + void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, LLInventoryType::EType inventory_type, const std::string inventory_type_string, @@ -59,6 +63,7 @@ public: ~LLAssetUploadResponder(); virtual void error(U32 statusNum, const std::string& reason); virtual void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return assetUploadResponder_timeout; } virtual void uploadUpload(const LLSD& content); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); @@ -110,6 +115,7 @@ public: const std::string& reason, const LLSD& content); void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return newAgentInventoryVariablePriceResponder_timeout; } virtual void onApplicationLevelError( const LLSD& error); diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp index 9ff6d9f8f..75934c156 100644 --- a/indra/newview/llcapabilitylistener.cpp +++ b/indra/newview/llcapabilitylistener.cpp @@ -95,12 +95,14 @@ bool LLCapabilityListener::capListener(const LLSD& request) << LL_ENDL; return false; // in case fatal-error function isn't } +#if 0 // AIFIXME: ignore this for now // Establish default timeout. This test relies on LLSD::asReal() returning // exactly 0.0 for an undef value. if (! timeout) { timeout = HTTP_REQUEST_EXPIRY_SECS; } +#endif // Look up the url for the requested capability name. std::string url = mProvider.getCapability(cap); if (! url.empty()) @@ -110,8 +112,7 @@ bool LLCapabilityListener::capListener(const LLSD& request) new LLSDMessage::EventResponder(LLEventPumps::instance(), request, mProvider.getDescription(), - cap, reply, error), - timeout); + cap, reply, error)); } else { diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index c4591df8d..f09245a66 100644 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -37,6 +37,9 @@ #include "llview.h" #include "lluuid.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy classifiedStatsResponder_timeout; + class LLClassifiedStatsResponder : public LLHTTPClient::Responder { public: @@ -45,6 +48,7 @@ public: virtual void result(const LLSD& content); //If we get back an error (not found, etc...), handle it here virtual void error(U32 status, const std::string& reason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return classifiedStatsResponder_timeout; } protected: LLHandle mClassifiedPanelHandle; diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 3345eb301..e7442483f 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -46,6 +46,9 @@ #include "message.h" #include "lltrans.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy eventPollResponder_timeout; + namespace { // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error. @@ -72,6 +75,7 @@ namespace void handleMessage(const LLSD& content); virtual void error(U32 status, const std::string& reason); virtual void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventPollResponder_timeout; } virtual void completedRaw(U32 status, const std::string& reason, diff --git a/indra/newview/llfloateractivespeakers.cpp b/indra/newview/llfloateractivespeakers.cpp index c4113c286..3b8bde610 100644 --- a/indra/newview/llfloateractivespeakers.cpp +++ b/indra/newview/llfloateractivespeakers.cpp @@ -57,6 +57,11 @@ #include "llavatarname.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy muteVoiceResponder_timeout; +extern AIHTTPTimeoutPolicy muteTextResponder_timeout; +extern AIHTTPTimeoutPolicy moderationModeResponder_timeout; + using namespace LLOldEvents; const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers @@ -882,6 +887,8 @@ void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return muteVoiceResponder_timeout; } + private: LLUUID mSessionID; }; @@ -947,6 +954,8 @@ void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data) } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return muteTextResponder_timeout; } + private: LLUUID mSessionID; }; @@ -987,6 +996,7 @@ void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_da { llwarns << status << ": " << reason << llendl; } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationModeResponder_timeout; } }; LLHTTPClient::post4(url, data, new ModerationModeResponder()); diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 1314a510a..ad3e873eb 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -37,6 +37,10 @@ #include "llviewerregion.h" #include "lluictrlfactory.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy asyncConsoleResponder_timeout; +extern AIHTTPTimeoutPolicy consoleResponder_timeout; + // Two versions of the sim console API are supported. // // SimConsole capability (deprecated): @@ -72,6 +76,7 @@ namespace // 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 { public: @@ -80,6 +85,7 @@ namespace { sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return asyncConsoleResponder_timeout; } }; class ConsoleResponder : public LLHTTPClient::Responder @@ -110,11 +116,14 @@ namespace } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return consoleResponder_timeout; } + LLTextEditor * mOutput; }; // This handles responses for console commands sent via the asynchronous // API. + class ConsoleResponseNode : public LLHTTPNode { public: diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h index bc20ea9c4..2636b6426 100644 --- a/indra/newview/llfloaterregiondebugconsole.h +++ b/indra/newview/llfloaterregiondebugconsole.h @@ -34,6 +34,8 @@ #include "llhttpclient.h" class LLTextEditor; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy floaterRegionDebugConsole_timeout; typedef boost::signals2::signal< void (const std::string& output)> console_reply_signal_t; @@ -44,6 +46,8 @@ public: LLFloaterRegionDebugConsole(); virtual ~LLFloaterRegionDebugConsole(); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return floaterRegionDebugConsole_timeout; } + // virtual BOOL postBuild(); void onClose(bool app_quitting); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index ecfed8b2f..e7f6b805b 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -91,6 +91,9 @@ const S32 TERRAIN_TEXTURE_COUNT = 4; const S32 CORNER_COUNT = 4; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy estateChangeInfoResponder_timeout; + ///---------------------------------------------------------------------------- /// Local class declaration ///---------------------------------------------------------------------------- @@ -2325,6 +2328,9 @@ public: llinfos << "LLEstateChangeInfoResponder::error " << status << ": " << reason << llendl; } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return estateChangeInfoResponder_timeout; } + private: LLPanelEstateInfo* mpPanel; }; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 48cee545c..c11c95d18 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -96,6 +96,9 @@ const U32 INCLUDE_SCREENSHOT = 0x01 << 0; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy userReportResponder_timeout; + //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- @@ -858,7 +861,7 @@ public: class LLUserReportResponder : public LLHTTPClient::Responder { public: - LLUserReportResponder(): LLHTTPClient::Responder() {} + LLUserReportResponder() { } void error(U32 status, const std::string& reason) { @@ -870,6 +873,7 @@ public: // we don't care about what the server returns LLUploadDialog::modalUploadFinished(); } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return userReportResponder_timeout; } }; void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report) diff --git a/indra/newview/llfloaterteleport.cpp b/indra/newview/llfloaterteleport.cpp index ae4ef5a3a..adfa034b1 100644 --- a/indra/newview/llfloaterteleport.cpp +++ b/indra/newview/llfloaterteleport.cpp @@ -55,6 +55,8 @@ #include "llworld.h" #include "pipeline.h" // for gPipeline +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy placeAvatarTeleportResponder_timeout; // OGPX HTTP responder for PlaceAvatar cap used for Teleport // very similar to the responder in Login, but not as many fields are returned in the TP version @@ -218,6 +220,8 @@ public: // gViewerWindow->setShowProgress(FALSE); } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return placeAvatarTeleportResponder_timeout; } }; // Statics diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index 3ae58c14f..a67d6aa43 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -54,6 +54,8 @@ #include "llvfile.h" #include "message.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy iamHere_timeout; // static LLFloaterTOS* LLFloaterTOS::sInstance = NULL; @@ -128,6 +130,8 @@ class LLIamHere : public LLHTTPClient::Responder mParent->setSiteIsAlive( alive ); } }; + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHere_timeout; } }; // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index a8479e895..baf90fc7e 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -45,6 +45,9 @@ #include "llviewerwindow.h" #include "llhttpclient.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy mediaTypeResponder_timeout; + static LLFloaterURLEntry* sInstance = NULL; // Move this to its own file. @@ -85,6 +88,8 @@ public: if ( floater_url_entry ) floater_url_entry->headerFetchComplete( status, resolved_mime_type ); } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mediaTypeResponder_timeout; } }; //----------------------------------------------------------------------------- diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 3a1d8ebfe..67ba049fe 100644 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -38,11 +38,15 @@ /* File Inclusions */ #include "llhttpclient.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy homeLocationResponder_timeout; + /* Typedef, Enum, Class, Struct, etc. */ class LLHomeLocationResponder : public LLHTTPClient::Responder { virtual void result( const LLSD& content ); virtual void error( U32 status, const std::string& reason ); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return homeLocationResponder_timeout; } }; #endif diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 909fa6aa6..2d5ee2293 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -84,6 +84,11 @@ #include "rlvhandler.h" // [/RLVa:KB] +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy startConferenceChatResponder_timeout; +extern AIHTTPTimeoutPolicy voiceCallCapResponder_timeout; +extern AIHTTPTimeoutPolicy sessionInviteResponder_timeout; + // // Constants // @@ -214,6 +219,8 @@ public: //the possible different language translations } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return startConferenceChatResponder_timeout; } + private: LLUUID mTempSessionID; LLUUID mCreatorID; @@ -301,6 +308,7 @@ public: virtual void error(U32 status, const std::string& reason); // called with bad status codes virtual void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return voiceCallCapResponder_timeout; } private: LLUUID mSessionID; @@ -1564,6 +1572,8 @@ public: //throw something back to the viewer here? } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return sessionInviteResponder_timeout; } + private: LLUUID mSessionID; }; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 628448301..e8c221414 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -77,6 +77,9 @@ #include "rlvhandler.h" // [/RLVa:KB] +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy viewerChatterBoxInvitationAcceptResponder_timeout; + // // Globals // @@ -91,7 +94,6 @@ LLIMMgr* gIMMgr = NULL; //{ // return (LLStringUtil::compareDict( a->mName, b->mName ) < 0); //} - class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Responder { @@ -175,6 +177,8 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerChatterBoxInvitationAcceptResponder_timeout; } + private: LLUUID mSessionID; LLIMMgr::EInvitationType mInvitiationType; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 1122712bc..ab88171ef 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -60,6 +60,9 @@ #include "process.h" #endif +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy createInventoryCategoryResponder_timeout; + // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewers with link items support, former caches are incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; @@ -511,6 +514,8 @@ public: } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return createInventoryCategoryResponder_timeout; } + private: void (*mCallback)(const LLSD&, void*); void* mData; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a7506e19a..c567c505d 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -43,8 +43,10 @@ #include #include -class LLInventoryObserver; +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy fetchInventoryResponder_timeout; +class LLInventoryObserver; class LLInventoryObject; class LLInventoryItem; class LLInventoryCategory; @@ -55,7 +57,6 @@ class LLViewerInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLInventoryModel // @@ -88,6 +89,7 @@ public: fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; void result(const LLSD& content); void error(U32 status, const std::string& reason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fetchInventoryResponder_timeout; } protected: LLSD mRequestSD; }; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 619722b70..03ca87137 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -38,6 +38,10 @@ #include "llviewerregion.h" #include "llviewerwindow.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy inventoryModelFetchDescendentsResponder_timeout; +extern AIHTTPTimeoutPolicy inventoryModelFetchItemResponder_timeout; + const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; const S32 MAX_FETCH_RETRIES = 10; @@ -374,6 +378,7 @@ public: LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; void result(const LLSD& content); void error(U32 status, const std::string& reason); + AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return inventoryModelFetchItemResponder_timeout; } }; void LLInventoryModelFetchItemResponder::result( const LLSD& content ) @@ -388,7 +393,6 @@ void LLInventoryModelFetchItemResponder::error( U32 status, const std::string& r LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); } - class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder { public: @@ -399,6 +403,8 @@ class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder //LLInventoryModelFetchDescendentsResponder() {}; void result(const LLSD& content); void error(U32 status, const std::string& reason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return inventoryModelFetchDescendentsResponder_timeout; } + protected: BOOL getIsRecursive(const LLUUID& cat_id) const; private: @@ -699,14 +705,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch() if (folder_request_body["folders"].size()) { LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); - LLHTTPClient::post4(url, folder_request_body, fetcher, 300.0); + LLHTTPClient::post4(url, folder_request_body, fetcher); } if (folder_request_body_lib["folders"].size()) { std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); - LLHTTPClient::post4(url_lib, folder_request_body_lib, fetcher, 300.0); + LLHTTPClient::post4(url_lib, folder_request_body_lib, fetcher); } } if (item_count) diff --git a/indra/newview/llmapresponders.h b/indra/newview/llmapresponders.h index b6fb8e551..94843d0e9 100644 --- a/indra/newview/llmapresponders.h +++ b/indra/newview/llmapresponders.h @@ -35,9 +35,13 @@ #include "llhttpclient.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy mapLayerResponder_timeout; + class LLMapLayerResponder : public LLHTTPClient::Responder { virtual void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mapLayerResponder_timeout; } }; #endif // LL_LLMAPLAYERRESPONDER_H diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index fa60a85e4..dfdd3e4ec 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -74,6 +74,15 @@ #include +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy meshHeaderResponder_timeout; +extern AIHTTPTimeoutPolicy meshLODResponder_timeout; +extern AIHTTPTimeoutPolicy meshSkinInfoResponder_timeout; +extern AIHTTPTimeoutPolicy meshDecompositionResponder_timeout; +extern AIHTTPTimeoutPolicy meshPhysicsShapeResponder_timeout; +extern AIHTTPTimeoutPolicy wholeModelFeeResponder_timeout; +extern AIHTTPTimeoutPolicy wholeModelUploadResponder_timeout; + LLMeshRepository gMeshRepo; const U32 MAX_MESH_REQUESTS_PER_SECOND = 100; @@ -221,6 +230,7 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshHeaderResponder_timeout; } }; class LLMeshLODResponder : public LLCurl::Responder @@ -246,6 +256,7 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshLODResponder_timeout; } }; class LLMeshSkinInfoResponder : public LLCurl::Responder @@ -264,6 +275,7 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshSkinInfoResponder_timeout; } }; class LLMeshDecompositionResponder : public LLCurl::Responder @@ -282,6 +294,7 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshDecompositionResponder_timeout; } }; class LLMeshPhysicsShapeResponder : public LLCurl::Responder @@ -300,6 +313,7 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshPhysicsShapeResponder_timeout; } }; #if MESH_IMPORT @@ -403,6 +417,7 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return wholeModelFeeResponder_timeout; } }; class LLWholeModelUploadResponder: public LLCurl::Responder @@ -459,6 +474,8 @@ public: } } } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return wholeModelUploadResponder_timeout; } }; #endif //MESH_IMPORT diff --git a/indra/newview/llpanelgroupvoting.cpp b/indra/newview/llpanelgroupvoting.cpp index b7a1ddd7e..978bddfda 100644 --- a/indra/newview/llpanelgroupvoting.cpp +++ b/indra/newview/llpanelgroupvoting.cpp @@ -52,6 +52,10 @@ #include "llviewerwindow.h" #include "llviewerregion.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy startGroupVoteResponder_timeout; +extern AIHTTPTimeoutPolicy groupProposalBallotResponder_timeout; + class LLPanelGroupVoting::impl { public: @@ -705,6 +709,10 @@ public: LLPanelGroupVoting::handleFailure(mGroupID); } + + //Return our timeout policy. + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return startGroupVoteResponder_timeout; } + private: LLUUID mGroupID; }; @@ -735,6 +743,10 @@ public: LLPanelGroupVoting::handleFailure(mGroupID); } + + //Return out timeout policy. + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return groupProposalBallotResponder_timeout; } + private: LLUUID mGroupID; }; @@ -781,8 +793,7 @@ void LLPanelGroupVoting::impl::sendStartGroupProposal() LLHTTPClient::post4( url, body, - new LLStartGroupVoteResponder(mGroupID), - 300); + new LLStartGroupVoteResponder(mGroupID)); } else { //DEPRECATED!!!!!!! This is a fallback just in case our backend cap is not there. Delete this block ASAP! @@ -828,8 +839,7 @@ void LLPanelGroupVoting::impl::sendGroupProposalBallot(const std::string& vote) LLHTTPClient::post4( url, body, - new LLGroupProposalBallotResponder(mGroupID), - 300); + new LLGroupProposalBallotResponder(mGroupID)); } else { //DEPRECATED!!!!!!! This is a fallback just in case our backend cap is not there. Delete this block ASAP! diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index c5163c3a5..a10e9f0cb 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -95,6 +95,9 @@ #define USE_VIEWER_AUTH 0 +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy iamHereLogin_timeout; + const S32 BLACK_BORDER_HEIGHT = 160; const S32 MAX_PASSWORD = 16; @@ -204,6 +207,8 @@ class LLIamHereLogin : public LLHTTPClient::Responder if ( mParent ) mParent->setSiteIsAlive( false ); }; + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereLogin_timeout; } }; // this is global and not a class member to keep crud out of the header file diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 0653111e3..c56f1b618 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -56,6 +56,15 @@ #include "llviewerregion.h" #include "llweb.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy navMeshStatusResponder_timeout; +extern AIHTTPTimeoutPolicy navMeshResponder_timeout; +extern AIHTTPTimeoutPolicy agentStateResponder_timeout; +extern AIHTTPTimeoutPolicy navMeshRebakeResponder_timeout; +extern AIHTTPTimeoutPolicy objectLinksetsResponder_timeout; +extern AIHTTPTimeoutPolicy terrainLinksetsResponder_timeout; +extern AIHTTPTimeoutPolicy charactersResponder_timeout; + #define CAP_SERVICE_RETRIEVE_NAVMESH "RetrieveNavMeshSrc" #define CAP_SERVICE_NAVMESH_STATUS "NavMeshGenerationStatus" @@ -109,6 +118,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string& pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return navMeshStatusResponder_timeout; } protected: @@ -131,6 +141,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string& pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return navMeshResponder_timeout; } protected: @@ -152,6 +163,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string& pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return agentStateResponder_timeout; } protected: @@ -171,6 +183,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string& pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return navMeshRebakeResponder_timeout; } protected: @@ -222,7 +235,6 @@ typedef boost::shared_ptr LinksetsResponderPtr; //--------------------------------------------------------------------------- // ObjectLinksetsResponder //--------------------------------------------------------------------------- - class ObjectLinksetsResponder : public LLHTTPClient::Responder { public: @@ -231,6 +243,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string &pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return objectLinksetsResponder_timeout; } protected: @@ -242,7 +255,6 @@ private: //--------------------------------------------------------------------------- // TerrainLinksetsResponder //--------------------------------------------------------------------------- - class TerrainLinksetsResponder : public LLHTTPClient::Responder { public: @@ -251,6 +263,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string &pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return terrainLinksetsResponder_timeout; } protected: @@ -262,7 +275,6 @@ private: //--------------------------------------------------------------------------- // CharactersResponder //--------------------------------------------------------------------------- - class CharactersResponder : public LLHTTPClient::Responder { public: @@ -271,6 +283,7 @@ public: virtual void result(const LLSD &pContent); virtual void error(U32 pStatus, const std::string &pReason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return charactersResponder_timeout; } protected: @@ -778,8 +791,7 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c // NavMeshStatusResponder //--------------------------------------------------------------------------- -NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) - : LLHTTPClient::Responder(), +NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) : mCapabilityURL(pCapabilityURL), mRegion(pRegion), mRegionUUID(), @@ -812,8 +824,7 @@ void NavMeshStatusResponder::error(U32 pStatus, const std::string& pReason) // NavMeshResponder //--------------------------------------------------------------------------- -NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) - : LLHTTPClient::Responder(), +NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) : mCapabilityURL(pCapabilityURL), mNavMeshVersion(pNavMeshVersion), mNavMeshPtr(pNavMeshPtr) @@ -838,9 +849,7 @@ void NavMeshResponder::error(U32 pStatus, const std::string& pReason) // AgentStateResponder //--------------------------------------------------------------------------- -AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) -: LLHTTPClient::Responder() -, mCapabilityURL(pCapabilityURL) +AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) : mCapabilityURL(pCapabilityURL) { } @@ -866,8 +875,7 @@ void AgentStateResponder::error(U32 pStatus, const std::string &pReason) //--------------------------------------------------------------------------- // navmesh rebake responder //--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) - : LLHTTPClient::Responder(), +NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) : mCapabilityURL(pCapabilityURL), mRebakeNavMeshCallback(pRebakeNavMeshCallback) { @@ -973,8 +981,7 @@ void LinksetsResponder::sendCallback() // ObjectLinksetsResponder //--------------------------------------------------------------------------- -ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) - : LLHTTPClient::Responder(), +ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) : mCapabilityURL(pCapabilityURL), mLinksetsResponsderPtr(pLinksetsResponsderPtr) { @@ -998,8 +1005,7 @@ void ObjectLinksetsResponder::error(U32 pStatus, const std::string &pReason) // TerrainLinksetsResponder //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) - : LLHTTPClient::Responder(), +TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) : mCapabilityURL(pCapabilityURL), mLinksetsResponsderPtr(pLinksetsResponsderPtr) { @@ -1023,8 +1029,7 @@ void TerrainLinksetsResponder::error(U32 pStatus, const std::string &pReason) // CharactersResponder //--------------------------------------------------------------------------- -CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) - : LLHTTPClient::Responder(), +CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) : mCapabilityURL(pCapabilityURL), mRequestId(pRequestId), mCharactersCallback(pCharactersCallback) diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index 65f53822b..6a4b94a8d 100644 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -39,6 +39,9 @@ #include "lltrans.h" #include "llviewerregion.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy productInfoRequestResponder_timeout; + class LLProductInfoRequestResponder : public LLHTTPClient::Responder { public: @@ -54,6 +57,8 @@ public: llwarns << "LLProductInfoRequest::error(" << status << ": " << reason << ")" << llendl; } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return productInfoRequestResponder_timeout; } }; LLProductInfoRequestManager::LLProductInfoRequestManager() : mSkuDescriptions() diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index c92ee3ff3..885b1d65c 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -38,6 +38,9 @@ #include "llhttpclient.h" #include "llpanel.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy remoteParcelRequestResponder_timeout; + class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder { public: @@ -46,6 +49,7 @@ public: virtual void result(const LLSD& content); //If we get back an error (not found, etc...), handle it here virtual void error(U32 status, const std::string& reason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return remoteParcelRequestResponder_timeout; } protected: LLHandle mPlacePanelHandle; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 5c0f7935b..159110fc0 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -54,6 +54,10 @@ #include "llstartup.h" #include "llbuffer.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout; +extern AIHTTPTimeoutPolicy lcl_responder_timeout; + ////////////////////////////////////////////////////////////////////////////// class LLTextureFetchWorker : public LLWorkerClass { @@ -288,7 +292,6 @@ private: }; ////////////////////////////////////////////////////////////////////////////// - class HTTPGetResponder : public LLCurl::Responder { LOG_CLASS(HTTPGetResponder); @@ -301,6 +304,8 @@ public: { } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return HTTPGetResponder_timeout; } + virtual void completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) @@ -3036,8 +3041,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) volatile const S32 & live_sequence, volatile bool & reporting_break, volatile bool & reporting_started) - : LLCurl::Responder(), - mFetcher(fetcher), + : mFetcher(fetcher), mExpectedSequence(expected_sequence), mLiveSequence(live_sequence), mReportingBreak(reporting_break), @@ -3071,6 +3075,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) mReportingStarted = true; } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return lcl_responder_timeout; } private: LLTextureFetch * mFetcher; diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index a646efa87..8b344ae0c 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -37,6 +37,9 @@ #include "llbufferstream.h" #include "json/reader.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy translationReceiver_timeout; + class LLTranslate { public : @@ -63,6 +66,8 @@ public : handleFailure(); } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return translationReceiver_timeout; } + virtual void completedRaw( U32 status, const std::string& reason, diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 0301f2640..5d4c67788 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -37,6 +37,9 @@ #include "llhttpclient.h" #include "llui.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy uploadModelPremissionsResponder_timeout; + class LLUploadPermissionsObserver { public: @@ -105,6 +108,8 @@ public: void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return uploadModelPremissionsResponder_timeout; } + private: LLHandle mObserverHandle; }; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index 3d8b5e017..a9b3a27f3 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -40,6 +40,9 @@ #include "llnotificationsutil.h" #include "llui.h" // getLanguage() +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy setDisplayNameResponder_timeout; + namespace LLViewerDisplayName { // Fired when viewer receives server response to display name change @@ -64,6 +67,8 @@ public: LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return setDisplayNameResponder_timeout; } }; void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 750180608..093a3989b 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -59,6 +59,11 @@ #include "llfloateravatarinfo.h" // for getProfileURL() function //#include "viewerversion.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy mimeDiscoveryResponder_timeout; +extern AIHTTPTimeoutPolicy viewerMediaOpenIDResponder_timeout; +extern AIHTTPTimeoutPolicy viewerMediaWebProfileResponder_timeout; + // Merov: Temporary definitions while porting the new viewer media code to Snowglobe const int LEFT_BUTTON = 0; const int RIGHT_BUTTON = 1; @@ -99,6 +104,8 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mimeDiscoveryResponder_timeout; } + public: viewer_media_t mMediaImpl; bool mInitialized; @@ -139,6 +146,7 @@ public: // We don't care about the content of the response, only the set-cookie header. } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaOpenIDResponder_timeout; } }; class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder @@ -168,7 +176,7 @@ public: } } - void completedRaw( + void completedRaw( U32 status, const std::string& reason, const LLChannelDescriptors& channels, @@ -178,6 +186,8 @@ public: // We don't care about the content of the response, only the set-cookie header. } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaWebProfileResponder_timeout; } + std::string mHost; }; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 74d0e17f2..7f472d32b 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -92,6 +92,10 @@ extern ImportTracker gImportTracker; void dialog_refresh_all(); +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy objectCostResponder_timeout; +extern AIHTTPTimeoutPolicy physicsFlagsResponder_timeout; + #define CULL_VIS //#define ORPHAN_SPAM //#define IGNORE_DEAD @@ -768,11 +772,12 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return objectCostResponder_timeout; } + private: LLSD mObjectIDs; }; - class LLPhysicsFlagsResponder : public LLCurl::Responder { public: @@ -864,6 +869,8 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return physicsFlagsResponder_timeout; } + private: LLSD mObjectIDs; }; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index adb3e25ad..ab9b89d13 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -82,13 +82,16 @@ #pragma warning(disable:4355) #endif +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy baseCapabilitiesComplete_timeout; +extern AIHTTPTimeoutPolicy simulatorFeaturesReceived_timeout; + const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; // The server only keeps our pending agent info for 60 seconds. // 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; @@ -262,6 +265,8 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseCapabilitiesComplete_timeout; } + static boost::intrusive_ptr build( U64 region_handle, S32 id ) { return boost::intrusive_ptr( @@ -1662,8 +1667,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) S32 id = ++mImpl->mHttpResponderID; LLHTTPClient::post4(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - CAP_REQUEST_TIMEOUT); + BaseCapabilitiesComplete::build(getHandle(), id)); } S32 LLViewerRegion::getNumSeedCapRetries() @@ -1698,8 +1702,7 @@ void LLViewerRegion::failedSeedCapability() S32 id = ++mImpl->mHttpResponderID; LLHTTPClient::post4(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - CAP_REQUEST_TIMEOUT); + BaseCapabilitiesComplete::build(getHandle(), id)); } else { @@ -1736,6 +1739,8 @@ public: regionp->setSimulatorFeatures(content); } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return simulatorFeaturesReceived_timeout; } + private: void retry() { @@ -1743,7 +1748,7 @@ private: { mAttempt++; LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get4(mRetryURL, new SimulatorFeaturesReceived(*this), CAP_REQUEST_TIMEOUT); + LLHTTPClient::get4(mRetryURL, new SimulatorFeaturesReceived(*this)); } } @@ -1769,7 +1774,7 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // kick off a request for simulator features - LLHTTPClient::get4(url, new SimulatorFeaturesReceived(url, getHandle()), CAP_REQUEST_TIMEOUT); + LLHTTPClient::get4(url, new SimulatorFeaturesReceived(url, getHandle())); } else { diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 8202bd3a8..799dc4262 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -63,6 +63,8 @@ #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived #include "sgmemstat.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy viewerStatsResponder_timeout; class StatAttributes { @@ -710,6 +712,8 @@ public: { llinfos << "ViewerStatsResponder::result" << llendl; } + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerStatsResponder_timeout; } }; /* diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 4b27f6a2a..67b1b2b10 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -113,6 +113,7 @@ // #include "llfloaterexploreanimations.h" #include "llimagemetadatareader.h" +#include "aihttptimeoutpolicy.h" // #include "llavatarname.h" diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index fe06343b7..de444efff 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -82,6 +82,10 @@ #define USE_SESSION_GROUPS 0 +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy viewerVoiceAccountProvisionResponder_timeout; +extern AIHTTPTimeoutPolicy voiceClientCapResponder_timeout; + static bool sConnectingToAgni = false; F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f; @@ -187,6 +191,8 @@ public: } } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerVoiceAccountProvisionResponder_timeout; } + private: int mRetries; }; @@ -1008,7 +1014,6 @@ static bool sMuteListListener_listening = false; static LLVoiceClientFriendsObserver *friendslist_listener = NULL; /////////////////////////////////////////////////////////////////////////////////////////////// - class LLVoiceClientCapResponder : public LLHTTPClient::Responder { public: @@ -1016,6 +1021,7 @@ public: virtual void error(U32 status, const std::string& reason); // called with bad status codes virtual void result(const LLSD& content); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return voiceClientCapResponder_timeout; } private: }; diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 213bc7c7c..95a2f6c62 100644 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -36,6 +36,10 @@ #include "llviewerprecompiledheaders.h" #include "llhttpclient.h" +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy environmentRequestResponder_timeout; +extern AIHTTPTimeoutPolicy environmentApplyResponder_timeout; + class LLEnvironmentRequest { LOG_CLASS(LLEnvironmentRequest); @@ -54,6 +58,7 @@ class LLEnvironmentRequestResponder: public LLHTTPClient::Responder public: virtual void result(const LLSD& content); virtual void error(U32 status, const std::string& reason); + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return environmentRequestResponder_timeout; } private: friend class LLEnvironmentRequest; @@ -97,6 +102,8 @@ public: virtual void error(U32 status, const std::string& reason); // non-200 errors only + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return environmentApplyResponder_timeout; } + private: friend class LLEnvironmentApply; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index b1c3c4269..f4cd188fe 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -49,6 +49,9 @@ #include #endif +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy XMLRPCTransaction_timeout; + LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const { return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id)); @@ -232,7 +235,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { try { - mCurlEasyRequestStateMachinePtr = new AICurlEasyRequestStateMachine(false); + mCurlEasyRequestStateMachinePtr = new AICurlEasyRequestStateMachine(false); // AIFIXME: This is the only unbuffered AICurlEasyRequestStateMachine left. } catch(AICurlNoEasyHandle const& error) { @@ -246,8 +249,6 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); - // Be a little impatient about establishing connections. - curlEasyRequest_w->setopt(CURLOPT_CONNECTTIMEOUT, 40L); /* Setting the DNS cache timeout to -1 disables it completely. This might help with bug #503 */ @@ -271,7 +272,7 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) setStatus(StatusOtherError); } - curlEasyRequest_w->finalizeRequest(mURI); + curlEasyRequest_w->finalizeRequest(mURI, XMLRPCTransaction_timeout, mCurlEasyRequestStateMachinePtr); } if (mStatus == LLXMLRPCTransaction::StatusNotStarted) // It could be LLXMLRPCTransaction::StatusOtherError. { @@ -479,10 +480,13 @@ size_t LLXMLRPCTransaction::Impl::curlDownloadCallback( size_t n = size * nmemb; #ifdef CWDEBUG + void* lockobj = impl.mCurlEasyRequestStateMachinePtr ? impl.mCurlEasyRequestStateMachinePtr->mCurlEasyRequest.get_ptr().get() : NULL; if (n < 80) - Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << buf2str(data, n) << "\", " << size << ", " << nmemb << ", " << user_data << ")"); + Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << + buf2str(data, n) << "\", " << size << ", " << nmemb << ", " << user_data << ") [" << lockobj << ']'); else - Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << buf2str(data, 40) << "\"...\"" << buf2str(data + n - 40, 40) << "\", " << size << ", " << nmemb << ", " << user_data << ")"); + Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << + buf2str(data, 40) << "\"...\"" << buf2str(data + n - 40, 40) << "\", " << size << ", " << nmemb << ", " << user_data << ") [" << lockobj << ']'); #endif impl.mResponseText.append(data, n); From a40fbf0da1b3897065c710652e129088d7e7ff26 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 6 Oct 2012 01:21:33 +0200 Subject: [PATCH 25/64] Cache hostname of url in CurlEasyRequest::mTimeoutLowercaseHostname Also add DoutCurlEasyEntering debug macro. The caching is necessary because CURLINFO_EFFECTIVE_URL is unreliable and can change several times during the transfer at any moment (as a result of forwarding etc). --- indra/aistatemachine/aicurl.cpp | 120 +++++++++++++++------------ indra/aistatemachine/aicurlprivate.h | 1 + 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 453098801..380630142 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -58,6 +58,9 @@ #include "aihttpheaders.h" #include "aihttptimeoutpolicy.h" #include "aicurleasyrequeststatemachine.h" + +// Some pretty printing for curl easy handle related things: +// Print the lock object related to the current easy handle in every debug output. #ifdef CWDEBUG #include #include @@ -70,9 +73,19 @@ Dout(dc::curl, x); \ libcw_do.pop_marker(); \ } while(0) -#else +#define DoutCurlEasyEntering(x) do { \ + using namespace libcwd; \ + std::ostringstream marker; \ + marker << (void*)this->get_lockobj(); \ + libcw_do.push_marker(); \ + libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ + DoutEntering(dc::curl, x); \ + libcw_do.pop_marker(); \ + } while(0) +#else // !CWDEBUG #define DoutCurlEasy(x) Dout(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') -#endif +#define DoutCurlEasyEntering(x) DoutEntering(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') +#endif // CWDEBUG //================================================================================== // Local variables. @@ -1230,51 +1243,6 @@ void CurlEasyRequest::applyDefaultOptions(void) ); } -void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine) -{ - llassert(!mRequestFinalized); - mResult = CURLE_FAILED_INIT; // General error code; the final result code is stored here by MultiHandle::check_run_count when msg is CURLMSG_DONE. - lldebugs << url << llendl; -#ifdef SHOW_ASSERT - // Do a sanity check on the headers. - int content_type_count = 0; - for (curl_slist* list = mHeaders; list; list = list->next) - { - if (strncmp(list->data, "Content-Type:", 13) == 0) - { - ++content_type_count; - } - } - if (content_type_count > 1) - { - llwarns << content_type_count << " Content-Type: headers!" << llendl; - } -#endif - mRequestFinalized = true; - setopt(CURLOPT_HTTPHEADER, mHeaders); - setoptString(CURLOPT_URL, url); - mTimeoutPolicy = &policy; - state_machine->setTotalDelayTimeout(policy.getTotalDelay()); - // The following line is a bit tricky: we store a pointer to the object without increasing its reference count. - // Of course we could increment the reference count, but that doesn't help much: if then this pointer would - // get "lost" we'd have a memory leak. Either way we must make sure that it is impossible that this pointer - // will be used if the object is deleted [In fact, since this is finalizeRequest() and not addRequest(), - // incrementing the reference counter would be wrong: if addRequest() is never called then the object is - // destroyed shortly after and this pointer is never even used.] - // This pointer is used in MultiHandle::check_run_count, which means that addRequest() was called and - // the reference counter was increased and the object is being kept alive, see the comments above - // command_queue in aicurlthread.cpp. In fact, this object survived until MultiHandle::add_easy_request - // was called and is kept alive by MultiHandle::mAddedEasyRequests. The only way to get deleted after - // that is when MultiHandle::remove_easy_request is called, which first removes the easy handle from - // the multi handle. So that it's (hopefully) no longer possible that info_read() in - // MultiHandle::check_run_count returns this easy handle, after the object is destroyed by deleting - // it from MultiHandle::mAddedEasyRequests. - setopt(CURLOPT_PRIVATE, get_lockobj()); -} - -//............................................................................. -// HTTP Timeout stuff - // url must be of the form // (see http://www.ietf.org/rfc/rfc3986.txt Appendix A for definitions not given here): // @@ -1299,8 +1267,8 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic // - userinfo does not contain a '@', and if it exists, is always terminated by a '@'. // - port does not contain a ':', and if it exists is always prepended by a ':'. // -// Only called by CurlEasyRequest::timeout_add_easy_request. -static std::string extract_canonical_hostname(std::string url) +// Only called by CurlEasyRequest::finalizeRequest. +static std::string extract_canonical_hostname(std::string const& url) { std::string::size_type pos; std::string::size_type authority = 0; // Default if there is no sheme. @@ -1325,13 +1293,57 @@ static std::string extract_canonical_hostname(std::string url) return hostname; } +void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine) +{ + DoutCurlEasyEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")"); + llassert(!mRequestFinalized); + mResult = CURLE_FAILED_INIT; // General error code; the final result code is stored here by MultiHandle::check_run_count when msg is CURLMSG_DONE. +#ifdef SHOW_ASSERT + // Do a sanity check on the headers. + int content_type_count = 0; + for (curl_slist* list = mHeaders; list; list = list->next) + { + if (strncmp(list->data, "Content-Type:", 13) == 0) + { + ++content_type_count; + } + } + if (content_type_count > 1) + { + llwarns << "Requesting: \"" << url << "\": " << content_type_count << " Content-Type: headers!" << llendl; + } +#endif + mRequestFinalized = true; + setopt(CURLOPT_HTTPHEADER, mHeaders); + setoptString(CURLOPT_URL, url); + mTimeoutLowercaseHostname = extract_canonical_hostname(url); + mTimeoutPolicy = &policy; + state_machine->setTotalDelayTimeout(policy.getTotalDelay()); + // The following line is a bit tricky: we store a pointer to the object without increasing its reference count. + // Of course we could increment the reference count, but that doesn't help much: if then this pointer would + // get "lost" we'd have a memory leak. Either way we must make sure that it is impossible that this pointer + // will be used if the object is deleted [In fact, since this is finalizeRequest() and not addRequest(), + // incrementing the reference counter would be wrong: if addRequest() is never called then the object is + // destroyed shortly after and this pointer is never even used.] + // This pointer is used in MultiHandle::check_run_count, which means that addRequest() was called and + // the reference counter was increased and the object is being kept alive, see the comments above + // command_queue in aicurlthread.cpp. In fact, this object survived until MultiHandle::add_easy_request + // was called and is kept alive by MultiHandle::mAddedEasyRequests. The only way to get deleted after + // that is when MultiHandle::remove_easy_request is called, which first removes the easy handle from + // the multi handle. So that it's (hopefully) no longer possible that info_read() in + // MultiHandle::check_run_count returns this easy handle, after the object is destroyed by deleting + // it from MultiHandle::mAddedEasyRequests. + setopt(CURLOPT_PRIVATE, get_lockobj()); +} + +//............................................................................. +// HTTP Timeout stuff + // CURL-THREAD // This is called when the easy handle is actually being added to the multi handle (thus after being queued). void CurlEasyRequest::timeout_add_easy_request(void) { - char* eff_url; - getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); // According to a discussion on IRC with a curl developer, we can rely on this returning the set CURLOPT_URL at this point. - setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(extract_canonical_hostname(eff_url))); + setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mTimeoutLowercaseHostname)); setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); // We do NOT use CURLOPT_LOW_SPEED_TIME and CURLOPT_LOW_SPEED_LIMIT, // instead use a progress meter callback. @@ -1462,9 +1474,7 @@ void CurlEasyRequest::timeout_done(CURLcode code) { if (code == CURLE_OPERATION_TIMEDOUT && !mTimeoutConnected) { - char* eff_url; - getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); //AIFIXME: cache hostname, cause this might have changed. - AIHTTPTimeoutPolicy::connect_timed_out(extract_canonical_hostname(eff_url)); + AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); // AIFIXME: use return value to change priority } // Abuse this boolean to tell any subsequent call to timeout_progress that this certainly can't timeout anymore. diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index 59c7d01dd..43cff7595 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -307,6 +307,7 @@ class CurlEasyRequest : public CurlEasyHandle { // AIFIXME: put all timeout stuff in it's own class. AIHTTPTimeoutPolicy const* mTimeoutPolicy; + std::string mTimeoutLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. bool mTimeoutConnected; // Set if we succeeded to connect and are transfering data. #ifdef CWDEBUG U64 mTimeout_connect_time; // Time at which mTimeoutConnected was set to true (for debugging purposes only). From 1252b0bde2f6740e21ec0892a263e190197355c0 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 8 Oct 2012 02:19:32 +0200 Subject: [PATCH 26/64] HTTP timeout work in progress. * Remove progress meter call back, use read/write/header callbacks instead. * Don't use timeout_lowspeed for ReplyDelay, instead use: * Add timeout stuff to the main loop (CurlEasyRequest::mTimeoutStalled). This patch fixes a few things compared to the previous version. More things need to be fixed. --- indra/aistatemachine/aicurl.cpp | 349 +++++++++++-------- indra/aistatemachine/aicurlprivate.h | 467 +++++++++++++------------- indra/aistatemachine/aicurlthread.cpp | 37 +- indra/aistatemachine/aicurlthread.h | 3 + 4 files changed, 486 insertions(+), 370 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 380630142..1b859e013 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -70,7 +70,9 @@ marker << (void*)this->get_lockobj(); \ libcw_do.push_marker(); \ libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ + libcw_do.inc_indent(2); \ Dout(dc::curl, x); \ + libcw_do.dec_indent(2); \ libcw_do.pop_marker(); \ } while(0) #define DoutCurlEasyEntering(x) do { \ @@ -79,7 +81,9 @@ marker << (void*)this->get_lockobj(); \ libcw_do.push_marker(); \ libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ + libcw_do.inc_indent(2); \ DoutEntering(dc::curl, x); \ + libcw_do.dec_indent(2); \ libcw_do.pop_marker(); \ } while(0) #else // !CWDEBUG @@ -810,9 +814,9 @@ DEFINE_FUNCTION_SETOPT1(curl_debug_callback, CURLOPT_DEBUGFUNCTION) DEFINE_FUNCTION_SETOPT4(curl_write_callback, CURLOPT_HEADERFUNCTION, CURLOPT_WRITEFUNCTION, CURLOPT_INTERLEAVEFUNCTION, CURLOPT_READFUNCTION) //DEFINE_FUNCTION_SETOPT1(curl_read_callback, CURLOPT_READFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_ssl_ctx_callback, CURLOPT_SSL_CTX_FUNCTION) -DEFINE_FUNCTION_SETOPT1(curl_progress_callback, CURLOPT_PROGRESSFUNCTION) DEFINE_FUNCTION_SETOPT3(curl_conv_callback, CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPT_CONV_FROM_UTF8_FUNCTION) #if 0 // Not used by the viewer. +DEFINE_FUNCTION_SETOPT1(curl_progress_callback, CURLOPT_PROGRESSFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_seek_callback, CURLOPT_SEEKFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_ioctl_callback, CURLOPT_IOCTLFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_sockopt_callback, CURLOPT_SOCKOPTFUNCTION) @@ -938,24 +942,6 @@ void CurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* us setopt(CURLOPT_SSL_CTX_DATA, this); } -//static -int CurlEasyRequest::progressCallback(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) -{ - CurlEasyRequest* self = static_cast(userdata); - ThreadSafeCurlEasyRequest* lockobj = self->get_lockobj(); - AICurlEasyRequest_wat lock_self(*lockobj); - return self->mProgressCallback(self->mProgressCallbackUserData, dltotal, dlnow, ultotal, ulnow); -} - -void CurlEasyRequest::setProgressCallback(curl_progress_callback callback, void* userdata) -{ - mProgressCallback = callback; - mProgressCallbackUserData = userdata; - setopt(CURLOPT_PROGRESSFUNCTION, callback ? &CurlEasyRequest::progressCallback : NULL); - setopt(CURLOPT_PROGRESSDATA, userdata ? this : NULL); - setopt(CURLOPT_NOPROGRESS, callback ? 0L: 1L); -} - #define llmaybewarns lllog(LLApp::isExiting() ? LLError::LEVEL_INFO : LLError::LEVEL_WARN, NULL, NULL, false, true) static size_t noHeaderCallback(char* ptr, size_t size, size_t nmemb, void* userdata) @@ -982,19 +968,12 @@ static CURLcode noSSLCtxCallback(CURL* curl, void* sslctx, void* parm) return CURLE_ABORTED_BY_CALLBACK; } -static int noProgressCallback(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) -{ - llmaybewarns << "Calling noProgressCallback(); curl session aborted." << llendl; - return CURLE_ABORTED_BY_CALLBACK; -} - void CurlEasyRequest::revokeCallbacks(void) { if (mHeaderCallback == &noHeaderCallback && mWriteCallback == &noWriteCallback && mReadCallback == &noReadCallback && - mSSLCtxCallback == &noSSLCtxCallback && - mProgressCallback == &noProgressCallback) + mSSLCtxCallback == &noSSLCtxCallback) { // Already revoked. return; @@ -1003,7 +982,6 @@ void CurlEasyRequest::revokeCallbacks(void) mWriteCallback = &noWriteCallback; mReadCallback = &noReadCallback; mSSLCtxCallback = &noSSLCtxCallback; - mProgressCallback = &noProgressCallback; if (active() && !no_warning()) { llwarns << "Revoking callbacks on a still active CurlEasyRequest object!" << llendl; @@ -1012,7 +990,6 @@ void CurlEasyRequest::revokeCallbacks(void) curl_easy_setopt(getEasyHandle(), CURLOPT_WRITEHEADER, &noWriteCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_READFUNCTION, &noReadCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_SSL_CTX_FUNCTION, &noSSLCtxCallback); - curl_easy_setopt(getEasyHandle(), CURLOPT_PROGRESSFUNCTION, &noProgressCallback); } CurlEasyRequest::~CurlEasyRequest() @@ -1339,146 +1316,233 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic //............................................................................. // HTTP Timeout stuff +//static +F64 const CurlEasyRequest::sTimeoutClockWidth = 1.0 / calc_clock_frequency(); // Time between two clock ticks, in seconds. +U64 CurlEasyRequest::sTimeoutClockCount; // Clock count, set once per select() exit. + // CURL-THREAD // This is called when the easy handle is actually being added to the multi handle (thus after being queued). +// AIFIXME: Doing this only when it is actually being added assures that the first curl easy handle that is +// being added for a particular host will be the one getting extra 'DNS lookup' connect time. +// However, if another curl easy handle for the same host is added immediately after, it will +// get less connect time, while it still (also) has to wait for this DNS lookup. +// +// <-----------------------------mTimeoutNothingReceivedYet--------------------------> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ +// | void CurlEasyRequest::timeout_add_easy_request(void) { setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mTimeoutLowercaseHostname)); setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); - // We do NOT use CURLOPT_LOW_SPEED_TIME and CURLOPT_LOW_SPEED_LIMIT, - // instead use a progress meter callback. - setProgressCallback(&AICurlPrivate::CurlEasyRequest::timeout_progress, this); // This boolean is valid (only) if we get a time out event from libcurl. - mTimeoutConnected = false; -} - -// CURL-THREAD -// This is called when the connection succeeded (thus after DNS lookup and connect). -void CurlEasyRequest::timeout_connected(void) -{ - DoutCurlEasy("Calling CurlEasyRequest::timeout_connected(): mTimeoutWaitingForReply = false"); - mTimeoutConnected = true; -#ifdef CWDEBUG - mTimeout_connect_time = get_clock_count(); -#endif - // Now that mTimeoutConnected is set we'll be calling timeout_progress(); initialize the variables used there. - mTimeout_dlnow = 0; - mTimeout_ulnow = 0; - mTimeout_progress_time = 0; - mTimeoutWaitingForReply = false; mTimeoutNothingReceivedYet = true; + mTimeoutStalled = (U64)-1; } // CURL-THREAD -// This is called when data was sent to the server socket. -void CurlEasyRequest::timeout_data_sent(size_t n) +// This is called when body data was sent to the server socket. +// <--mTimeoutLowSpeedOn--> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ ^ ^ ^ ^ +// | | | | | | +bool CurlEasyRequest::timeout_data_sent(size_t n) { - if (!mTimeoutConnected) + // Generate events. + if (!mTimeoutLowSpeedOn) { - // If we can send data (for the first time) then that's our way to know we connected. - timeout_connected(); + // If we can send data (for the first time) then that's our only way to know we connected. + timeout_reset_lowspeed(); } + // Detect low speed. + return timeout_lowspeed(n); +} + +// CURL-THREAD +// This is called when the 'low speed' timer should be started. +// <--mTimeoutLowSpeedOn--> <----mTimeoutLowSpeedOn----> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ +// | | +void CurlEasyRequest::timeout_reset_lowspeed(void) +{ + mTimeoutLowSpeedClock = get_clock_count(); + mTimeoutLowSpeedOn = true; + mTimeoutLastSecond = -1; // This causes timeout_lowspeed to initialize the rest. + mTimeoutStalled = (U64)-1; // Stop reply delay timer. +} + +// CURL-THREAD +// This is called when everything we had to send to the server has been sent. +// <--mTimeoutLowSpeedOn--> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ +// | +void CurlEasyRequest::timeout_upload_finished(void) +{ + // We finished uploading (if there was a body to upload at all), so not more transfer rate timeouts. + mTimeoutLowSpeedOn = false; + // Timeout if the server doesn't reply quick enough. + mTimeoutStalled = sTimeoutClockCount + mTimeoutPolicy->getReplyDelay() / sTimeoutClockWidth; } // CURL-THREAD // This is called when data was received from the server. -void CurlEasyRequest::timeout_data_received(size_t n) -{ - if (n > 0) - { -#ifdef CWDEBUG - if (mTimeoutNothingReceivedYet) - DoutCurlEasy("CurlEasyRequest::timeout_data_received(): Received data from server: set mTimeoutWaitingForReply = false"); -#endif - // We received something, now switch to getLowSpeedLimit()/getLowSpeedTime(). - mTimeoutWaitingForReply = false; - mTimeoutNothingReceivedYet = false; - } -} - -// CURL_THREAD -//static -int CurlEasyRequest::timeout_progress(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) -{ - CurlEasyRequest* self = static_cast(userdata); - - //AIFIXME: There has to be a better way to determine this (because it feels fuzzy, I only allow it to SET the boolean): -#ifdef CWDEBUG - if (!self->mTimeoutWaitingForReply && (self->mTimeoutNothingReceivedYet && ultotal > 0 && ulnow == ultotal)) - Dout(dc::curl, "CurlEasyRequest::timeout_progress(): uploading data finished: set mTimeoutWaitingForReply = true [" << (void*)self->get_lockobj() << ']'); -#endif - llassert(ulnow == 0 || ultotal > 0); // Do we always know the total upload size? - self->mTimeoutWaitingForReply = self->mTimeoutWaitingForReply || (self->mTimeoutNothingReceivedYet && ultotal > 0 && ulnow == ultotal); - - return self->mTimeoutConnected ? self->timeout_progress(dlnow, ulnow) : 0; -} - -// CURL_THREAD -// dlnow is the number of bytes of the BODY of the message, received from the server. -// ulnow is the number of bytes of the BODY of the message, sent to the server so far. // -// Note that the algorithm used here is basically the same as libcurl uses -// for CURLOPT_LOW_SPEED_LIMIT / CURLOPT_LOW_SPEED_TIME, but we can't use that -// because we need to change the variables involved during transfer, which isn't -// officially supported by libcurl. -// Libcurl does the progress callback at the exact same point as checking for -// low speed, and the same data is passed (except the time, unfortunately), so -// the functionality is the same. -int CurlEasyRequest::timeout_progress(double dlnow, double ulnow) +// <-----------------------------mTimeoutNothingReceivedYet--------------------------><----mTimeoutLowSpeedOn----> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ ^ ^ ^ ^ ^ ^ +// | | | | | | | | +bool CurlEasyRequest::timeout_data_received(size_t n) { - static double const clock_frequency = calc_clock_frequency(); - U64 last_time = mTimeout_progress_time; - mTimeout_progress_time = get_clock_count(); - double transfer = (dlnow - mTimeout_dlnow) + (ulnow - mTimeout_ulnow); // Just combine up and download :p. - mTimeout_dlnow = dlnow; - mTimeout_ulnow = ulnow; - if (!last_time || mTimeout_progress_time == last_time) // Is this the first time this function is called (or are we called infinitely fast)? + // The HTTP header of the reply is the first thing we receive. + if (mTimeoutNothingReceivedYet && n > 0) { - DoutCurlEasy("timeout_progress(" << dlnow << ", " << ulnow << ") called at " << - ((mTimeout_progress_time - mTimeout_connect_time) / clock_frequency) << " seconds after connect" << - (last_time ? "" : " (first time)")); - // Start the timer: we need to have a too low transfer rate, for at least - // mTimeoutPolicy->getLowSpeedTime() seconds, counting from this moment. - mTransferOK = mTimeout_progress_time; - return 0; + mTimeoutNothingReceivedYet = false; + // We received something; switch to getLowSpeedLimit()/getLowSpeedTime(). + timeout_reset_lowspeed(); } - transfer *= clock_frequency / (mTimeout_progress_time - last_time); // Bytes per second. - U64 timer = mTimeout_progress_time - mTransferOK; // Low speed timer in clock ticks. - U16 lowspeedtime = mTimeoutWaitingForReply ? mTimeoutPolicy->getReplyDelay() : mTimeoutPolicy->getLowSpeedTime(); - U32 lowspeedlimit = mTimeoutWaitingForReply ? (U32)1 : mTimeoutPolicy->getLowSpeedLimit(); - DoutCurlEasy("timeout_progress(" << dlnow << ", " << ulnow << ") called at " << ((mTimeout_progress_time - mTimeout_connect_time) / clock_frequency) << - " seconds after connect (timer = " << (timer / clock_frequency) << " s ; transfer = " << transfer << " bytes/s; lowspeedtime = " << lowspeedtime << - "; lowspeedlimit = " << lowspeedlimit << " (mTimeoutWaitingForReply == " << (mTimeoutWaitingForReply ? "true" : "false") << "))"); - if (transfer >= lowspeedlimit) + return mTimeoutLowSpeedOn ? timeout_lowspeed(n) : false; +} + +// CURL_THREAD +// bytes is the number of bytes we just sent or received (including headers). +// Returns true if the transfer should be aborted. +// +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ +// | | | | | | | | | | | | | | +bool CurlEasyRequest::timeout_lowspeed(size_t bytes) +{ + DoutCurlEasyEntering("CurlEasyRequest::timeout_lowspeed(" << bytes << ")"); + + // The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works. + // + // libcurl determines the transfer rate since the last call to an equivalent 'lowspeed' function, and then + // triggers a timeout if CURLOPT_LOW_SPEED_TIME long such a transfer value is less than CURLOPT_LOW_SPEED_LIMIT. + // That doesn't work right because once there IS data it can happen that this function is called a few + // times (with less than a milisecond in between) causing seemingly VERY high "transfer rate" spikes. + // The only correct way to determine the transfer rate is to actually average over CURLOPT_LOW_SPEED_TIME + // seconds. + // + // We do this as follows: we create low_speed_time (in seconds) buckets and fill them with the number + // of bytes received during that second. We also keep track of the sum of all bytes received between 'now' + // and 'now - llmax(starttime, low_speed_time)'. Then if that period reaches at least low_speed_time + // seconds, and the transfer rate (sum / low_speed_time) is less than low_speed_limit, we abort. + + // When are we? + S32 second = (sTimeoutClockCount - mTimeoutLowSpeedClock) * sTimeoutClockWidth; + + // If this is the same second as last time, just add the number of bytes to the current bucket. + if (second == mTimeoutLastSecond) { - // Yay! Transfer rate is OK; restart timeout timer. - mTransferOK = mTimeout_progress_time; + mTimeoutTotalBytes += bytes; + mTimeoutBuckets[mTimeoutBucket] += bytes; + return false; } - else if (timer > clock_frequency * lowspeedtime) + + // We arrived at a new second. + // The below is at most executed once per second, even though for + // every currently connected transfer, CPU is not a big issue. + + // Determine the number of buckets needed and increase the number of buckets if needed. + U16 const low_speed_time = mTimeoutPolicy->getLowSpeedTime(); + if (low_speed_time > mTimeoutBuckets.size()) { - // We haven't seen a high enough transfer rate for too long. Abort the transfer. - llwarns << + mTimeoutBuckets.resize(low_speed_time, 0); + } + + S32 s = mTimeoutLastSecond; + mTimeoutLastSecond = second; + + // If this is the first time this function is called, we need to do some initialization. + if (s == -1) + { + mTimeoutBucket = 0; // It doesn't really matter where we start. + mTimeoutTotalBytes = bytes; + mTimeoutBuckets[mTimeoutBucket] = bytes; + return false; + } + + // Update all administration. + U16 bucket = mTimeoutBucket; + while(1) // Run over all the seconds that were skipped. + { + if (++bucket == low_speed_time) + bucket = 0; + if (++s == second) + break; + mTimeoutTotalBytes -= mTimeoutBuckets[bucket]; + mTimeoutBuckets[bucket] = 0; + } + mTimeoutBucket = bucket; + mTimeoutTotalBytes -= mTimeoutBuckets[mTimeoutBucket]; + mTimeoutTotalBytes += bytes; + mTimeoutBuckets[mTimeoutBucket] = bytes; + + // Check if we timed out. + U32 const low_speed_limit = mTimeoutPolicy->getLowSpeedLimit(); + U32 mintotalbytes = low_speed_limit * low_speed_time; + DoutCurlEasy("Transfered " << mTimeoutTotalBytes << " bytes in " << llmin(second, (S32)low_speed_time) << " seconds after " << second << " second" << ((second == 1) ? "" : "s") << "."); + if (second >= low_speed_time) + { + DoutCurlEasy("Average transfer rate is " << (mTimeoutTotalBytes / low_speed_time) << " bytes/s (low speed limit is " << low_speed_limit << " bytes/s)"); + if (mTimeoutTotalBytes < mintotalbytes) + { + // The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer. + llwarns << #ifdef CWDEBUG - (void*)get_lockobj() << ": " + (void*)get_lockobj() << ": " #endif - "aborting slow connection (transfer rate below " << lowspeedlimit << - " for more than " << lowspeedtime << " second" << ((lowspeedtime == 1) ? "" : "s") << ")." << llendl; - return 1; + "aborting slow connection (average transfer rate below " << low_speed_limit << + " for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << ")." << llendl; + return true; + } } - return 0; + + // Calculate how long the data transfer may stall until we should timeout. + llassert_always(mintotalbytes > 0); + S32 max_stall_time = 0; + U32 dropped_bytes = 0; + while(1) + { + if (++bucket == low_speed_time) // The next second the next bucket will be emptied. + bucket = 0; + ++max_stall_time; + dropped_bytes += mTimeoutBuckets[bucket]; + // Note how, when max_stall_time == low_speed_time, dropped_bytes has + // to be equal to mTimeoutTotalBytes, the sum of all vector elements. + llassert_always(max_stall_time < low_speed_time || dropped_bytes == mTimeoutTotalBytes); + // And thus the following will certainly abort. + if (second + max_stall_time >= low_speed_time && mTimeoutTotalBytes - dropped_bytes < mintotalbytes) + break; + } + // If this function isn't called until mTimeoutStalled, we stalled. + mTimeoutStalled = sTimeoutClockCount + max_stall_time / sTimeoutClockWidth; + + return false; } // CURL-THREAD // This is called immediately before done() after curl finished, with code. +// <----mTimeoutLowSpeedOn----> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ +// | void CurlEasyRequest::timeout_done(CURLcode code) { - if (code == CURLE_OPERATION_TIMEDOUT && !mTimeoutConnected) + // AIFIXME: checking mTimeoutConnected doesn't work: CURL_POLL_OUT is set when connect() is called and always + // reset before we get here causing timeout_upload_finished() to be called: mTimeoutConnected will always be true. + // Also mTimeoutNothingReceivedYet is hardly accurate, as what we really want to know is if the DNS failed. + if (code == CURLE_OPERATION_TIMEDOUT && mTimeoutNothingReceivedYet) { + // Inform policy object that there might be problems with this host. AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); // AIFIXME: use return value to change priority } - // Abuse this boolean to tell any subsequent call to timeout_progress that this certainly can't timeout anymore. - mTimeoutConnected = false; + // Make sure no timeout will happen anymore. + mTimeoutLowSpeedOn = false; + mTimeoutStalled = (U64)-1; } // End of HTTP Timeout stuff. @@ -1643,8 +1707,12 @@ size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nm // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); - buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. - buffered_easy_request_w->timeout_data_received(bytes); // Timeout administration. + buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. + if (buffered_easy_request_w->timeout_data_received(bytes)) // Update timeout administration. + { + // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. + return 0; + } return bytes; } @@ -1660,8 +1728,12 @@ size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nme S32 bytes = size * nmemb; // The maximum amount to read. AICurlResponderBuffer_wat buffer_w(*lockobj); buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); - buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. - buffered_easy_request_w->timeout_data_sent(bytes); // Timeout administration. + buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + if (buffered_easy_request_w->timeout_data_sent(bytes)) // Timeout administration. + { + // Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK. + return CURL_READFUNC_ABORT; + } return bytes; // Return the amount actually read (might be lowered by readAfter()). } @@ -1678,8 +1750,11 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n char const* const header_line = static_cast(data); size_t const header_len = size * nmemb; - buffered_easy_request_w->timeout_data_received(header_len); // Timeout administration. - + if (buffered_easy_request_w->timeout_data_received(header_len)) // Update timeout administration. + { + // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. + return 0; + } if (!header_len) { return header_len; diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index 43cff7595..e22976ca6 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -39,290 +39,303 @@ class AIHTTPTimeoutPolicy; class AICurlEasyRequestStateMachine; namespace AICurlPrivate { -namespace curlthread { class MultiHandle; } + namespace curlthread { class MultiHandle; } -struct Stats { - static LLAtomicU32 easy_calls; - static LLAtomicU32 easy_errors; - static LLAtomicU32 easy_init_calls; - static LLAtomicU32 easy_init_errors; - static LLAtomicU32 easy_cleanup_calls; - static LLAtomicU32 multi_calls; - static LLAtomicU32 multi_errors; + struct Stats { + static LLAtomicU32 easy_calls; + static LLAtomicU32 easy_errors; + static LLAtomicU32 easy_init_calls; + static LLAtomicU32 easy_init_errors; + static LLAtomicU32 easy_cleanup_calls; + static LLAtomicU32 multi_calls; + static LLAtomicU32 multi_errors; - static void print(void); -}; + static void print(void); + }; -void handle_multi_error(CURLMcode code); -inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; } + void handle_multi_error(CURLMcode code); + inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; } -bool curlThreadIsRunning(void); -void wakeUpCurlThread(void); -void stopCurlThread(void); + bool curlThreadIsRunning(void); + void wakeUpCurlThread(void); + void stopCurlThread(void); -class ThreadSafeCurlEasyRequest; -class ThreadSafeBufferedCurlEasyRequest; + class ThreadSafeCurlEasyRequest; + class ThreadSafeBufferedCurlEasyRequest; #define DECLARE_SETOPT(param_type) \ - CURLcode setopt(CURLoption option, param_type parameter) + CURLcode setopt(CURLoption option, param_type parameter) -// This class wraps CURL*'s. -// It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl. -class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEvents { - public: - CurlEasyHandle(void); - ~CurlEasyHandle(); + // This class wraps CURL*'s. + // It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl. + class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEvents { + public: + CurlEasyHandle(void); + ~CurlEasyHandle(); - private: - // Disallow assignment. - CurlEasyHandle& operator=(CurlEasyHandle const*); + private: + // Disallow assignment. + CurlEasyHandle& operator=(CurlEasyHandle const*); - public: - // Reset all options of a libcurl session handle. - void reset(void) { llassert(!mActiveMultiHandle); curl_easy_reset(mEasyHandle); } + public: + // Reset all options of a libcurl session handle. + void reset(void) { llassert(!mActiveMultiHandle); curl_easy_reset(mEasyHandle); } - // Set options for a curl easy handle. - DECLARE_SETOPT(long); - DECLARE_SETOPT(long long); - DECLARE_SETOPT(void const*); - DECLARE_SETOPT(curl_debug_callback); - DECLARE_SETOPT(curl_write_callback); - //DECLARE_SETOPT(curl_read_callback); Same type as curl_write_callback - DECLARE_SETOPT(curl_ssl_ctx_callback); - DECLARE_SETOPT(curl_progress_callback); - DECLARE_SETOPT(curl_conv_callback); + // Set options for a curl easy handle. + DECLARE_SETOPT(long); + DECLARE_SETOPT(long long); + DECLARE_SETOPT(void const*); + DECLARE_SETOPT(curl_debug_callback); + DECLARE_SETOPT(curl_write_callback); + //DECLARE_SETOPT(curl_read_callback); Same type as curl_write_callback + DECLARE_SETOPT(curl_ssl_ctx_callback); + DECLARE_SETOPT(curl_conv_callback); #if 0 // Not used by the viewer. - DECLARE_SETOPT(curl_seek_callback); - DECLARE_SETOPT(curl_ioctl_callback); - DECLARE_SETOPT(curl_sockopt_callback); - DECLARE_SETOPT(curl_opensocket_callback); - DECLARE_SETOPT(curl_closesocket_callback); - DECLARE_SETOPT(curl_sshkeycallback); - DECLARE_SETOPT(curl_chunk_bgn_callback); - DECLARE_SETOPT(curl_chunk_end_callback); - DECLARE_SETOPT(curl_fnmatch_callback); + DECLARE_SETOPT(curl_progress_callback); + DECLARE_SETOPT(curl_seek_callback); + DECLARE_SETOPT(curl_ioctl_callback); + DECLARE_SETOPT(curl_sockopt_callback); + DECLARE_SETOPT(curl_opensocket_callback); + DECLARE_SETOPT(curl_closesocket_callback); + DECLARE_SETOPT(curl_sshkeycallback); + DECLARE_SETOPT(curl_chunk_bgn_callback); + DECLARE_SETOPT(curl_chunk_end_callback); + DECLARE_SETOPT(curl_fnmatch_callback); #endif - // Automatically cast int types to a long. Note that U32/S32 are int and - // that you can overload int and long even if they have the same size. - CURLcode setopt(CURLoption option, U32 parameter) { return setopt(option, (long)parameter); } - CURLcode setopt(CURLoption option, S32 parameter) { return setopt(option, (long)parameter); } + // Automatically cast int types to a long. Note that U32/S32 are int and + // that you can overload int and long even if they have the same size. + CURLcode setopt(CURLoption option, U32 parameter) { return setopt(option, (long)parameter); } + CURLcode setopt(CURLoption option, S32 parameter) { return setopt(option, (long)parameter); } - // Clone a libcurl session handle using all the options previously set. - //CurlEasyHandle(CurlEasyHandle const& orig); + // Clone a libcurl session handle using all the options previously set. + //CurlEasyHandle(CurlEasyHandle const& orig); - // URL encode/decode the given string. - char* escape(char* url, int length); - char* unescape(char* url, int inlength , int* outlength); + // URL encode/decode the given string. + char* escape(char* url, int length); + char* unescape(char* url, int inlength , int* outlength); - // Extract information from a curl handle. - private: - CURLcode getinfo_priv(CURLINFO info, void* data); - public: - // The rest are inlines to provide some type-safety. - CURLcode getinfo(CURLINFO info, char** data) { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, curl_slist** data) { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, double* data) { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, long* data) { return getinfo_priv(info, data); } + // Extract information from a curl handle. + private: + CURLcode getinfo_priv(CURLINFO info, void* data); + public: + // The rest are inlines to provide some type-safety. + CURLcode getinfo(CURLINFO info, char** data) { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, curl_slist** data) { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, double* data) { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, long* data) { return getinfo_priv(info, data); } #ifdef __LP64__ // sizeof(long) > sizeof(int) ? - // Overload for integer types that are too small (libcurl demands a long). - CURLcode getinfo(CURLINFO info, S32* data) { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } - CURLcode getinfo(CURLINFO info, U32* data) { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } + // Overload for integer types that are too small (libcurl demands a long). + CURLcode getinfo(CURLINFO info, S32* data) { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } + CURLcode getinfo(CURLINFO info, U32* data) { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } #else // sizeof(long) == sizeof(int) - CURLcode getinfo(CURLINFO info, S32* data) { return getinfo_priv(info, reinterpret_cast(data)); } - CURLcode getinfo(CURLINFO info, U32* data) { return getinfo_priv(info, reinterpret_cast(data)); } + CURLcode getinfo(CURLINFO info, S32* data) { return getinfo_priv(info, reinterpret_cast(data)); } + CURLcode getinfo(CURLINFO info, U32* data) { return getinfo_priv(info, reinterpret_cast(data)); } #endif - // Perform a file transfer (blocking). - CURLcode perform(void); - // Pause and unpause a connection. - CURLcode pause(int bitmask); + // Perform a file transfer (blocking). + CURLcode perform(void); + // Pause and unpause a connection. + CURLcode pause(int bitmask); - // Called when a request is queued for removal. In that case a race between the actual removal - // and revoking of the callbacks is harmless (and happens for the raw non-statemachine version). - void remove_queued(void) { mQueuedForRemoval = true; } - // In case it's added after being removed. - void add_queued(void) { mQueuedForRemoval = false; } + // Called when a request is queued for removal. In that case a race between the actual removal + // and revoking of the callbacks is harmless (and happens for the raw non-statemachine version). + void remove_queued(void) { mQueuedForRemoval = true; } + // In case it's added after being removed. + void add_queued(void) { mQueuedForRemoval = false; } - private: - CURL* mEasyHandle; - CURLM* mActiveMultiHandle; - char* mErrorBuffer; - AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists. - bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal. + private: + CURL* mEasyHandle; + CURLM* mActiveMultiHandle; + char* mErrorBuffer; + AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists. + bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal. #ifdef SHOW_ASSERT - public: - bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread. + public: + bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread. #endif - private: - // This should only be called from MultiHandle; add/remove an easy handle to/from a multi handle. - friend class curlthread::MultiHandle; - CURLMcode add_handle_to_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); - CURLMcode remove_handle_from_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); + private: + // This should only be called from MultiHandle; add/remove an easy handle to/from a multi handle. + friend class curlthread::MultiHandle; + CURLMcode add_handle_to_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); + CURLMcode remove_handle_from_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); - public: - // Returns true if this easy handle was added to a curl multi handle. - bool active(void) const { return mActiveMultiHandle; } + public: + // Returns true if this easy handle was added to a curl multi handle. + bool active(void) const { return mActiveMultiHandle; } - // Returns true when it is expected that the parent will revoke callbacks before the curl - // easy handle is removed from the multi handle; that usually happens when an external - // error demands termination of the request (ie, an expiration). - bool no_warning(void) const { return mQueuedForRemoval || LLApp::isExiting(); } + // Returns true when it is expected that the parent will revoke callbacks before the curl + // easy handle is removed from the multi handle; that usually happens when an external + // error demands termination of the request (ie, an expiration). + bool no_warning(void) const { return mQueuedForRemoval || LLApp::isExiting(); } - // Used for debugging purposes. - bool operator==(CURL* easy_handle) const { return mEasyHandle == easy_handle; } + // Used for debugging purposes. + bool operator==(CURL* easy_handle) const { return mEasyHandle == easy_handle; } - private: - // Call this prior to every curl_easy function whose return value is passed to check_easy_code. - void setErrorBuffer(void); + private: + // Call this prior to every curl_easy function whose return value is passed to check_easy_code. + void setErrorBuffer(void); - static void handle_easy_error(CURLcode code); + static void handle_easy_error(CURLcode code); - // Always first call setErrorBuffer()! - static inline CURLcode check_easy_code(CURLcode code) - { - Stats::easy_calls++; - if (code != CURLE_OK) - handle_easy_error(code); - return code; - } + // Always first call setErrorBuffer()! + static inline CURLcode check_easy_code(CURLcode code) + { + Stats::easy_calls++; + if (code != CURLE_OK) + handle_easy_error(code); + return code; + } - protected: - // Return the underlying curl easy handle. - CURL* getEasyHandle(void) const { return mEasyHandle; } + protected: + // Return the underlying curl easy handle. + CURL* getEasyHandle(void) const { return mEasyHandle; } - // Keep POSTFIELD data alive. - void setPostField(AIPostFieldPtr const& post_field_ptr) { mPostField = post_field_ptr; } + // Keep POSTFIELD data alive. + void setPostField(AIPostFieldPtr const& post_field_ptr) { mPostField = post_field_ptr; } - private: - // Return, and possibly create, the curl (easy) error buffer used by the current thread. - static char* getTLErrorBuffer(void); -}; + private: + // Return, and possibly create, the curl (easy) error buffer used by the current thread. + static char* getTLErrorBuffer(void); + }; -// CurlEasyRequest adds a slightly more powerful interface that can be used -// to set the options on a curl easy handle. -// -// Calling sendRequest() will then connect to the given URL and perform -// the data exchange. Use getResult() to determine if an error occurred. -// -// Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest: -// a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest, -// which is only created by creating a AICurlEasyRequest. When the last copy of such -// AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted -// and the CurlEasyRequest destructed. -class CurlEasyRequest : public CurlEasyHandle { - private: - void setPost_raw(U32 size, char const* data); - public: - void setPost(U32 size) { setPost_raw(size, NULL); } - void setPost(AIPostFieldPtr const& postdata, U32 size); - void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } - void setoptString(CURLoption option, std::string const& value); - void addHeader(char const* str); - void addHeaders(AIHTTPHeaders const& headers); + // CurlEasyRequest adds a slightly more powerful interface that can be used + // to set the options on a curl easy handle. + // + // Calling sendRequest() will then connect to the given URL and perform + // the data exchange. Use getResult() to determine if an error occurred. + // + // Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest: + // a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest, + // which is only created by creating a AICurlEasyRequest. When the last copy of such + // AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted + // and the CurlEasyRequest destructed. + class CurlEasyRequest : public CurlEasyHandle { + private: + void setPost_raw(U32 size, char const* data); + public: + void setPost(U32 size) { setPost_raw(size, NULL); } + void setPost(AIPostFieldPtr const& postdata, U32 size); + void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } + void setoptString(CURLoption option, std::string const& value); + void addHeader(char const* str); + void addHeaders(AIHTTPHeaders const& headers); - private: - // Callback stubs. - static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata); - static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata); - static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata); - static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata); - static int progressCallback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow); + private: + // Callback stubs. + static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata); + static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata); + static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata); + static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata); - curl_write_callback mHeaderCallback; - void* mHeaderCallbackUserData; - curl_write_callback mWriteCallback; - void* mWriteCallbackUserData; - curl_read_callback mReadCallback; - void* mReadCallbackUserData; - curl_ssl_ctx_callback mSSLCtxCallback; - void* mSSLCtxCallbackUserData; - curl_progress_callback mProgressCallback; - void* mProgressCallbackUserData; + curl_write_callback mHeaderCallback; + void* mHeaderCallbackUserData; + curl_write_callback mWriteCallback; + void* mWriteCallbackUserData; + curl_read_callback mReadCallback; + void* mReadCallbackUserData; + curl_ssl_ctx_callback mSSLCtxCallback; + void* mSSLCtxCallbackUserData; - public: - void setHeaderCallback(curl_write_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 setProgressCallback(curl_progress_callback callback, void* userdata); + public: + void setHeaderCallback(curl_write_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); - // Call this if the set callbacks are about to be invalidated. - void revokeCallbacks(void); + // Call this if the set callbacks are about to be invalidated. + void revokeCallbacks(void); - // Reset everything to the state it was in when this object was just created. - void resetState(void); + // Reset everything to the state it was in when this object was just created. + void resetState(void); - private: - // Called from applyDefaultOptions. - void applyProxySettings(void); + private: + // Called from applyDefaultOptions. + void applyProxySettings(void); - // Used in applyProxySettings. - static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); + // Used in applyProxySettings. + static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); - public: - // Set default options that we want applied to all curl easy handles. - void applyDefaultOptions(void); + public: + // Set default options that we want applied to all curl easy handles. + void applyDefaultOptions(void); - // Prepare the request for adding it to a multi session, or calling perform. - // This actually adds the headers that were collected with addHeader. - void finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine); + // Prepare the request for adding it to a multi session, or calling perform. + // This actually adds the headers that were collected with addHeader. + void finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine); - // Called by MultiHandle::add_easy_request when the easy handle is actually being added to the multi handle. - void timeout_add_easy_request(void); + //------------------------------------------- + // Timeout administration events: - // Called when data was written the first time, meaning that the connection succeeded. - void timeout_connected(void); + // Called by MultiHandle::add_easy_request when the easy handle is actually being added to the multi handle. + void timeout_add_easy_request(void); - // Called when data is sent. - void timeout_data_sent(size_t n); + // Called after sending all headers, when body data is written the first time. + void timeout_connected(void); - // Called when data is received. - void timeout_data_received(size_t n); + // Called when everything we had to send to the server has been sent. + void timeout_upload_finished(void); - // Called immediately before done() after curl finished, with code. - void timeout_done(CURLcode code); + // Called when data is sent. Returns true if transfer timed out. + bool timeout_data_sent(size_t n); - // Progress meter callback. - static int timeout_progress(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow); - int timeout_progress(double dlnow, double ulnow); + // Called when data is received. Returns true if transfer timed out. + bool timeout_data_received(size_t n); - // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. - void store_result(CURLcode result) { mResult = result; } + // Called immediately before done() after curl finished, with code. + void timeout_done(CURLcode code); - // Called by MultiHandle::check_run_count() when the curl easy handle is done. - void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } + // Accessor. + bool timeout_has_stalled(void) const { return mTimeoutStalled < sTimeoutClockCount; } - // Called by MultiHandle::check_run_count() to fill info with the transfer info. - void getTransferInfo(AICurlInterface::TransferInfo* info); + private: + // (Re)start low speed transer rate detection. + void timeout_reset_lowspeed(void); - // If result != CURLE_FAILED_INIT then also info was filled. - void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL); + // Common low speed detection, Called from timeout_data_sent or timeout_data_received. + bool timeout_lowspeed(size_t bytes); - private: - curl_slist* mHeaders; - bool mRequestFinalized; - AICurlEasyHandleEvents* mEventsTarget; - CURLcode mResult; + // End of timeout stuff + //------------------------------------------- - // AIFIXME: put all timeout stuff in it's own class. - AIHTTPTimeoutPolicy const* mTimeoutPolicy; - std::string mTimeoutLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. - bool mTimeoutConnected; // Set if we succeeded to connect and are transfering data. -#ifdef CWDEBUG - U64 mTimeout_connect_time; // Time at which mTimeoutConnected was set to true (for debugging purposes only). -#endif - bool mTimeoutWaitingForReply; // Set after we finished sending data to the server and are waiting for the reply. - bool mTimeoutNothingReceivedYet; // Set when connected, reset when the HTML reply header from the server is received. - U64 mTimeout_progress_time; // The (last) time timeout_progress() was called, in microseconds. - U64 mTransferOK; // The last time the transfer rate was OK. - double mTimeout_dlnow; // Number of downloaded bytes so far, as per last call to timeout_progress. - double mTimeout_ulnow; // Number of uploaded bytes so far, as per last call to timeout_progress. + public: + // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. + void store_result(CURLcode result) { mResult = result; } - private: - // This class may only be created by constructing a ThreadSafeCurlEasyRequest. - friend class ThreadSafeCurlEasyRequest; - // Throws AICurlNoEasyHandle. + // Called by MultiHandle::check_run_count() when the curl easy handle is done. + void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } + + // Called by MultiHandle::check_run_count() to fill info with the transfer info. + void getTransferInfo(AICurlInterface::TransferInfo* info); + + // If result != CURLE_FAILED_INIT then also info was filled. + void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL); + + private: + curl_slist* mHeaders; + bool mRequestFinalized; + AICurlEasyHandleEvents* mEventsTarget; + CURLcode mResult; + + // AIFIXME: put all timeout stuff in it's own class. + AIHTTPTimeoutPolicy const* mTimeoutPolicy; + std::string mTimeoutLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. + std::vector mTimeoutBuckets; // An array with the number of bytes transfered in each second. + U16 mTimeoutBucket; // The bucket corresponding to mTimeoutLastSecond. + bool mTimeoutNothingReceivedYet; // Set when connected, reset when the HTML reply header from the server is received. + bool mTimeoutLowSpeedOn; // Set while uploading or downloading data. + S32 mTimeoutLastSecond; // The time at which timeout_lowspeed was last called, in seconds since mTimeoutLowSpeedClock. + U32 mTimeoutTotalBytes; // The sum of all bytes in mTimeoutBuckets. + U64 mTimeoutLowSpeedClock; // Clock count at which low speed transfer rate started. + U64 mTimeoutStalled; // The clock count at which this transaction is considered to be stalling. + public: + static F64 const sTimeoutClockWidth; // Time between two clock ticks in seconds. + static U64 sTimeoutClockCount; // Clock count used during one loop of the main loop. + + private: + // This class may only be created by constructing a ThreadSafeCurlEasyRequest. + friend class ThreadSafeCurlEasyRequest; + // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL) { applyDefaultOptions(); } diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index c593ec910..3e9788c7b 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -30,7 +30,7 @@ #include "linden_common.h" #include "aicurlthread.h" -#include "lltimer.h" // ms_sleep +#include "lltimer.h" // ms_sleep, get_clock_count #include #if !LL_WINDOWS #include @@ -699,7 +699,7 @@ bool MergeIterator::next(curl_socket_t& fd_out, int& ev_bitmask_out) class CurlSocketInfo { public: - CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action); + CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeCurlEasyRequest* lockobj); ~CurlSocketInfo(); void set_action(int action); @@ -709,11 +709,13 @@ class CurlSocketInfo CURL const* mEasy; curl_socket_t mSocketFd; int mAction; + AICurlEasyRequest mEasyRequest; }; -CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action) : - mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE) +CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeCurlEasyRequest* lockobj) : + mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mEasyRequest(lockobj) { + llassert(*AICurlEasyRequest_wat(*mEasyRequest) == easy); mMultiHandle.assign(s, this); llassert(!mMultiHandle.mReadPollSet->contains(s)); llassert(!mMultiHandle.mWritePollSet->contains(s)); @@ -741,7 +743,12 @@ void CurlSocketInfo::set_action(int action) if ((action & CURL_POLL_OUT)) mMultiHandle.mWritePollSet->add(mSocketFd); else + { mMultiHandle.mWritePollSet->remove(mSocketFd); + // If CURL_POLL_OUT is removed, we have nothing more to send apparently. + AICurlEasyRequest_wat curl_easy_request_w(*mEasyRequest); + curl_easy_request_w->timeout_upload_finished(); // Update timeout administration. + } } } @@ -1302,9 +1309,12 @@ void AICurlThread::run(void) llwarns << "select() failed: " << errno << ", " << strerror(errno) << llendl; continue; } - else if (ready == 0) + // Clock count used for timeouts. + CurlEasyRequest::sTimeoutClockCount = get_clock_count(); + if (ready == 0) { multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0); + multi_handle_w->handle_stalls(); } else { @@ -1362,6 +1372,18 @@ MultiHandle::~MultiHandle() delete mReadPollSet; } +void MultiHandle::handle_stalls(void) +{ + for(addedEasyRequests_type::iterator iter = mAddedEasyRequests.begin(); iter != mAddedEasyRequests.end(); iter = mAddedEasyRequests.begin()) + { + if (AICurlEasyRequest_wat(**iter)->timeout_has_stalled()) + { + Dout(dc::curl, "MultiHandle::handle_stalls(): Easy request stalled! [" << (void*)iter->get_ptr().get() << "]"); + remove_easy_request(*iter, false); + } + } +} + #if defined(CWDEBUG) || defined(DEBUG_CURLIO) #undef AI_CASE_RETURN #define AI_CASE_RETURN(x) do { case x: return #x; } while(0) @@ -1398,7 +1420,10 @@ int MultiHandle::socket_callback(CURL* easy, curl_socket_t s, int action, void* { if (!sock_info) { - sock_info = new CurlSocketInfo(self, easy, s, action); + ThreadSafeCurlEasyRequest* ptr; + CURLcode rese = curl_easy_getinfo(easy, CURLINFO_PRIVATE, &ptr); + llassert_always(rese == CURLE_OK); + sock_info = new CurlSocketInfo(self, easy, s, action, ptr); } else { diff --git a/indra/aistatemachine/aicurlthread.h b/indra/aistatemachine/aicurlthread.h index 839c8339e..4e1ff9ff2 100644 --- a/indra/aistatemachine/aicurlthread.h +++ b/indra/aistatemachine/aicurlthread.h @@ -95,6 +95,9 @@ class MultiHandle : public CurlMultiHandle // This is called before sleeping, after calling (one or more times) socket_action. void check_run_count(void); + // Called from the main loop every time select() timed out. + void handle_stalls(void); + public: //----------------------------------------------------------------------------- // Curl socket administration: From 6a4f76a2195fff6b3b2e07452e84e725d3233094 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 8 Oct 2012 04:57:22 +0200 Subject: [PATCH 27/64] Bug fix for previous commit. --- .../aicurleasyrequeststatemachine.cpp | 3 ++ indra/aistatemachine/aicurlthread.cpp | 49 ++++++++++++------- indra/aistatemachine/aicurlthread.h | 6 +++ 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index 868419e91..85a993351 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -88,6 +88,9 @@ void AICurlEasyRequestStateMachine::finished(AICurlEasyRequest_wat&) // CURL-THREAD void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_wat&) { + llassert(mFinished || mTimedOut); // If we neither finished nor timed out, then why is this being removed? + // Note that allowing this would cause an assertion later on for removing + // a CurlResponderBuffer with a still active Responder. set_state(mFinished ? AICurlEasyRequestStateMachine_removed_after_finished : AICurlEasyRequestStateMachine_removed); } diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 3e9788c7b..35e424fbc 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1374,13 +1374,16 @@ MultiHandle::~MultiHandle() void MultiHandle::handle_stalls(void) { - for(addedEasyRequests_type::iterator iter = mAddedEasyRequests.begin(); iter != mAddedEasyRequests.end(); iter = mAddedEasyRequests.begin()) + for(addedEasyRequests_type::iterator iter = mAddedEasyRequests.begin(); iter != mAddedEasyRequests.end();) { if (AICurlEasyRequest_wat(**iter)->timeout_has_stalled()) { Dout(dc::curl, "MultiHandle::handle_stalls(): Easy request stalled! [" << (void*)iter->get_ptr().get() << "]"); - remove_easy_request(*iter, false); + finish_easy_request(*iter, CURLE_OPERATION_TIMEDOUT); + remove_easy_request(iter++, false); } + else + ++iter; } } @@ -1527,6 +1530,11 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request } return (CURLMcode)-2; // Was already removed before, or never added (queued). } + return remove_easy_request(iter, as_per_command); +} + +CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command) +{ CURLMcode res; { AICurlEasyRequest_wat curl_easy_request_w(**iter); @@ -1535,9 +1543,12 @@ CURLMcode MultiHandle::remove_easy_request(AICurlEasyRequest const& easy_request curl_easy_request_w->mRemovedPerCommand = as_per_command; #endif } +#if CWDEBUG + ThreadSafeCurlEasyRequest* lockobj = iter->get_ptr().get(); +#endif mAddedEasyRequests.erase(iter); mHandleAddedOrRemoved = true; - Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)easy_request.get_ptr().get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); + Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles."); // Attempt to add a queued request, if any. if (!mQueuedRequests.empty()) @@ -1565,20 +1576,8 @@ void MultiHandle::check_run_count(void) llassert_always(rese == CURLE_OK); AICurlEasyRequest easy_request(ptr); llassert(*AICurlEasyRequest_wat(*easy_request) == easy); - // Store the result and transfer info in the easy handle. - { - AICurlEasyRequest_wat curl_easy_request_w(*easy_request); - curl_easy_request_w->store_result(msg->data.result); -#ifdef CWDEBUG - char* eff_url; - curl_easy_request_w->getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); - Dout(dc::curl, "Finished: " << eff_url << " (" << curl_easy_strerror(msg->data.result) << ") [CURLINFO_PRIVATE = " << (void*)ptr << "]"); -#endif - // Update timeout administration. - curl_easy_request_w->timeout_done(msg->data.result); - // Signal that this easy handle finished. - curl_easy_request_w->done(curl_easy_request_w); - } + // Store result and trigger events for the easy request. + finish_easy_request(easy_request, msg->data.result); // This invalidates msg, but not easy_request. CURLMcode res = remove_easy_request(easy_request); // This should hold, I think, because the handles are obviously ok and @@ -1602,6 +1601,22 @@ void MultiHandle::check_run_count(void) mPrevRunningHandles = mRunningHandles; } +void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result) +{ + AICurlEasyRequest_wat curl_easy_request_w(*easy_request); + // Store the result in the easy handle. + curl_easy_request_w->store_result(result); +#ifdef CWDEBUG + char* eff_url; + curl_easy_request_w->getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); + Dout(dc::curl, "Finished: " << eff_url << " (" << curl_easy_strerror(result) << ") [CURLINFO_PRIVATE = " << (void*)easy_request.get_ptr().get() << "]"); +#endif + // Update timeout administration. + curl_easy_request_w->timeout_done(result); + // Signal that this easy handle finished. + curl_easy_request_w->done(curl_easy_request_w); +} + } // namespace curlthread } // namespace AICurlPrivate diff --git a/indra/aistatemachine/aicurlthread.h b/indra/aistatemachine/aicurlthread.h index 4e1ff9ff2..b8800440f 100644 --- a/indra/aistatemachine/aicurlthread.h +++ b/indra/aistatemachine/aicurlthread.h @@ -82,6 +82,12 @@ class MultiHandle : public CurlMultiHandle long mTimeOut; // The last time out in ms as set by the callback CURLMOPT_TIMERFUNCTION. private: + // Store result and trigger events for easy request. + void finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result); + // Remove easy request at iter (must exist). + // Note that it's possible that a new request from mQueuedRequests is inserted before iter. + CURLMcode remove_easy_request(addedEasyRequests_type::iterator const& iter, bool as_per_command); + static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp); static int timer_callback(CURLM* multi, long timeout_ms, void* userp); From 02ead94848d5556cbedb8dc0014531ab69b4ae69 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 8 Oct 2012 19:14:22 +0200 Subject: [PATCH 28/64] HTTP timeout work in progress. More debug output. Avoid the new assert when exiting the viewer. --- indra/aistatemachine/aicurl.cpp | 5 ++++ indra/aistatemachine/aicurlthread.cpp | 36 ++++++++++++++------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 1b859e013..cd3716c8a 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1338,6 +1338,7 @@ void CurlEasyRequest::timeout_add_easy_request(void) // This boolean is valid (only) if we get a time out event from libcurl. mTimeoutNothingReceivedYet = true; mTimeoutStalled = (U64)-1; + DoutCurlEasy("timeout_add_easy_request: mTimeoutStalled set to -1"); } // CURL-THREAD @@ -1370,6 +1371,7 @@ void CurlEasyRequest::timeout_reset_lowspeed(void) mTimeoutLowSpeedOn = true; mTimeoutLastSecond = -1; // This causes timeout_lowspeed to initialize the rest. mTimeoutStalled = (U64)-1; // Stop reply delay timer. + DoutCurlEasy("timeout_reset_lowspeed: mTimeoutStalled set to -1"); } // CURL-THREAD @@ -1384,6 +1386,7 @@ void CurlEasyRequest::timeout_upload_finished(void) mTimeoutLowSpeedOn = false; // Timeout if the server doesn't reply quick enough. mTimeoutStalled = sTimeoutClockCount + mTimeoutPolicy->getReplyDelay() / sTimeoutClockWidth; + DoutCurlEasy("timeout_upload_finished: mTimeoutStalled set to sTimeoutClockCount (" << sTimeoutClockCount << ") + " << (mTimeoutStalled - sTimeoutClockCount) << " (" << mTimeoutPolicy->getReplyDelay() << " seconds)"); } // CURL-THREAD @@ -1519,6 +1522,7 @@ bool CurlEasyRequest::timeout_lowspeed(size_t bytes) } // If this function isn't called until mTimeoutStalled, we stalled. mTimeoutStalled = sTimeoutClockCount + max_stall_time / sTimeoutClockWidth; + DoutCurlEasy("mTimeoutStalled set to sTimeoutClockCount (" << sTimeoutClockCount << ") + " << (mTimeoutStalled - sTimeoutClockCount) << " (" << max_stall_time << " seconds)"); return false; } @@ -1543,6 +1547,7 @@ void CurlEasyRequest::timeout_done(CURLcode code) // Make sure no timeout will happen anymore. mTimeoutLowSpeedOn = false; mTimeoutStalled = (U64)-1; + DoutCurlEasy("timeout_done: mTimeoutStalled set to -1"); } // End of HTTP Timeout stuff. diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 35e424fbc..bea567c9e 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -695,6 +695,23 @@ bool MergeIterator::next(curl_socket_t& fd_out, int& ev_bitmask_out) //----------------------------------------------------------------------------- // CurlSocketInfo +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#undef AI_CASE_RETURN +#define AI_CASE_RETURN(x) do { case x: return #x; } while(0) +static char const* action_str(int action) +{ + switch(action) + { + AI_CASE_RETURN(CURL_POLL_NONE); + AI_CASE_RETURN(CURL_POLL_IN); + AI_CASE_RETURN(CURL_POLL_OUT); + AI_CASE_RETURN(CURL_POLL_INOUT); + AI_CASE_RETURN(CURL_POLL_REMOVE); + } + return ""; +} +#endif + // A class with info for each socket that is in use by curl. class CurlSocketInfo { @@ -729,6 +746,7 @@ CurlSocketInfo::~CurlSocketInfo() void CurlSocketInfo::set_action(int action) { + Dout(dc::curl, "CurlSocketInfo::set_action(" << action_str(mAction) << " --> " << action_str(action) << ") [" << (void*)mEasyRequest.get_ptr().get() << "]"); int toggle_action = mAction ^ action; mAction = action; if ((toggle_action & CURL_POLL_IN)) @@ -1366,6 +1384,7 @@ MultiHandle::~MultiHandle() // Curl demands that all handles are removed from the multi session handle before calling curl_multi_cleanup. for(addedEasyRequests_type::iterator iter = mAddedEasyRequests.begin(); iter != mAddedEasyRequests.end(); iter = mAddedEasyRequests.begin()) { + finish_easy_request(*iter, CURLE_OK); // Error code is not used anyway. remove_easy_request(*iter); } delete mWritePollSet; @@ -1387,23 +1406,6 @@ void MultiHandle::handle_stalls(void) } } -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) -#undef AI_CASE_RETURN -#define AI_CASE_RETURN(x) do { case x: return #x; } while(0) -char const* action_str(int action) -{ - switch(action) - { - AI_CASE_RETURN(CURL_POLL_NONE); - AI_CASE_RETURN(CURL_POLL_IN); - AI_CASE_RETURN(CURL_POLL_OUT); - AI_CASE_RETURN(CURL_POLL_INOUT); - AI_CASE_RETURN(CURL_POLL_REMOVE); - } - return ""; -} -#endif - //static int MultiHandle::socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp) { From faee255730cfd4b5441fcf47e08072459f1d3ef6 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 9 Oct 2012 21:01:55 +0200 Subject: [PATCH 29/64] HTTP timeout bug fix! Plus work in progress. Use the better understandable alias CURLOPT_HTTPHEADER in debug output Bug fix - finally! This fixes a bug I've been looking for a week. By accidently calling get_clock_count() for the mTimeoutLowSpeedClock 'event', the time difference 'now' - 'event' becomes negative, which should be impossible; the result being that timeout_low_speed stalled for 24 seconds while looping over the full 32 bit. That in turn made SSL handshakes of libcurl fail, which seemed to be impossible since the calls to libcurl had not changed! --- indra/aistatemachine/aicurl.cpp | 80 ++++++++++++++++++++++---- indra/aistatemachine/aicurlprivate.h | 18 +++++- indra/aistatemachine/aicurlthread.cpp | 51 ++++++++++++++-- indra/aistatemachine/debug_libcurl.cpp | 2 +- 4 files changed, 133 insertions(+), 18 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index cd3716c8a..5f53a8685 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1061,6 +1061,8 @@ static int curl_debug_cb(CURL*, curl_infotype infotype, char* buf, size_t size, break; case CURLINFO_HEADER_OUT: LibcwDoutStream << "H< "; + if (size >= 4 && strncmp(buf, "GET ", 4) == 0) + request->mDebugIsGetMethod = true; break; case CURLINFO_DATA_IN: LibcwDoutStream << "D> "; @@ -1171,6 +1173,7 @@ void CurlEasyRequest::applyProxySettings(void) //static CURLcode CurlEasyRequest::curlCtxCallback(CURL* curl, void* sslctx, void* parm) { + DoutEntering(dc::curl, "CurlEasyRequest::curlCtxCallback((CURL*)" << (void*)curl << ", " << sslctx << ", " << parm << ")"); SSL_CTX* ctx = (SSL_CTX*)sslctx; // Turn off TLS v1.1 (which is not supported anyway by Linden Lab) because otherwise we fail to connect. // Also turn off SSL v2, which is highly broken and strongly discouraged[1]. @@ -1320,6 +1323,21 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic F64 const CurlEasyRequest::sTimeoutClockWidth = 1.0 / calc_clock_frequency(); // Time between two clock ticks, in seconds. U64 CurlEasyRequest::sTimeoutClockCount; // Clock count, set once per select() exit. +void CurlEasyRequest::timeout_timings(void) +{ + double t; + getinfo(CURLINFO_NAMELOOKUP_TIME, &t); + DoutCurlEasy("CURLINFO_NAMELOOKUP_TIME = " << t); + getinfo(CURLINFO_CONNECT_TIME, &t); + DoutCurlEasy("CURLINFO_CONNECT_TIME = " << t); + getinfo(CURLINFO_APPCONNECT_TIME, &t); + DoutCurlEasy("CURLINFO_APPCONNECT_TIME = " << t); + getinfo(CURLINFO_PRETRANSFER_TIME, &t); + DoutCurlEasy("CURLINFO_PRETRANSFER_TIME = " << t); + getinfo(CURLINFO_STARTTRANSFER_TIME, &t); + DoutCurlEasy("CURLINFO_STARTTRANSFER_TIME = " << t); +} + // CURL-THREAD // This is called when the easy handle is actually being added to the multi handle (thus after being queued). // AIFIXME: Doing this only when it is actually being added assures that the first curl easy handle that is @@ -1336,9 +1354,11 @@ void CurlEasyRequest::timeout_add_easy_request(void) setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mTimeoutLowercaseHostname)); setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); // This boolean is valid (only) if we get a time out event from libcurl. + mTimeoutLowSpeedOn = false; mTimeoutNothingReceivedYet = true; mTimeoutStalled = (U64)-1; DoutCurlEasy("timeout_add_easy_request: mTimeoutStalled set to -1"); + mTimeoutUploadFinished = false; } // CURL-THREAD @@ -1367,11 +1387,11 @@ bool CurlEasyRequest::timeout_data_sent(size_t n) // | | void CurlEasyRequest::timeout_reset_lowspeed(void) { - mTimeoutLowSpeedClock = get_clock_count(); + mTimeoutLowSpeedClock = sTimeoutClockCount; mTimeoutLowSpeedOn = true; mTimeoutLastSecond = -1; // This causes timeout_lowspeed to initialize the rest. mTimeoutStalled = (U64)-1; // Stop reply delay timer. - DoutCurlEasy("timeout_reset_lowspeed: mTimeoutStalled set to -1"); + DoutCurlEasy("timeout_reset_lowspeed: mTimeoutLowSpeedClock = " << mTimeoutLowSpeedClock << "; mTimeoutStalled = -1"); } // CURL-THREAD @@ -1382,6 +1402,10 @@ void CurlEasyRequest::timeout_reset_lowspeed(void) // | void CurlEasyRequest::timeout_upload_finished(void) { + if (1 || mTimeoutUploadFinished) + timeout_timings(); + llassert(!mTimeoutUploadFinished); // If we get here twice, then the 'upload finished' detection failed. + mTimeoutUploadFinished = true; // We finished uploading (if there was a body to upload at all), so not more transfer rate timeouts. mTimeoutLowSpeedOn = false; // Timeout if the server doesn't reply quick enough. @@ -1402,6 +1426,16 @@ bool CurlEasyRequest::timeout_data_received(size_t n) if (mTimeoutNothingReceivedYet && n > 0) { mTimeoutNothingReceivedYet = false; + if (!mTimeoutUploadFinished) + { + // mTimeoutUploadFinished not being set this point should only happen for GET requests (in fact, then it is normal), + // because in that case it is impossible to detect the difference between connecting and waiting for a reply without + // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsGetMethod is only valid when the debug channel 'curlio' is on, + // because it is set in the debug callback function. + Debug(llassert(mDebugIsGetMethod || !dc::curlio.is_on())); + // 'Upload finished' detection failed, generate it now. + timeout_upload_finished(); + } // We received something; switch to getLowSpeedLimit()/getLowSpeedTime(). timeout_reset_lowspeed(); } @@ -1435,6 +1469,10 @@ bool CurlEasyRequest::timeout_lowspeed(size_t bytes) // When are we? S32 second = (sTimeoutClockCount - mTimeoutLowSpeedClock) * sTimeoutClockWidth; + llassert(sTimeoutClockWidth > 0.0); + // This REALLY should never happen, but due to another bug it did happened + // and caused something so evil and hard to find that... NEVER AGAIN! + llassert(second >= 0); // If this is the same second as last time, just add the number of bytes to the current bucket. if (second == mTimeoutLastSecond) @@ -1520,7 +1558,7 @@ bool CurlEasyRequest::timeout_lowspeed(size_t bytes) if (second + max_stall_time >= low_speed_time && mTimeoutTotalBytes - dropped_bytes < mintotalbytes) break; } - // If this function isn't called until mTimeoutStalled, we stalled. + // If this function isn't called again within max_stall_time seconds, we stalled. mTimeoutStalled = sTimeoutClockCount + max_stall_time / sTimeoutClockWidth; DoutCurlEasy("mTimeoutStalled set to sTimeoutClockCount (" << sTimeoutClockCount << ") + " << (mTimeoutStalled - sTimeoutClockCount) << " (" << max_stall_time << " seconds)"); @@ -1535,14 +1573,27 @@ bool CurlEasyRequest::timeout_lowspeed(size_t bytes) // | void CurlEasyRequest::timeout_done(CURLcode code) { - // AIFIXME: checking mTimeoutConnected doesn't work: CURL_POLL_OUT is set when connect() is called and always - // reset before we get here causing timeout_upload_finished() to be called: mTimeoutConnected will always be true. - // Also mTimeoutNothingReceivedYet is hardly accurate, as what we really want to know is if the DNS failed. - if (code == CURLE_OPERATION_TIMEDOUT && mTimeoutNothingReceivedYet) + timeout_timings(); + llassert(mTimeoutUploadFinished || mTimeoutNothingReceivedYet); // If this is false then the 'upload finished' detection failed. + if (code == CURLE_OPERATION_TIMEDOUT) { - // Inform policy object that there might be problems with this host. - AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); - // AIFIXME: use return value to change priority + if (mTimeoutNothingReceivedYet) + { + // Only consider this to possibly be related to a DNS lookup if we didn't connect + // to the remote host yet. Note that CURLINFO_CONNECT_TIME gives the time needed + // to connect to the proxy, or first host-- and fails to take redirects into account. + // Also note that CURLINFO_APPCONNECT_TIME gives the time of the FIRST actual + // connect, so for any transfers on the same pipeline that come after this we + // also correctly determine that there was not a problem with a DNS lookup. + double appconnect_time; + getinfo(CURLINFO_APPCONNECT_TIME, &appconnect_time); + if (appconnect_time == 0) + { + // Inform policy object that there might be problems with resolving this host. + AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); + // AIFIXME: use return value to change priority + } + } } // Make sure no timeout will happen anymore. mTimeoutLowSpeedOn = false; @@ -1550,6 +1601,11 @@ void CurlEasyRequest::timeout_done(CURLcode code) DoutCurlEasy("timeout_done: mTimeoutStalled set to -1"); } +void CurlEasyRequest::timeout_print_diagnostics(AIHTTPTimeoutPolicy const& policy) +{ + llwarns << "Request to " << mTimeoutLowercaseHostname << " timed out for " << policy.name() << llendl; +} + // End of HTTP Timeout stuff. //............................................................................. @@ -1880,6 +1936,10 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request if (mResponder) { + if (code == CURLE_OPERATION_TIMEDOUT) + { + curl_easy_request_w->timeout_print_diagnostics(mResponder->getHTTPTimeoutPolicy()); + } if (mEventsTarget) { // Only the responder registers for these events. diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index e22976ca6..5b9d6457f 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -253,7 +253,7 @@ namespace AICurlPrivate { // Called from applyDefaultOptions. void applyProxySettings(void); - // Used in applyProxySettings. + // Used in applyDefaultOptions. static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); public: @@ -288,6 +288,9 @@ namespace AICurlPrivate { // Accessor. bool timeout_has_stalled(void) const { return mTimeoutStalled < sTimeoutClockCount; } + // Called from CurlResponderBuffer::processOutput if a timeout occurred. + void timeout_print_diagnostics(AIHTTPTimeoutPolicy const& policy); + private: // (Re)start low speed transer rate detection. void timeout_reset_lowspeed(void); @@ -300,7 +303,7 @@ namespace AICurlPrivate { public: // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. - void store_result(CURLcode result) { mResult = result; } + void storeResult(CURLcode result) { mResult = result; } // Called by MultiHandle::check_run_count() when the curl easy handle is done. void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } @@ -324,6 +327,7 @@ namespace AICurlPrivate { U16 mTimeoutBucket; // The bucket corresponding to mTimeoutLastSecond. bool mTimeoutNothingReceivedYet; // Set when connected, reset when the HTML reply header from the server is received. bool mTimeoutLowSpeedOn; // Set while uploading or downloading data. + bool mTimeoutUploadFinished; // Only used for debugging. S32 mTimeoutLastSecond; // The time at which timeout_lowspeed was last called, in seconds since mTimeoutLowSpeedClock. U32 mTimeoutTotalBytes; // The sum of all bytes in mTimeoutBuckets. U64 mTimeoutLowSpeedClock; // Clock count at which low speed transfer rate started. @@ -331,13 +335,20 @@ namespace AICurlPrivate { public: static F64 const sTimeoutClockWidth; // Time between two clock ticks in seconds. static U64 sTimeoutClockCount; // Clock count used during one loop of the main loop. +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + bool mDebugIsGetMethod; +#endif private: // This class may only be created by constructing a ThreadSafeCurlEasyRequest. friend class ThreadSafeCurlEasyRequest; // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : - mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL) + mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + mDebugIsGetMethod(false), +#endif + mTimeoutPolicy(NULL) { applyDefaultOptions(); } public: ~CurlEasyRequest(); @@ -348,6 +359,7 @@ namespace AICurlPrivate { // For debugging purposes bool is_finalized(void) const { return mRequestFinalized; } + void timeout_timings(void); // Return pointer to the ThreadSafe (wrapped) version of this object. ThreadSafeCurlEasyRequest* get_lockobj(void); diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index bea567c9e..ee345ac47 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -697,7 +697,7 @@ bool MergeIterator::next(curl_socket_t& fd_out, int& ev_bitmask_out) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) #undef AI_CASE_RETURN -#define AI_CASE_RETURN(x) do { case x: return #x; } while(0) +#define AI_CASE_RETURN(x) case x: return #x; static char const* action_str(int action) { switch(action) @@ -710,6 +710,32 @@ static char const* action_str(int action) } return ""; } + +struct DebugFdSet { + int nfds; + fd_set* fdset; + DebugFdSet(int n, fd_set* p) : nfds(n), fdset(p) { } +}; + +std::ostream& operator<<(std::ostream& os, DebugFdSet const& s) +{ + if (!s.fdset) + return os << "NULL"; + bool first = true; + os << '{'; + for (int fd = 0; fd < s.nfds; ++fd) + { + if (FD_ISSET(fd, s.fdset)) + { + if (!first) + os << ", "; + os << fd; + first = false; + } + } + os << '}'; + return os; +} #endif // A class with info for each socket that is in use by curl. @@ -763,9 +789,17 @@ void CurlSocketInfo::set_action(int action) else { mMultiHandle.mWritePollSet->remove(mSocketFd); - // If CURL_POLL_OUT is removed, we have nothing more to send apparently. + + // The following is a bit of a hack, needed because of the lack of proper timeout callbacks in libcurl. + // The removal of CURL_POLL_OUT could be part of the SSL handshake, therefore check if we're already connected: AICurlEasyRequest_wat curl_easy_request_w(*mEasyRequest); - curl_easy_request_w->timeout_upload_finished(); // Update timeout administration. + double pretransfer_time; + curl_easy_request_w->getinfo(CURLINFO_PRETRANSFER_TIME, &pretransfer_time); + if (pretransfer_time > 0) + { + // If CURL_POLL_OUT is removed and CURLINFO_PRETRANSFER_TIME is already set, then we have nothing more to send apparently. + curl_easy_request_w->timeout_upload_finished(); // Update timeout administration. + } } } } @@ -1284,6 +1318,9 @@ void AICurlThread::run(void) timeout.tv_sec = timeout_ms / 1000; timeout.tv_usec = (timeout_ms % 1000) * 1000; #ifdef CWDEBUG +#ifdef DEBUG_CURLIO + Dout(dc::curl|flush_cf|continued_cf, "select(" << nfds << ", " << DebugFdSet(nfds, read_fd_set) << ", " << DebugFdSet(nfds, write_fd_set) << ", NULL, timeout = " << timeout_ms << " ms) = "); +#else static int last_nfds = -1; static long last_timeout_ms = -1; static int same_count = 0; @@ -1299,10 +1336,14 @@ void AICurlThread::run(void) { ++same_count; } +#endif #endif ready = select(nfds, read_fd_set, write_fd_set, NULL, &timeout); mWakeUpMutex.unlock(); #ifdef CWDEBUG +#ifdef DEBUG_CURLIO + Dout(dc::finish|cond_error_cf(ready == -1), ready); +#else static int last_ready = -2; static int last_errno = 0; if (!same) @@ -1319,6 +1360,7 @@ void AICurlThread::run(void) last_ready = ready; if (ready == -1) last_errno = errno; +#endif #endif // Select returns the total number of bits set in each of the fd_set's (upon return), // or -1 when an error occurred. A value of 0 means that a timeout occurred. @@ -1329,6 +1371,7 @@ void AICurlThread::run(void) } // Clock count used for timeouts. CurlEasyRequest::sTimeoutClockCount = get_clock_count(); + Dout(dc::curl, "CurlEasyRequest::sTimeoutClockCount = " << CurlEasyRequest::sTimeoutClockCount); if (ready == 0) { multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0); @@ -1607,7 +1650,7 @@ void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CUR { AICurlEasyRequest_wat curl_easy_request_w(*easy_request); // Store the result in the easy handle. - curl_easy_request_w->store_result(result); + curl_easy_request_w->storeResult(result); #ifdef CWDEBUG char* eff_url; curl_easy_request_w->getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); diff --git a/indra/aistatemachine/debug_libcurl.cpp b/indra/aistatemachine/debug_libcurl.cpp index 85833d4b1..512bc696c 100644 --- a/indra/aistatemachine/debug_libcurl.cpp +++ b/indra/aistatemachine/debug_libcurl.cpp @@ -249,7 +249,7 @@ std::ostream& operator<<(std::ostream& os, CURLoption option) CASEPRINT(CURLOPT_LOW_SPEED_TIME); CASEPRINT(CURLOPT_RESUME_FROM); CASEPRINT(CURLOPT_COOKIE); - CASEPRINT(CURLOPT_RTSPHEADER); + CASEPRINT(CURLOPT_HTTPHEADER); CASEPRINT(CURLOPT_HTTPPOST); CASEPRINT(CURLOPT_SSLCERT); CASEPRINT(CURLOPT_KEYPASSWD); From 3ac46f5fa7b04d6cca57eeaed24c7351382cf72d Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 12 Oct 2012 19:39:11 +0200 Subject: [PATCH 30/64] HTTP timeout work in progress. --- indra/aistatemachine/aicurl.cpp | 40 +++++++++++++++------------ indra/aistatemachine/aicurlthread.cpp | 37 ++++++++++++++++++++++++- indra/newview/llxmlrpctransaction.cpp | 17 +++++++----- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 5f53a8685..fae7c3633 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1573,26 +1573,32 @@ bool CurlEasyRequest::timeout_lowspeed(size_t bytes) // | void CurlEasyRequest::timeout_done(CURLcode code) { - timeout_timings(); llassert(mTimeoutUploadFinished || mTimeoutNothingReceivedYet); // If this is false then the 'upload finished' detection failed. - if (code == CURLE_OPERATION_TIMEDOUT) + if (code == CURLE_OPERATION_TIMEDOUT || code == CURLE_COULDNT_RESOLVE_HOST) { - if (mTimeoutNothingReceivedYet) + bool dns_problem = false; + if (code == CURLE_COULDNT_RESOLVE_HOST) { - // Only consider this to possibly be related to a DNS lookup if we didn't connect - // to the remote host yet. Note that CURLINFO_CONNECT_TIME gives the time needed - // to connect to the proxy, or first host-- and fails to take redirects into account. - // Also note that CURLINFO_APPCONNECT_TIME gives the time of the FIRST actual - // connect, so for any transfers on the same pipeline that come after this we - // also correctly determine that there was not a problem with a DNS lookup. - double appconnect_time; - getinfo(CURLINFO_APPCONNECT_TIME, &appconnect_time); - if (appconnect_time == 0) - { - // Inform policy object that there might be problems with resolving this host. - AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); - // AIFIXME: use return value to change priority - } + // Note that CURLINFO_OS_ERRNO returns 0; we don't know any more than this. + llwarns << "Failed to resolve hostname " << mTimeoutLowercaseHostname << llendl; + dns_problem = true; + } + else if (mTimeoutNothingReceivedYet) + { + // Only consider this to possibly be related to a DNS lookup if we didn't + // resolved the host yet, which can be detected by asking for + // CURLINFO_NAMELOOKUP_TIME which is set when libcurl initiates the + // actual connect and thus knows the IP# (possibly from it's DNS cache). + double namelookup_time; + getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time); + dns_problem = (namelookup_time == 0); + } + if (dns_problem) + { + // Inform policy object that there might be problems with resolving this host. + // This will increase the connect timeout the next time we try to connect to this host. + AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); + // AIFIXME: use return value to change priority } } // Make sure no timeout will happen anymore. diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index ee345ac47..0abb4bc82 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1654,7 +1654,42 @@ void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CUR #ifdef CWDEBUG char* eff_url; curl_easy_request_w->getinfo(CURLINFO_EFFECTIVE_URL, &eff_url); - Dout(dc::curl, "Finished: " << eff_url << " (" << curl_easy_strerror(result) << ") [CURLINFO_PRIVATE = " << (void*)easy_request.get_ptr().get() << "]"); + double namelookup_time, connect_time, appconnect_time, pretransfer_time, starttransfer_time; + curl_easy_request_w->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time); + curl_easy_request_w->getinfo(CURLINFO_CONNECT_TIME, &connect_time); + curl_easy_request_w->getinfo(CURLINFO_APPCONNECT_TIME, &appconnect_time); + curl_easy_request_w->getinfo(CURLINFO_PRETRANSFER_TIME, &pretransfer_time); + curl_easy_request_w->getinfo(CURLINFO_STARTTRANSFER_TIME, &starttransfer_time); + // If appconnect_time is almost equal to connect_time, then it was just set because this is a connection re-use. + if (appconnect_time - connect_time <= 1e-6) + { + appconnect_time = 0; + } + // If connect_time is almost equal to namelookup_time, then it was just set because it was already connected. + if (connect_time - namelookup_time <= 1e-6) + { + connect_time = 0; + } + // If namelookup_time is less than 500 microseconds, then it's very likely just a DNS cache lookup. + if (namelookup_time < 500e-6) + { + namelookup_time = 0; + } + Dout(dc::curl|continued_cf, "Finished: " << eff_url << " (" << curl_easy_strerror(result) << "); "); + if (namelookup_time) + { + Dout(dc::continued, "namelookup time: " << namelookup_time << ", "); + } + if (connect_time) + { + Dout(dc::continued, "connect_time: " << connect_time << ", "); + } + if (appconnect_time) + { + Dout(dc::continued, "appconnect_time: " << appconnect_time << ", "); + } + Dout(dc::finish, "pretransfer_time: " << pretransfer_time << ", starttransfer_time: " << starttransfer_time << + ". [CURLINFO_PRIVATE = " << (void*)easy_request.get_ptr().get() << "]"); #endif // Update timeout administration. curl_easy_request_w->timeout_done(result); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index f4cd188fe..e96dc1f2f 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -322,15 +322,18 @@ void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success) if (!success) { // AICurlEasyRequestStateMachine did abort. - // This currently only happens when libcurl didn't finish before the timer expired. - std::ostringstream msg; - F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeOut"); - msg << "Connection to " << mURI << " timed out (" << timeout_value << " s)!"; - if (timeout_value < 40) + // This currently only happens when libcurl didn't finish before the timer expired, or when the viewer was quit. + if (LLApp::isRunning()) { - msg << "\nTry increasing CurlRequestTimeOut in Debug Settings."; + std::ostringstream msg; + F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeOut"); + msg << "Connection to " << mURI << " timed out (" << timeout_value << " s)!"; + if (timeout_value < 40) + { + msg << "\nTry increasing CurlRequestTimeOut in Debug Settings."; + } + setStatus(LLXMLRPCTransaction::StatusOtherError, msg.str()); } - setStatus(LLXMLRPCTransaction::StatusOtherError, msg.str()); return; } From 83312fbb74f440d126113d8d93ea8b7e2e1edf18 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 14 Oct 2012 02:45:58 +0200 Subject: [PATCH 31/64] Allow getinfo() to be called on a const CurlEasyRequest. --- indra/aistatemachine/aicurl.cpp | 14 ++++++++++++-- indra/aistatemachine/aicurlprivate.h | 24 +++++++++++++----------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index fae7c3633..c26b93f2e 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -678,7 +678,7 @@ char* CurlEasyHandle::getTLErrorBuffer(void) return tldata.mCurlErrorBuffer; } -void CurlEasyHandle::setErrorBuffer(void) +void CurlEasyHandle::setErrorBuffer(void) const { char* error_buffer = getTLErrorBuffer(); if (mErrorBuffer != error_buffer) @@ -697,7 +697,7 @@ void CurlEasyHandle::setErrorBuffer(void) } } -CURLcode CurlEasyHandle::getinfo_priv(CURLINFO info, void* data) +CURLcode CurlEasyHandle::getinfo_priv(CURLINFO info, void* data) const { setErrorBuffer(); return check_easy_code(curl_easy_getinfo(mEasyHandle, info, data)); @@ -874,6 +874,11 @@ ThreadSafeCurlEasyRequest* CurlEasyRequest::get_lockobj(void) return static_cast(AIThreadSafeSimpleDC::wrapper_cast(this)); } +ThreadSafeCurlEasyRequest const* CurlEasyRequest::get_lockobj(void) const +{ + return static_cast(AIThreadSafeSimpleDC::wrapper_cast(this)); +} + //static size_t CurlEasyRequest::headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { @@ -1723,6 +1728,11 @@ ThreadSafeBufferedCurlEasyRequest* CurlResponderBuffer::get_lockobj(void) return static_cast(AIThreadSafeSimple::wrapper_cast(this)); } +ThreadSafeBufferedCurlEasyRequest const* CurlResponderBuffer::get_lockobj(void) const +{ + return static_cast(AIThreadSafeSimple::wrapper_cast(this)); +} + void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder) { mInput.reset(new LLBufferArray); diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index 5b9d6457f..a95b9a314 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -116,20 +116,20 @@ namespace AICurlPrivate { // Extract information from a curl handle. private: - CURLcode getinfo_priv(CURLINFO info, void* data); + CURLcode getinfo_priv(CURLINFO info, void* data) const; public: // The rest are inlines to provide some type-safety. - CURLcode getinfo(CURLINFO info, char** data) { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, curl_slist** data) { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, double* data) { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, long* data) { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, char** data) const { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, curl_slist** data) const { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, double* data) const { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, long* data) const { return getinfo_priv(info, data); } #ifdef __LP64__ // sizeof(long) > sizeof(int) ? // Overload for integer types that are too small (libcurl demands a long). - CURLcode getinfo(CURLINFO info, S32* data) { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } - CURLcode getinfo(CURLINFO info, U32* data) { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } + CURLcode getinfo(CURLINFO info, S32* data) const { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } + CURLcode getinfo(CURLINFO info, U32* data) const { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } #else // sizeof(long) == sizeof(int) - CURLcode getinfo(CURLINFO info, S32* data) { return getinfo_priv(info, reinterpret_cast(data)); } - CURLcode getinfo(CURLINFO info, U32* data) { return getinfo_priv(info, reinterpret_cast(data)); } + CURLcode getinfo(CURLINFO info, S32* data) const { return getinfo_priv(info, reinterpret_cast(data)); } + CURLcode getinfo(CURLINFO info, U32* data) const { return getinfo_priv(info, reinterpret_cast(data)); } #endif // Perform a file transfer (blocking). @@ -146,7 +146,7 @@ namespace AICurlPrivate { private: CURL* mEasyHandle; CURLM* mActiveMultiHandle; - char* mErrorBuffer; + mutable char* mErrorBuffer; AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists. bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal. #ifdef SHOW_ASSERT @@ -174,7 +174,7 @@ namespace AICurlPrivate { private: // Call this prior to every curl_easy function whose return value is passed to check_easy_code. - void setErrorBuffer(void); + void setErrorBuffer(void) const; static void handle_easy_error(CURLcode code); @@ -363,6 +363,7 @@ namespace AICurlPrivate { // Return pointer to the ThreadSafe (wrapped) version of this object. ThreadSafeCurlEasyRequest* get_lockobj(void); + ThreadSafeCurlEasyRequest const* get_lockobj(void) const; protected: // Pass events to parent. @@ -452,6 +453,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC public: // Return pointer to the ThreadSafe (wrapped) version of this object. ThreadSafeBufferedCurlEasyRequest* get_lockobj(void); + ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const; // Return true when prepRequest was already called and the object has not been // invalidated as a result of calling timed_out(). From 2539e41e595b1c9dc2a9e4816d05d4c12ad441b1 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 14 Oct 2012 02:53:36 +0200 Subject: [PATCH 32/64] Avoid problems in case a host also resolves to IPv6 --- indra/aistatemachine/aicurl.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index c26b93f2e..9898da6da 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1213,6 +1213,16 @@ void CurlEasyRequest::applyDefaultOptions(void) setopt(CURLOPT_NOSIGNAL, 1); // Cache DNS look ups an hour. If we set it smaller we risk frequent connect timeouts in cases where DNS look ups are slow. setopt(CURLOPT_DNS_CACHE_TIMEOUT, 3600); + // Only resolve to IPV4. + // Rationale: if a host resolves to both, ipv4 and ipv6, then this stops libcurl from + // using the ipv6 address. If we don't do that then libcurl first attempts to connect + // to the ipv4 IP number (using only HALF the connect timeout we passed to it!) and if + // that fails try the ipv6 IP number, which then most likely fails with "network unreachable". + // Then libcurl immediately returns with just the ipv6 error as result masking the real problem. + // Since the viewer doesn't support IPv6 at least for UDP services, and there are no + // transition plans to IPv6 anywhere at this moment, the easiest way to get rid of this + // problem is by simply not falling back to ipv6. + setopt(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); // Disable SSL/TLS session caching; some servers (aka id.secondlife.com) refuse connections when session ids are enabled. setopt(CURLOPT_SSL_SESSIONID_CACHE, 0); // Set the CURL options for either SOCKS or HTTP proxy. From ccd98c3c3dc9d35d694f1cd4e03f902b068555db Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 14 Oct 2012 02:55:45 +0200 Subject: [PATCH 33/64] Fix comment. --- indra/aistatemachine/aicurlprivate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index a95b9a314..15d606f79 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -397,7 +397,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC buffer_ptr_t& getInput(void) { return mInput; } buffer_ptr_t& getOutput(void) { return mOutput; } - // Called if libcurl doesn't deliver within mRequestTimeOut seconds. + // Called if libcurl doesn't deliver within AIHTTPTimeoutPolicy::mMaximumTotalDelay seconds. void timed_out(void); // Called after removed_from_multi_handle was called. From 9fba54ad5d5c9ea577551f8df052c9b4bf4b54e5 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 14 Oct 2012 03:13:32 +0200 Subject: [PATCH 34/64] On failed transfer, print CURLINFO_OS_ERRNO when available. --- indra/aistatemachine/aicurlthread.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 0abb4bc82..28c66d6fc 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -864,10 +864,9 @@ AICurlThread::~AICurlThread() } #if LL_WINDOWS -static std::string formatWSAError() +static std::string formatWSAError(int e = WSAGetLastError()) { std::ostringstream r; - int e = WSAGetLastError(); LPTSTR error_str = 0; r << e; if(FormatMessage( @@ -884,9 +883,9 @@ static std::string formatWSAError() return r.str(); } #elif WINDOWS_CODE -static std::string formatWSAError() +static std::string formatWSAError(int e = errno) { - return strerror(errno); + return strerror(e); } #endif @@ -1675,7 +1674,21 @@ void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CUR { namelookup_time = 0; } - Dout(dc::curl|continued_cf, "Finished: " << eff_url << " (" << curl_easy_strerror(result) << "); "); + Dout(dc::curl|continued_cf, "Finished: " << eff_url << " (" << curl_easy_strerror(result)); + if (result != CURLE_OK) + { + long os_error; + curl_easy_request_w->getinfo(CURLINFO_OS_ERRNO, &os_error); + if (os_error) + { +#if WINDOWS_CODE + Dout(dc::continued, ": " << formatWSAError(os_error)); +#else + Dout(dc::continued, ": " << strerror(os_error)); +#endif + } + } + Dout(dc::continued, "); "); if (namelookup_time) { Dout(dc::continued, "namelookup time: " << namelookup_time << ", "); From 76fc30e460ac8cff4c4d19149017f73cc9ee4f5e Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 15 Oct 2012 03:34:32 +0200 Subject: [PATCH 35/64] HTTPTimeout work in progress. * Moved DoutCurlEasy and DoutCurlEasyEntering from aicurl.cpp to aicurl.h and renamed them to DoutCurl and DoutCurlEntering respectively. * Moved the callback functions from aicurl.cpp to aicurlthread.cpp. * In CurlEasyRequest, renamed timeout_timings to print_curl_timings and mTimeoutLowercaseHostname to mLowercaseHostname. * Put all remaining CurlEasyRequest::mTimeout* variables and timeout_* methods in curlthread::HTTPTimeout, stripping them of said prefix, and moved the definition to aicurlprivate.h. Added a ThreadSafeCurlEasyRequest* member and a get_lockobj() method so to that class so we can still use DoutCurl / DoutCurlEntering. timeout_add_easy_request was removed completely and reimplemented as the constructor of HTTPTimeout. timeout_has_stalled was renamed to HTTPTimeout::has_stalled, but also reimplemented as CurlEasyRequest::has_stalled. * CurlEasyRequest::mRequestFinalized was removed and it's functionality taken over by CurlEasyRequest::mTimeoutPolicy. * Fixed the indentation of struct Stats, class CurlEasyHandle and class CurlEasyRequest. * Added CurlEasyRequest::set_timeout_opts * Added CurlSocketInfo::mTimeout (LLPointer). * mUploadFinished is now reset in HTTPTimeout::data_received, this was needed because "HEAD /something" header-only messages triggered upload_finished (unlike "GET ..."), and in combination with redirection that caused an assert. --- indra/aistatemachine/aicurl.cpp | 689 ++------------------------ indra/aistatemachine/aicurl.h | 34 +- indra/aistatemachine/aicurlprivate.h | 544 ++++++++++---------- indra/aistatemachine/aicurlthread.cpp | 615 ++++++++++++++++++++++- 4 files changed, 961 insertions(+), 921 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 9898da6da..f4d65c49e 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -59,38 +59,6 @@ #include "aihttptimeoutpolicy.h" #include "aicurleasyrequeststatemachine.h" -// Some pretty printing for curl easy handle related things: -// Print the lock object related to the current easy handle in every debug output. -#ifdef CWDEBUG -#include -#include -#define DoutCurlEasy(x) do { \ - using namespace libcwd; \ - std::ostringstream marker; \ - marker << (void*)this->get_lockobj(); \ - libcw_do.push_marker(); \ - libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ - libcw_do.inc_indent(2); \ - Dout(dc::curl, x); \ - libcw_do.dec_indent(2); \ - libcw_do.pop_marker(); \ - } while(0) -#define DoutCurlEasyEntering(x) do { \ - using namespace libcwd; \ - std::ostringstream marker; \ - marker << (void*)this->get_lockobj(); \ - libcw_do.push_marker(); \ - libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ - libcw_do.inc_indent(2); \ - DoutEntering(dc::curl, x); \ - libcw_do.dec_indent(2); \ - libcw_do.pop_marker(); \ - } while(0) -#else // !CWDEBUG -#define DoutCurlEasy(x) Dout(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') -#define DoutCurlEasyEntering(x) DoutEntering(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') -#endif // CWDEBUG - //================================================================================== // Local variables. // @@ -571,6 +539,11 @@ void intrusive_ptr_release(Responder* responder) namespace AICurlPrivate { +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +// CURLOPT_DEBUGFUNCTION function. +extern int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr); +#endif + //static LLAtomicU32 Stats::easy_calls; LLAtomicU32 Stats::easy_errors; @@ -841,7 +814,7 @@ void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size) { llassert_always(postdata->data()); - DoutCurlEasy("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\"."); + DoutCurl("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\"."); setPostField(postdata); // Make sure the data stays around until we don't need it anymore. setPost_raw(size, postdata->data()); @@ -852,7 +825,7 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data) if (!data) { // data == NULL when we're going to read the data using CURLOPT_READFUNCTION. - DoutCurlEasy("POST size is " << size << " bytes."); + DoutCurl("POST size is " << size << " bytes."); } // Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)). @@ -1015,7 +988,8 @@ void CurlEasyRequest::resetState(void) reset(); curl_slist_free_all(mHeaders); mHeaders = NULL; - mRequestFinalized = false; + mTimeoutPolicy = NULL; + mTimeout = NULL; mEventsTarget = NULL; mResult = CURLE_FAILED_INIT; applyDefaultOptions(); @@ -1023,125 +997,16 @@ void CurlEasyRequest::resetState(void) void CurlEasyRequest::addHeader(char const* header) { - llassert(!mRequestFinalized); + llassert(!mTimeoutPolicy); // Cannot add a header after calling finalizeRequest. mHeaders = curl_slist_append(mHeaders, header); } void CurlEasyRequest::addHeaders(AIHTTPHeaders const& headers) { - llassert(!mRequestFinalized); + llassert(!mTimeoutPolicy); // Cannot add headers after calling finalizeRequest. headers.append_to(mHeaders); } -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) - -static int curl_debug_cb(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr) -{ -#ifdef CWDEBUG - using namespace ::libcwd; - - CurlEasyRequest* request = (CurlEasyRequest*)user_ptr; - std::ostringstream marker; - marker << (void*)request->get_lockobj(); - libcw_do.push_marker(); - libcw_do.marker().assign(marker.str().data(), marker.str().size()); - if (!debug::channels::dc::curlio.is_on()) - debug::channels::dc::curlio.on(); - LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio|cond_nonewline_cf(infotype == CURLINFO_TEXT)) -#else - if (infotype == CURLINFO_TEXT) - { - while (size > 0 && (buf[size - 1] == '\r' || buf[size - 1] == '\n')) - --size; - } - LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio) -#endif - switch (infotype) - { - case CURLINFO_TEXT: - LibcwDoutStream << "* "; - break; - case CURLINFO_HEADER_IN: - LibcwDoutStream << "H> "; - break; - case CURLINFO_HEADER_OUT: - LibcwDoutStream << "H< "; - if (size >= 4 && strncmp(buf, "GET ", 4) == 0) - request->mDebugIsGetMethod = true; - break; - case CURLINFO_DATA_IN: - LibcwDoutStream << "D> "; - break; - case CURLINFO_DATA_OUT: - LibcwDoutStream << "D< "; - break; - case CURLINFO_SSL_DATA_IN: - LibcwDoutStream << "S> "; - break; - case CURLINFO_SSL_DATA_OUT: - LibcwDoutStream << "S< "; - break; - default: - LibcwDoutStream << "?? "; - } - if (infotype == CURLINFO_TEXT) - LibcwDoutStream.write(buf, size); - else if (infotype == CURLINFO_HEADER_IN || infotype == CURLINFO_HEADER_OUT) - LibcwDoutStream << libcwd::buf2str(buf, size); - else if (infotype == CURLINFO_DATA_IN) - { - LibcwDoutStream << size << " bytes"; - bool finished = false; - size_t i = 0; - while (i < size) - { - char c = buf[i]; - if (!('0' <= c && c <= '9') && !('a' <= c && c <= 'f')) - { - if (0 < i && i + 1 < size && buf[i] == '\r' && buf[i + 1] == '\n') - { - // Binary output: "[0-9a-f]*\r\n ...binary data..." - LibcwDoutStream << ": \"" << libcwd::buf2str(buf, i + 2) << "\"..."; - finished = true; - } - break; - } - ++i; - } - if (!finished && size > 9 && buf[0] == '<') - { - // Human readable output: html, xml or llsd. - if (!strncmp(buf, "", 6)) - { - LibcwDoutStream << ": \"" << libcwd::buf2str(buf, size) << '"'; - finished = true; - } - } - if (!finished) - { - // Unknown format. Only print the first and last 20 characters. - if (size > 40UL) - { - LibcwDoutStream << ": \"" << libcwd::buf2str(buf, 20) << "\"...\"" << libcwd::buf2str(&buf[size - 20], 20) << '"'; - } - else - { - LibcwDoutStream << ": \"" << libcwd::buf2str(buf, size) << '"'; - } - } - } - else if (infotype == CURLINFO_DATA_OUT) - LibcwDoutStream << size << " bytes: \"" << libcwd::buf2str(buf, size) << '"'; - else - LibcwDoutStream << size << " bytes"; - LibcwDoutScopeEnd; -#ifdef CWDEBUG - libcw_do.pop_marker(); -#endif - return 0; -} -#endif - void CurlEasyRequest::applyProxySettings(void) { LLProxy& proxy = *LLProxy::getInstance(); @@ -1232,7 +1097,7 @@ void CurlEasyRequest::applyDefaultOptions(void) if (dc::curlio.is_on()) { setopt(CURLOPT_VERBOSE, 1); - setopt(CURLOPT_DEBUGFUNCTION, &curl_debug_cb); + setopt(CURLOPT_DEBUGFUNCTION, &debug_callback); setopt(CURLOPT_DEBUGDATA, this); } ); @@ -1290,8 +1155,8 @@ static std::string extract_canonical_hostname(std::string const& url) void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine) { - DoutCurlEasyEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")"); - llassert(!mRequestFinalized); + DoutCurlEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")"); + llassert(!mTimeoutPolicy); // May only call finalizeRequest once! mResult = CURLE_FAILED_INIT; // General error code; the final result code is stored here by MultiHandle::check_run_count when msg is CURLMSG_DONE. #ifdef SHOW_ASSERT // Do a sanity check on the headers. @@ -1308,10 +1173,9 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic llwarns << "Requesting: \"" << url << "\": " << content_type_count << " Content-Type: headers!" << llendl; } #endif - mRequestFinalized = true; setopt(CURLOPT_HTTPHEADER, mHeaders); setoptString(CURLOPT_URL, url); - mTimeoutLowercaseHostname = extract_canonical_hostname(url); + mLowercaseHostname = extract_canonical_hostname(url); mTimeoutPolicy = &policy; state_machine->setTotalDelayTimeout(policy.getTotalDelay()); // The following line is a bit tricky: we store a pointer to the object without increasing its reference count. @@ -1331,305 +1195,31 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic setopt(CURLOPT_PRIVATE, get_lockobj()); } -//............................................................................. -// HTTP Timeout stuff +// AIFIXME: Doing this only when it is actually being added assures that the first curl easy handle that is +// // being added for a particular host will be the one getting extra 'DNS lookup' connect time. +// // However, if another curl easy handle for the same host is added immediately after, it will +// // get less connect time, while it still (also) has to wait for this DNS lookup. +void CurlEasyRequest::set_timeout_opts(void) +{ + setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mLowercaseHostname)); + setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); +} -//static -F64 const CurlEasyRequest::sTimeoutClockWidth = 1.0 / calc_clock_frequency(); // Time between two clock ticks, in seconds. -U64 CurlEasyRequest::sTimeoutClockCount; // Clock count, set once per select() exit. - -void CurlEasyRequest::timeout_timings(void) +void CurlEasyRequest::print_curl_timings(void) const { double t; getinfo(CURLINFO_NAMELOOKUP_TIME, &t); - DoutCurlEasy("CURLINFO_NAMELOOKUP_TIME = " << t); + DoutCurl("CURLINFO_NAMELOOKUP_TIME = " << t); getinfo(CURLINFO_CONNECT_TIME, &t); - DoutCurlEasy("CURLINFO_CONNECT_TIME = " << t); + DoutCurl("CURLINFO_CONNECT_TIME = " << t); getinfo(CURLINFO_APPCONNECT_TIME, &t); - DoutCurlEasy("CURLINFO_APPCONNECT_TIME = " << t); + DoutCurl("CURLINFO_APPCONNECT_TIME = " << t); getinfo(CURLINFO_PRETRANSFER_TIME, &t); - DoutCurlEasy("CURLINFO_PRETRANSFER_TIME = " << t); + DoutCurl("CURLINFO_PRETRANSFER_TIME = " << t); getinfo(CURLINFO_STARTTRANSFER_TIME, &t); - DoutCurlEasy("CURLINFO_STARTTRANSFER_TIME = " << t); + DoutCurl("CURLINFO_STARTTRANSFER_TIME = " << t); } -// CURL-THREAD -// This is called when the easy handle is actually being added to the multi handle (thus after being queued). -// AIFIXME: Doing this only when it is actually being added assures that the first curl easy handle that is -// being added for a particular host will be the one getting extra 'DNS lookup' connect time. -// However, if another curl easy handle for the same host is added immediately after, it will -// get less connect time, while it still (also) has to wait for this DNS lookup. -// -// <-----------------------------mTimeoutNothingReceivedYet--------------------------> -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ -// | -void CurlEasyRequest::timeout_add_easy_request(void) -{ - setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(mTimeoutLowercaseHostname)); - setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); - // This boolean is valid (only) if we get a time out event from libcurl. - mTimeoutLowSpeedOn = false; - mTimeoutNothingReceivedYet = true; - mTimeoutStalled = (U64)-1; - DoutCurlEasy("timeout_add_easy_request: mTimeoutStalled set to -1"); - mTimeoutUploadFinished = false; -} - -// CURL-THREAD -// This is called when body data was sent to the server socket. -// <--mTimeoutLowSpeedOn--> -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ ^ ^ ^ ^ ^ -// | | | | | | -bool CurlEasyRequest::timeout_data_sent(size_t n) -{ - // Generate events. - if (!mTimeoutLowSpeedOn) - { - // If we can send data (for the first time) then that's our only way to know we connected. - timeout_reset_lowspeed(); - } - // Detect low speed. - return timeout_lowspeed(n); -} - -// CURL-THREAD -// This is called when the 'low speed' timer should be started. -// <--mTimeoutLowSpeedOn--> <----mTimeoutLowSpeedOn----> -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ ^ -// | | -void CurlEasyRequest::timeout_reset_lowspeed(void) -{ - mTimeoutLowSpeedClock = sTimeoutClockCount; - mTimeoutLowSpeedOn = true; - mTimeoutLastSecond = -1; // This causes timeout_lowspeed to initialize the rest. - mTimeoutStalled = (U64)-1; // Stop reply delay timer. - DoutCurlEasy("timeout_reset_lowspeed: mTimeoutLowSpeedClock = " << mTimeoutLowSpeedClock << "; mTimeoutStalled = -1"); -} - -// CURL-THREAD -// This is called when everything we had to send to the server has been sent. -// <--mTimeoutLowSpeedOn--> -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ -// | -void CurlEasyRequest::timeout_upload_finished(void) -{ - if (1 || mTimeoutUploadFinished) - timeout_timings(); - llassert(!mTimeoutUploadFinished); // If we get here twice, then the 'upload finished' detection failed. - mTimeoutUploadFinished = true; - // We finished uploading (if there was a body to upload at all), so not more transfer rate timeouts. - mTimeoutLowSpeedOn = false; - // Timeout if the server doesn't reply quick enough. - mTimeoutStalled = sTimeoutClockCount + mTimeoutPolicy->getReplyDelay() / sTimeoutClockWidth; - DoutCurlEasy("timeout_upload_finished: mTimeoutStalled set to sTimeoutClockCount (" << sTimeoutClockCount << ") + " << (mTimeoutStalled - sTimeoutClockCount) << " (" << mTimeoutPolicy->getReplyDelay() << " seconds)"); -} - -// CURL-THREAD -// This is called when data was received from the server. -// -// <-----------------------------mTimeoutNothingReceivedYet--------------------------><----mTimeoutLowSpeedOn----> -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ ^ ^ ^ ^ ^ ^ ^ -// | | | | | | | | -bool CurlEasyRequest::timeout_data_received(size_t n) -{ - // The HTTP header of the reply is the first thing we receive. - if (mTimeoutNothingReceivedYet && n > 0) - { - mTimeoutNothingReceivedYet = false; - if (!mTimeoutUploadFinished) - { - // mTimeoutUploadFinished not being set this point should only happen for GET requests (in fact, then it is normal), - // because in that case it is impossible to detect the difference between connecting and waiting for a reply without - // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsGetMethod is only valid when the debug channel 'curlio' is on, - // because it is set in the debug callback function. - Debug(llassert(mDebugIsGetMethod || !dc::curlio.is_on())); - // 'Upload finished' detection failed, generate it now. - timeout_upload_finished(); - } - // We received something; switch to getLowSpeedLimit()/getLowSpeedTime(). - timeout_reset_lowspeed(); - } - return mTimeoutLowSpeedOn ? timeout_lowspeed(n) : false; -} - -// CURL_THREAD -// bytes is the number of bytes we just sent or received (including headers). -// Returns true if the transfer should be aborted. -// -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ -// | | | | | | | | | | | | | | -bool CurlEasyRequest::timeout_lowspeed(size_t bytes) -{ - DoutCurlEasyEntering("CurlEasyRequest::timeout_lowspeed(" << bytes << ")"); - - // The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works. - // - // libcurl determines the transfer rate since the last call to an equivalent 'lowspeed' function, and then - // triggers a timeout if CURLOPT_LOW_SPEED_TIME long such a transfer value is less than CURLOPT_LOW_SPEED_LIMIT. - // That doesn't work right because once there IS data it can happen that this function is called a few - // times (with less than a milisecond in between) causing seemingly VERY high "transfer rate" spikes. - // The only correct way to determine the transfer rate is to actually average over CURLOPT_LOW_SPEED_TIME - // seconds. - // - // We do this as follows: we create low_speed_time (in seconds) buckets and fill them with the number - // of bytes received during that second. We also keep track of the sum of all bytes received between 'now' - // and 'now - llmax(starttime, low_speed_time)'. Then if that period reaches at least low_speed_time - // seconds, and the transfer rate (sum / low_speed_time) is less than low_speed_limit, we abort. - - // When are we? - S32 second = (sTimeoutClockCount - mTimeoutLowSpeedClock) * sTimeoutClockWidth; - llassert(sTimeoutClockWidth > 0.0); - // This REALLY should never happen, but due to another bug it did happened - // and caused something so evil and hard to find that... NEVER AGAIN! - llassert(second >= 0); - - // If this is the same second as last time, just add the number of bytes to the current bucket. - if (second == mTimeoutLastSecond) - { - mTimeoutTotalBytes += bytes; - mTimeoutBuckets[mTimeoutBucket] += bytes; - return false; - } - - // We arrived at a new second. - // The below is at most executed once per second, even though for - // every currently connected transfer, CPU is not a big issue. - - // Determine the number of buckets needed and increase the number of buckets if needed. - U16 const low_speed_time = mTimeoutPolicy->getLowSpeedTime(); - if (low_speed_time > mTimeoutBuckets.size()) - { - mTimeoutBuckets.resize(low_speed_time, 0); - } - - S32 s = mTimeoutLastSecond; - mTimeoutLastSecond = second; - - // If this is the first time this function is called, we need to do some initialization. - if (s == -1) - { - mTimeoutBucket = 0; // It doesn't really matter where we start. - mTimeoutTotalBytes = bytes; - mTimeoutBuckets[mTimeoutBucket] = bytes; - return false; - } - - // Update all administration. - U16 bucket = mTimeoutBucket; - while(1) // Run over all the seconds that were skipped. - { - if (++bucket == low_speed_time) - bucket = 0; - if (++s == second) - break; - mTimeoutTotalBytes -= mTimeoutBuckets[bucket]; - mTimeoutBuckets[bucket] = 0; - } - mTimeoutBucket = bucket; - mTimeoutTotalBytes -= mTimeoutBuckets[mTimeoutBucket]; - mTimeoutTotalBytes += bytes; - mTimeoutBuckets[mTimeoutBucket] = bytes; - - // Check if we timed out. - U32 const low_speed_limit = mTimeoutPolicy->getLowSpeedLimit(); - U32 mintotalbytes = low_speed_limit * low_speed_time; - DoutCurlEasy("Transfered " << mTimeoutTotalBytes << " bytes in " << llmin(second, (S32)low_speed_time) << " seconds after " << second << " second" << ((second == 1) ? "" : "s") << "."); - if (second >= low_speed_time) - { - DoutCurlEasy("Average transfer rate is " << (mTimeoutTotalBytes / low_speed_time) << " bytes/s (low speed limit is " << low_speed_limit << " bytes/s)"); - if (mTimeoutTotalBytes < mintotalbytes) - { - // The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer. - llwarns << -#ifdef CWDEBUG - (void*)get_lockobj() << ": " -#endif - "aborting slow connection (average transfer rate below " << low_speed_limit << - " for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << ")." << llendl; - return true; - } - } - - // Calculate how long the data transfer may stall until we should timeout. - llassert_always(mintotalbytes > 0); - S32 max_stall_time = 0; - U32 dropped_bytes = 0; - while(1) - { - if (++bucket == low_speed_time) // The next second the next bucket will be emptied. - bucket = 0; - ++max_stall_time; - dropped_bytes += mTimeoutBuckets[bucket]; - // Note how, when max_stall_time == low_speed_time, dropped_bytes has - // to be equal to mTimeoutTotalBytes, the sum of all vector elements. - llassert_always(max_stall_time < low_speed_time || dropped_bytes == mTimeoutTotalBytes); - // And thus the following will certainly abort. - if (second + max_stall_time >= low_speed_time && mTimeoutTotalBytes - dropped_bytes < mintotalbytes) - break; - } - // If this function isn't called again within max_stall_time seconds, we stalled. - mTimeoutStalled = sTimeoutClockCount + max_stall_time / sTimeoutClockWidth; - DoutCurlEasy("mTimeoutStalled set to sTimeoutClockCount (" << sTimeoutClockCount << ") + " << (mTimeoutStalled - sTimeoutClockCount) << " (" << max_stall_time << " seconds)"); - - return false; -} - -// CURL-THREAD -// This is called immediately before done() after curl finished, with code. -// <----mTimeoutLowSpeedOn----> -// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done -// ^ -// | -void CurlEasyRequest::timeout_done(CURLcode code) -{ - llassert(mTimeoutUploadFinished || mTimeoutNothingReceivedYet); // If this is false then the 'upload finished' detection failed. - if (code == CURLE_OPERATION_TIMEDOUT || code == CURLE_COULDNT_RESOLVE_HOST) - { - bool dns_problem = false; - if (code == CURLE_COULDNT_RESOLVE_HOST) - { - // Note that CURLINFO_OS_ERRNO returns 0; we don't know any more than this. - llwarns << "Failed to resolve hostname " << mTimeoutLowercaseHostname << llendl; - dns_problem = true; - } - else if (mTimeoutNothingReceivedYet) - { - // Only consider this to possibly be related to a DNS lookup if we didn't - // resolved the host yet, which can be detected by asking for - // CURLINFO_NAMELOOKUP_TIME which is set when libcurl initiates the - // actual connect and thus knows the IP# (possibly from it's DNS cache). - double namelookup_time; - getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time); - dns_problem = (namelookup_time == 0); - } - if (dns_problem) - { - // Inform policy object that there might be problems with resolving this host. - // This will increase the connect timeout the next time we try to connect to this host. - AIHTTPTimeoutPolicy::connect_timed_out(mTimeoutLowercaseHostname); - // AIFIXME: use return value to change priority - } - } - // Make sure no timeout will happen anymore. - mTimeoutLowSpeedOn = false; - mTimeoutStalled = (U64)-1; - DoutCurlEasy("timeout_done: mTimeoutStalled set to -1"); -} - -void CurlEasyRequest::timeout_print_diagnostics(AIHTTPTimeoutPolicy const& policy) -{ - llwarns << "Request to " << mTimeoutLowercaseHostname << " timed out for " << policy.name() << llendl; -} - -// End of HTTP Timeout stuff. -//............................................................................. - void CurlEasyRequest::getTransferInfo(AICurlInterface::TransferInfo* info) { // Curl explicitly demands a double for these info's. @@ -1780,225 +1370,6 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w curl_easy_request_w->addHeaders(headers); } -//static -size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data) -{ - ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); - - // We need to lock the curl easy request object too, because that lock is used - // to make sure that callbacks and destruction aren't done simultaneously. - AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); - - S32 bytes = size * nmemb; // The amount to write. - AICurlResponderBuffer_wat buffer_w(*lockobj); - // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. - //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; - buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); - buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. - if (buffered_easy_request_w->timeout_data_received(bytes)) // Update timeout administration. - { - // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. - return 0; - } - return bytes; -} - -//static -size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) -{ - ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); - - // We need to lock the curl easy request object too, because that lock is used - // to make sure that callbacks and destruction aren't done simultaneously. - AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); - - S32 bytes = size * nmemb; // The maximum amount to read. - AICurlResponderBuffer_wat buffer_w(*lockobj); - buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); - buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. - if (buffered_easy_request_w->timeout_data_sent(bytes)) // Timeout administration. - { - // Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK. - return CURL_READFUNC_ABORT; - } - return bytes; // Return the amount actually read (might be lowered by readAfter()). -} - -//static -size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data) -{ - ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); - - // We need to lock the curl easy request object, because that lock is used - // to make sure that callbacks and destruction aren't done simultaneously. - AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); - - // This used to be headerCallback() in llurlrequest.cpp. - - char const* const header_line = static_cast(data); - size_t const header_len = size * nmemb; - if (buffered_easy_request_w->timeout_data_received(header_len)) // Update timeout administration. - { - // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. - return 0; - } - if (!header_len) - { - return header_len; - } - std::string header(header_line, header_len); - if (!LLStringUtil::_isASCII(header)) - { - return header_len; - } - - // Per HTTP spec the first header line must be the status line. - if (header.substr(0, 5) == "HTTP/") - { - std::string::iterator const begin = header.begin(); - std::string::iterator const end = header.end(); - std::string::iterator pos1 = std::find(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'); - U32 status; - std::string reason; - if (pos3 != end && std::isdigit(*pos1)) - { - status = atoi(&header_line[pos1 - begin]); - reason.assign(pos2, pos3); - } - else - { - status = HTTP_INTERNAL_ERROR; - reason = "Header parse error."; - llwarns << "Received broken header line from server: \"" << header << "\"" << llendl; - } - { - AICurlResponderBuffer_wat curl_responder_buffer_w(*lockobj); - curl_responder_buffer_w->received_HTTP_header(); - curl_responder_buffer_w->setStatusAndReason(status, 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); - - AICurlResponderBuffer_wat(*lockobj)->received_header(key, value); - } - else - { - LLStringUtil::trim(header); - if (!header.empty()) - { - llwarns << "Unable to parse header: " << header << llendl; - } - } - - return header_len; -} - -void CurlResponderBuffer::setStatusAndReason(U32 status, std::string const& reason) -{ - mStatus = status; - mReason = reason; -} - -void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) -{ - llerrs << "Unexpected call to added_to_multi_handle()." << llendl; -} - -void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w) -{ - llerrs << "Unexpected call to finished()." << llendl; -} - -void CurlResponderBuffer::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) -{ - DoutCurlEasy("Calling CurlResponderBuffer::removed_from_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); - - // Lock self. - ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); - llassert(dynamic_cast(static_cast(ThreadSafeCurlEasyRequest::wrapper_cast(&*curl_easy_request_w))) == lockobj); - AICurlResponderBuffer_wat buffer_w(*lockobj); - llassert(&*buffer_w == this); - - processOutput(curl_easy_request_w); -} - -void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request_w) -{ - U32 responseCode = 0; - std::string responseReason; - - CURLcode code; - curl_easy_request_w->getResult(&code); - if (code == CURLE_OK) - { - curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode); - // If getResult code is CURLE_OK then we should have decoded the first header line ourselves. - llassert(responseCode == mStatus); - if (responseCode == mStatus) - responseReason = mReason; - else - responseReason = "Unknown reason."; - } - else - { - responseCode = 499; - responseReason = AICurlInterface::strerror(code); - curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); - } - - if (mResponder) - { - if (code == CURLE_OPERATION_TIMEDOUT) - { - curl_easy_request_w->timeout_print_diagnostics(mResponder->getHTTPTimeoutPolicy()); - } - if (mEventsTarget) - { - // Only the responder registers for these events. - llassert(mEventsTarget == mResponder.get()); - // Allow clients to parse headers before we attempt to parse - // the body and provide completed/result/error calls. - mEventsTarget->completed_headers(responseCode, responseReason); - } - mResponder->completedRaw(responseCode, responseReason, sChannels, mOutput); - mResponder = NULL; - } - - resetState(curl_easy_request_w); -} - -void CurlResponderBuffer::received_HTTP_header(void) -{ - if (mEventsTarget) - mEventsTarget->received_HTTP_header(); -} - -void CurlResponderBuffer::received_header(std::string const& key, std::string const& value) -{ - if (mEventsTarget) - mEventsTarget->received_header(key, value); -} - -void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason) -{ - if (mEventsTarget) - mEventsTarget->completed_headers(status, reason); -} - //----------------------------------------------------------------------------- // CurlMultiHandle diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index e19ae15e0..595127532 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -49,7 +49,7 @@ #undef CURLOPT_DNS_USE_GLOBAL_CACHE #define CURLOPT_DNS_USE_GLOBAL_CACHE do_not_use_CURLOPT_DNS_USE_GLOBAL_CACHE -#include "stdtypes.h" // U32 +#include "stdtypes.h" // U16, S32, U32, F64 #include "llatomic.h" // LLAtomicU32 #include "aithreadsafe.h" #include "aihttpheaders.h" @@ -59,6 +59,38 @@ class LLBufferArray; class LLChannelDescriptors; class AIHTTPTimeoutPolicy; +// Some pretty printing for curl easy handle related things: +// Print the lock object related to the current easy handle in every debug output. +#ifdef CWDEBUG +#include +#include +#define DoutCurl(x) do { \ + using namespace libcwd; \ + std::ostringstream marker; \ + marker << (void*)this->get_lockobj(); \ + libcw_do.push_marker(); \ + libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ + libcw_do.inc_indent(2); \ + Dout(dc::curl, x); \ + libcw_do.dec_indent(2); \ + libcw_do.pop_marker(); \ + } while(0) +#define DoutCurlEntering(x) do { \ + using namespace libcwd; \ + std::ostringstream marker; \ + marker << (void*)this->get_lockobj(); \ + libcw_do.push_marker(); \ + libcw_do.marker().assign(marker.str().data(), marker.str().size()); \ + libcw_do.inc_indent(2); \ + DoutEntering(dc::curl, x); \ + libcw_do.dec_indent(2); \ + libcw_do.pop_marker(); \ + } while(0) +#else // !CWDEBUG +#define DoutCurl(x) Dout(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') +#define DoutCurlEntering(x) DoutEntering(dc::curl, x << " [" << (void*)this->get_lockobj() << ']') +#endif // CWDEBUG + //----------------------------------------------------------------------------- // Exceptions. // diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index 15d606f79..dc244da42 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -33,323 +33,358 @@ #include #include "llatomic.h" +#include "llrefcount.h" class AIHTTPHeaders; class AIHTTPTimeoutPolicy; class AICurlEasyRequestStateMachine; namespace AICurlPrivate { - namespace curlthread { class MultiHandle; } - struct Stats { - static LLAtomicU32 easy_calls; - static LLAtomicU32 easy_errors; - static LLAtomicU32 easy_init_calls; - static LLAtomicU32 easy_init_errors; - static LLAtomicU32 easy_cleanup_calls; - static LLAtomicU32 multi_calls; - static LLAtomicU32 multi_errors; +class ThreadSafeCurlEasyRequest; - static void print(void); - }; +namespace curlthread { + +class MultiHandle; - void handle_multi_error(CURLMcode code); - inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; } +// A class that keeps track of timeout administration per connection. +class HTTPTimeout : public LLRefCount { + private: + AIHTTPTimeoutPolicy const* mPolicy; // A pointer to the used timeout policy. + std::vector mBuckets; // An array with the number of bytes transfered in each second. + U16 mBucket; // The bucket corresponding to mLastSecond. + bool mNothingReceivedYet; // Set when created, reset when the HTML reply header from the server is received. + bool mLowSpeedOn; // Set while uploading or downloading data. + bool mUploadFinished; // Used to keep track of whether upload_finished was called yet. + S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock. + U32 mTotalBytes; // The sum of all bytes in mBuckets. + U64 mLowSpeedClock; // Clock count at which low speed detection (re)started. + U64 mStalled; // The clock count at which this transaction is considered to be stalling if nothing is transfered anymore. + public: + static F64 const sClockWidth; // Time between two clock ticks in seconds. + static U64 sClockCount; // Clock count used as 'now' during one loop of the main loop. +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + ThreadSafeCurlEasyRequest* mLockObj; +#endif - bool curlThreadIsRunning(void); - void wakeUpCurlThread(void); - void stopCurlThread(void); + public: + HTTPTimeout(AIHTTPTimeoutPolicy const* policy, ThreadSafeCurlEasyRequest* lock_obj) : + mPolicy(policy), mNothingReceivedYet(true), mLowSpeedOn(false), mUploadFinished(false), mStalled((U64)-1) +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + , mLockObj(lock_obj) +#endif + { } - class ThreadSafeCurlEasyRequest; - class ThreadSafeBufferedCurlEasyRequest; + // Called after sending all headers, when body data is written the first time. + void connected(void); + + // Called when everything we had to send to the server has been sent. + void upload_finished(void); + + // Called when data is sent. Returns true if transfer timed out. + bool data_sent(size_t n); + + // Called when data is received. Returns true if transfer timed out. + bool data_received(size_t n); + + // Called immediately before done() after curl finished, with code. + void done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code); + + // Accessor. + bool has_stalled(void) const { return mStalled < sClockCount; } + + // Called from CurlResponderBuffer::processOutput if a timeout occurred. + void print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w); + +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + void* get_lockobj(void) const { return mLockObj; } +#endif + + private: + // (Re)start low speed transer rate detection. + void reset_lowspeed(void); + + // Common low speed detection, Called from data_sent or data_received. + bool lowspeed(size_t bytes); +}; + +} // namespace curlthread + +struct Stats { + static LLAtomicU32 easy_calls; + static LLAtomicU32 easy_errors; + static LLAtomicU32 easy_init_calls; + static LLAtomicU32 easy_init_errors; + static LLAtomicU32 easy_cleanup_calls; + static LLAtomicU32 multi_calls; + static LLAtomicU32 multi_errors; + + static void print(void); +}; + +void handle_multi_error(CURLMcode code); +inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; } + +bool curlThreadIsRunning(void); +void wakeUpCurlThread(void); +void stopCurlThread(void); + +class ThreadSafeCurlEasyRequest; +class ThreadSafeBufferedCurlEasyRequest; #define DECLARE_SETOPT(param_type) \ CURLcode setopt(CURLoption option, param_type parameter) - // This class wraps CURL*'s. - // It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl. - class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEvents { - public: - CurlEasyHandle(void); - ~CurlEasyHandle(); +// This class wraps CURL*'s. +// It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl. +class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEvents { + public: + CurlEasyHandle(void); + ~CurlEasyHandle(); - private: - // Disallow assignment. - CurlEasyHandle& operator=(CurlEasyHandle const*); + private: + // Disallow assignment. + CurlEasyHandle& operator=(CurlEasyHandle const*); - public: - // Reset all options of a libcurl session handle. - void reset(void) { llassert(!mActiveMultiHandle); curl_easy_reset(mEasyHandle); } + public: + // Reset all options of a libcurl session handle. + void reset(void) { llassert(!mActiveMultiHandle); curl_easy_reset(mEasyHandle); } - // Set options for a curl easy handle. - DECLARE_SETOPT(long); - DECLARE_SETOPT(long long); - DECLARE_SETOPT(void const*); - DECLARE_SETOPT(curl_debug_callback); - DECLARE_SETOPT(curl_write_callback); - //DECLARE_SETOPT(curl_read_callback); Same type as curl_write_callback - DECLARE_SETOPT(curl_ssl_ctx_callback); - DECLARE_SETOPT(curl_conv_callback); + // Set options for a curl easy handle. + DECLARE_SETOPT(long); + DECLARE_SETOPT(long long); + DECLARE_SETOPT(void const*); + DECLARE_SETOPT(curl_debug_callback); + DECLARE_SETOPT(curl_write_callback); + //DECLARE_SETOPT(curl_read_callback); Same type as curl_write_callback + DECLARE_SETOPT(curl_ssl_ctx_callback); + DECLARE_SETOPT(curl_conv_callback); #if 0 // Not used by the viewer. - DECLARE_SETOPT(curl_progress_callback); - DECLARE_SETOPT(curl_seek_callback); - DECLARE_SETOPT(curl_ioctl_callback); - DECLARE_SETOPT(curl_sockopt_callback); - DECLARE_SETOPT(curl_opensocket_callback); - DECLARE_SETOPT(curl_closesocket_callback); - DECLARE_SETOPT(curl_sshkeycallback); - DECLARE_SETOPT(curl_chunk_bgn_callback); - DECLARE_SETOPT(curl_chunk_end_callback); - DECLARE_SETOPT(curl_fnmatch_callback); + DECLARE_SETOPT(curl_progress_callback); + DECLARE_SETOPT(curl_seek_callback); + DECLARE_SETOPT(curl_ioctl_callback); + DECLARE_SETOPT(curl_sockopt_callback); + DECLARE_SETOPT(curl_opensocket_callback); + DECLARE_SETOPT(curl_closesocket_callback); + DECLARE_SETOPT(curl_sshkeycallback); + DECLARE_SETOPT(curl_chunk_bgn_callback); + DECLARE_SETOPT(curl_chunk_end_callback); + DECLARE_SETOPT(curl_fnmatch_callback); #endif - // Automatically cast int types to a long. Note that U32/S32 are int and - // that you can overload int and long even if they have the same size. - CURLcode setopt(CURLoption option, U32 parameter) { return setopt(option, (long)parameter); } - CURLcode setopt(CURLoption option, S32 parameter) { return setopt(option, (long)parameter); } + // Automatically cast int types to a long. Note that U32/S32 are int and + // that you can overload int and long even if they have the same size. + CURLcode setopt(CURLoption option, U32 parameter) { return setopt(option, (long)parameter); } + CURLcode setopt(CURLoption option, S32 parameter) { return setopt(option, (long)parameter); } - // Clone a libcurl session handle using all the options previously set. - //CurlEasyHandle(CurlEasyHandle const& orig); + // Clone a libcurl session handle using all the options previously set. + //CurlEasyHandle(CurlEasyHandle const& orig); - // URL encode/decode the given string. - char* escape(char* url, int length); - char* unescape(char* url, int inlength , int* outlength); + // URL encode/decode the given string. + char* escape(char* url, int length); + char* unescape(char* url, int inlength , int* outlength); - // Extract information from a curl handle. - private: - CURLcode getinfo_priv(CURLINFO info, void* data) const; - public: - // The rest are inlines to provide some type-safety. - CURLcode getinfo(CURLINFO info, char** data) const { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, curl_slist** data) const { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, double* data) const { return getinfo_priv(info, data); } - CURLcode getinfo(CURLINFO info, long* data) const { return getinfo_priv(info, data); } + // Extract information from a curl handle. + private: + CURLcode getinfo_priv(CURLINFO info, void* data) const; + public: + // The rest are inlines to provide some type-safety. + CURLcode getinfo(CURLINFO info, char** data) const { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, curl_slist** data) const { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, double* data) const { return getinfo_priv(info, data); } + CURLcode getinfo(CURLINFO info, long* data) const { return getinfo_priv(info, data); } #ifdef __LP64__ // sizeof(long) > sizeof(int) ? - // Overload for integer types that are too small (libcurl demands a long). - CURLcode getinfo(CURLINFO info, S32* data) const { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } - CURLcode getinfo(CURLINFO info, U32* data) const { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } + // Overload for integer types that are too small (libcurl demands a long). + CURLcode getinfo(CURLINFO info, S32* data) const { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } + CURLcode getinfo(CURLINFO info, U32* data) const { long ldata; CURLcode res = getinfo_priv(info, &ldata); *data = static_cast(ldata); return res; } #else // sizeof(long) == sizeof(int) - CURLcode getinfo(CURLINFO info, S32* data) const { return getinfo_priv(info, reinterpret_cast(data)); } - CURLcode getinfo(CURLINFO info, U32* data) const { return getinfo_priv(info, reinterpret_cast(data)); } + CURLcode getinfo(CURLINFO info, S32* data) const { return getinfo_priv(info, reinterpret_cast(data)); } + CURLcode getinfo(CURLINFO info, U32* data) const { return getinfo_priv(info, reinterpret_cast(data)); } #endif - // Perform a file transfer (blocking). - CURLcode perform(void); - // Pause and unpause a connection. - CURLcode pause(int bitmask); + // Perform a file transfer (blocking). + CURLcode perform(void); + // Pause and unpause a connection. + CURLcode pause(int bitmask); - // Called when a request is queued for removal. In that case a race between the actual removal - // and revoking of the callbacks is harmless (and happens for the raw non-statemachine version). - void remove_queued(void) { mQueuedForRemoval = true; } - // In case it's added after being removed. - void add_queued(void) { mQueuedForRemoval = false; } + // Called when a request is queued for removal. In that case a race between the actual removal + // and revoking of the callbacks is harmless (and happens for the raw non-statemachine version). + void remove_queued(void) { mQueuedForRemoval = true; } + // In case it's added after being removed. + void add_queued(void) { mQueuedForRemoval = false; } - private: - CURL* mEasyHandle; - CURLM* mActiveMultiHandle; - mutable char* mErrorBuffer; - AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists. - bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal. + private: + CURL* mEasyHandle; + CURLM* mActiveMultiHandle; + mutable char* mErrorBuffer; + AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists. + bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal. #ifdef SHOW_ASSERT - public: - bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread. + public: + bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread. #endif - private: - // This should only be called from MultiHandle; add/remove an easy handle to/from a multi handle. - friend class curlthread::MultiHandle; - CURLMcode add_handle_to_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); - CURLMcode remove_handle_from_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); + private: + // This should only be called from MultiHandle; add/remove an easy handle to/from a multi handle. + friend class curlthread::MultiHandle; + CURLMcode add_handle_to_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); + CURLMcode remove_handle_from_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle); - public: - // Returns true if this easy handle was added to a curl multi handle. - bool active(void) const { return mActiveMultiHandle; } + public: + // Returns true if this easy handle was added to a curl multi handle. + bool active(void) const { return mActiveMultiHandle; } - // Returns true when it is expected that the parent will revoke callbacks before the curl - // easy handle is removed from the multi handle; that usually happens when an external - // error demands termination of the request (ie, an expiration). - bool no_warning(void) const { return mQueuedForRemoval || LLApp::isExiting(); } + // Returns true when it is expected that the parent will revoke callbacks before the curl + // easy handle is removed from the multi handle; that usually happens when an external + // error demands termination of the request (ie, an expiration). + bool no_warning(void) const { return mQueuedForRemoval || LLApp::isExiting(); } - // Used for debugging purposes. - bool operator==(CURL* easy_handle) const { return mEasyHandle == easy_handle; } + // Used for debugging purposes. + bool operator==(CURL* easy_handle) const { return mEasyHandle == easy_handle; } - private: - // Call this prior to every curl_easy function whose return value is passed to check_easy_code. - void setErrorBuffer(void) const; + private: + // Call this prior to every curl_easy function whose return value is passed to check_easy_code. + void setErrorBuffer(void) const; - static void handle_easy_error(CURLcode code); + static void handle_easy_error(CURLcode code); - // Always first call setErrorBuffer()! - static inline CURLcode check_easy_code(CURLcode code) - { - Stats::easy_calls++; - if (code != CURLE_OK) - handle_easy_error(code); - return code; - } + // Always first call setErrorBuffer()! + static inline CURLcode check_easy_code(CURLcode code) + { + Stats::easy_calls++; + if (code != CURLE_OK) + handle_easy_error(code); + return code; + } - protected: - // Return the underlying curl easy handle. - CURL* getEasyHandle(void) const { return mEasyHandle; } + protected: + // Return the underlying curl easy handle. + CURL* getEasyHandle(void) const { return mEasyHandle; } - // Keep POSTFIELD data alive. - void setPostField(AIPostFieldPtr const& post_field_ptr) { mPostField = post_field_ptr; } + // Keep POSTFIELD data alive. + void setPostField(AIPostFieldPtr const& post_field_ptr) { mPostField = post_field_ptr; } - private: - // Return, and possibly create, the curl (easy) error buffer used by the current thread. - static char* getTLErrorBuffer(void); - }; + private: + // Return, and possibly create, the curl (easy) error buffer used by the current thread. + static char* getTLErrorBuffer(void); +}; - // CurlEasyRequest adds a slightly more powerful interface that can be used - // to set the options on a curl easy handle. - // - // Calling sendRequest() will then connect to the given URL and perform - // the data exchange. Use getResult() to determine if an error occurred. - // - // Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest: - // a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest, - // which is only created by creating a AICurlEasyRequest. When the last copy of such - // AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted - // and the CurlEasyRequest destructed. - class CurlEasyRequest : public CurlEasyHandle { - private: - void setPost_raw(U32 size, char const* data); - public: - void setPost(U32 size) { setPost_raw(size, NULL); } - void setPost(AIPostFieldPtr const& postdata, U32 size); - void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } - void setoptString(CURLoption option, std::string const& value); - void addHeader(char const* str); - void addHeaders(AIHTTPHeaders const& headers); +// CurlEasyRequest adds a slightly more powerful interface that can be used +// to set the options on a curl easy handle. +// +// Calling sendRequest() will then connect to the given URL and perform +// the data exchange. Use getResult() to determine if an error occurred. +// +// Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest: +// a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest, +// which is only created by creating a AICurlEasyRequest. When the last copy of such +// AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted +// and the CurlEasyRequest destructed. +class CurlEasyRequest : public CurlEasyHandle { + private: + void setPost_raw(U32 size, char const* data); + public: + void setPost(U32 size) { setPost_raw(size, NULL); } + void setPost(AIPostFieldPtr const& postdata, U32 size); + void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } + void setoptString(CURLoption option, std::string const& value); + void addHeader(char const* str); + void addHeaders(AIHTTPHeaders const& headers); - private: - // Callback stubs. - static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata); - static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata); - static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata); - static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata); + private: + // Callback stubs. + static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata); + static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata); + static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata); + static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata); - curl_write_callback mHeaderCallback; - void* mHeaderCallbackUserData; - curl_write_callback mWriteCallback; - void* mWriteCallbackUserData; - curl_read_callback mReadCallback; - void* mReadCallbackUserData; - curl_ssl_ctx_callback mSSLCtxCallback; - void* mSSLCtxCallbackUserData; + curl_write_callback mHeaderCallback; + void* mHeaderCallbackUserData; + curl_write_callback mWriteCallback; + void* mWriteCallbackUserData; + curl_read_callback mReadCallback; + void* mReadCallbackUserData; + curl_ssl_ctx_callback mSSLCtxCallback; + void* mSSLCtxCallbackUserData; - public: - void setHeaderCallback(curl_write_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); + public: + void setHeaderCallback(curl_write_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); - // Call this if the set callbacks are about to be invalidated. - void revokeCallbacks(void); + // Call this if the set callbacks are about to be invalidated. + void revokeCallbacks(void); - // Reset everything to the state it was in when this object was just created. - void resetState(void); + // Reset everything to the state it was in when this object was just created. + void resetState(void); - private: - // Called from applyDefaultOptions. - void applyProxySettings(void); + private: + // Called from applyDefaultOptions. + void applyProxySettings(void); - // Used in applyDefaultOptions. - static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); + // Used in applyDefaultOptions. + static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); - public: - // Set default options that we want applied to all curl easy handles. - void applyDefaultOptions(void); + public: + // Set default options that we want applied to all curl easy handles. + void applyDefaultOptions(void); - // Prepare the request for adding it to a multi session, or calling perform. - // This actually adds the headers that were collected with addHeader. - void finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine); + // Prepare the request for adding it to a multi session, or calling perform. + // This actually adds the headers that were collected with addHeader. + void finalizeRequest(std::string const& url, AIHTTPTimeoutPolicy const& policy, AICurlEasyRequestStateMachine* state_machine); - //------------------------------------------- - // Timeout administration events: + // Last second initialization. Called from MultiHandle::add_easy_request. + void set_timeout_opts(void); - // Called by MultiHandle::add_easy_request when the easy handle is actually being added to the multi handle. - void timeout_add_easy_request(void); + public: + // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. + void storeResult(CURLcode result) { mResult = result; } - // Called after sending all headers, when body data is written the first time. - void timeout_connected(void); + // Called by MultiHandle::check_run_count() when the curl easy handle is done. + void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } - // Called when everything we had to send to the server has been sent. - void timeout_upload_finished(void); + // Called by MultiHandle::check_run_count() to fill info with the transfer info. + void getTransferInfo(AICurlInterface::TransferInfo* info); - // Called when data is sent. Returns true if transfer timed out. - bool timeout_data_sent(size_t n); + // If result != CURLE_FAILED_INIT then also info was filled. + void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL); - // Called when data is received. Returns true if transfer timed out. - bool timeout_data_received(size_t n); + // For debugging purposes. + void print_curl_timings(void) const; - // Called immediately before done() after curl finished, with code. - void timeout_done(CURLcode code); + private: + curl_slist* mHeaders; + AICurlEasyHandleEvents* mEventsTarget; + CURLcode mResult; - // Accessor. - bool timeout_has_stalled(void) const { return mTimeoutStalled < sTimeoutClockCount; } - - // Called from CurlResponderBuffer::processOutput if a timeout occurred. - void timeout_print_diagnostics(AIHTTPTimeoutPolicy const& policy); - - private: - // (Re)start low speed transer rate detection. - void timeout_reset_lowspeed(void); - - // Common low speed detection, Called from timeout_data_sent or timeout_data_received. - bool timeout_lowspeed(size_t bytes); - - // End of timeout stuff - //------------------------------------------- - - public: - // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. - void storeResult(CURLcode result) { mResult = result; } - - // Called by MultiHandle::check_run_count() when the curl easy handle is done. - void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } - - // Called by MultiHandle::check_run_count() to fill info with the transfer info. - void getTransferInfo(AICurlInterface::TransferInfo* info); - - // If result != CURLE_FAILED_INIT then also info was filled. - void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL); - - private: - curl_slist* mHeaders; - bool mRequestFinalized; - AICurlEasyHandleEvents* mEventsTarget; - CURLcode mResult; - - // AIFIXME: put all timeout stuff in it's own class. - AIHTTPTimeoutPolicy const* mTimeoutPolicy; - std::string mTimeoutLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. - std::vector mTimeoutBuckets; // An array with the number of bytes transfered in each second. - U16 mTimeoutBucket; // The bucket corresponding to mTimeoutLastSecond. - bool mTimeoutNothingReceivedYet; // Set when connected, reset when the HTML reply header from the server is received. - bool mTimeoutLowSpeedOn; // Set while uploading or downloading data. - bool mTimeoutUploadFinished; // Only used for debugging. - S32 mTimeoutLastSecond; // The time at which timeout_lowspeed was last called, in seconds since mTimeoutLowSpeedClock. - U32 mTimeoutTotalBytes; // The sum of all bytes in mTimeoutBuckets. - U64 mTimeoutLowSpeedClock; // Clock count at which low speed transfer rate started. - U64 mTimeoutStalled; // The clock count at which this transaction is considered to be stalling. - public: - static F64 const sTimeoutClockWidth; // Time between two clock ticks in seconds. - static U64 sTimeoutClockCount; // Clock count used during one loop of the main loop. + AIHTTPTimeoutPolicy const* mTimeoutPolicy; + std::string mLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. + LLPointer mTimeout; #if defined(CWDEBUG) || defined(DEBUG_CURLIO) - bool mDebugIsGetMethod; + public: + bool mDebugIsGetMethod; #endif - private: - // This class may only be created by constructing a ThreadSafeCurlEasyRequest. - friend class ThreadSafeCurlEasyRequest; - // Throws AICurlNoEasyHandle. - CurlEasyRequest(void) : - mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), + public: + // These two are only valid after finalizeRequest. + AIHTTPTimeoutPolicy const* getTimeoutPolicy(void) const { return mTimeoutPolicy; } + std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; } + // Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request. + void set_timeout_object(LLPointer& timeout) { mTimeout = timeout; } + // And the accessor for it. + LLPointer& httptimeout(void) { return mTimeout; } + // Return true if no data has been received on the latest socket (if any) for too long. + bool has_stalled(void) const { return mTimeout && mTimeout->has_stalled(); } + + private: + // This class may only be created by constructing a ThreadSafeCurlEasyRequest. + friend class ThreadSafeCurlEasyRequest; + // Throws AICurlNoEasyHandle. + CurlEasyRequest(void) : mHeaders(NULL), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) - mDebugIsGetMethod(false), + , mDebugIsGetMethod(false) #endif - mTimeoutPolicy(NULL) - { applyDefaultOptions(); } + { applyDefaultOptions(); } public: ~CurlEasyRequest(); @@ -358,8 +393,7 @@ namespace AICurlPrivate { void send_events_to(AICurlEasyHandleEvents* target) { mEventsTarget = target; } // For debugging purposes - bool is_finalized(void) const { return mRequestFinalized; } - void timeout_timings(void); + bool is_finalized(void) const { return mTimeoutPolicy; } // Return pointer to the ThreadSafe (wrapped) version of this object. ThreadSafeCurlEasyRequest* get_lockobj(void); diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 28c66d6fc..9b27cd042 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -30,7 +30,10 @@ #include "linden_common.h" #include "aicurlthread.h" +#include "aihttptimeoutpolicy.h" #include "lltimer.h" // ms_sleep, get_clock_count +#include "llhttpstatuscodes.h" +#include "llbuffer.h" #include #if !LL_WINDOWS #include @@ -753,6 +756,7 @@ class CurlSocketInfo curl_socket_t mSocketFd; int mAction; AICurlEasyRequest mEasyRequest; + LLPointer mTimeout; }; CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeCurlEasyRequest* lockobj) : @@ -763,6 +767,14 @@ CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socke llassert(!mMultiHandle.mReadPollSet->contains(s)); llassert(!mMultiHandle.mWritePollSet->contains(s)); set_action(action); + // Create a new HTTPTimeout object and keep a pointer to it in the corresponding CurlEasyRequest object. + // The reason for this seemingly redundant storage (we could just store it directly in the CurlEasyRequest + // and not in CurlSocketInfo) is because in the case of a redirection there exist temporarily two + // CurlSocketInfo objects for a request and we need upload_finished() to be called on the HTTPTimeout + // object related to THIS CurlSocketInfo. + AICurlEasyRequest_wat easy_request_w(*lockobj); + mTimeout = new HTTPTimeout(easy_request_w->getTimeoutPolicy(), lockobj); + easy_request_w->set_timeout_object(mTimeout); } CurlSocketInfo::~CurlSocketInfo() @@ -798,7 +810,7 @@ void CurlSocketInfo::set_action(int action) if (pretransfer_time > 0) { // If CURL_POLL_OUT is removed and CURLINFO_PRETRANSFER_TIME is already set, then we have nothing more to send apparently. - curl_easy_request_w->timeout_upload_finished(); // Update timeout administration. + mTimeout->upload_finished(); // Update timeout administration. } } } @@ -1369,8 +1381,8 @@ void AICurlThread::run(void) continue; } // Clock count used for timeouts. - CurlEasyRequest::sTimeoutClockCount = get_clock_count(); - Dout(dc::curl, "CurlEasyRequest::sTimeoutClockCount = " << CurlEasyRequest::sTimeoutClockCount); + HTTPTimeout::sClockCount = get_clock_count(); + Dout(dc::curl, "HTTPTimeout::sClockCount = " << HTTPTimeout::sClockCount); if (ready == 0) { multi_handle_w->socket_action(CURL_SOCKET_TIMEOUT, 0); @@ -1437,7 +1449,7 @@ void MultiHandle::handle_stalls(void) { for(addedEasyRequests_type::iterator iter = mAddedEasyRequests.begin(); iter != mAddedEasyRequests.end();) { - if (AICurlEasyRequest_wat(**iter)->timeout_has_stalled()) + if (AICurlEasyRequest_wat(**iter)->has_stalled()) { Dout(dc::curl, "MultiHandle::handle_stalls(): Easy request stalled! [" << (void*)iter->get_ptr().get() << "]"); finish_easy_request(*iter, CURLE_OPERATION_TIMEDOUT); @@ -1526,7 +1538,7 @@ void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) CURLMcode ret; { AICurlEasyRequest_wat curl_easy_request_w(*easy_request); - curl_easy_request_w->timeout_add_easy_request(); + curl_easy_request_w->set_timeout_opts(); ret = curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle); } if (ret == CURLM_OK) @@ -1705,11 +1717,272 @@ void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CUR ". [CURLINFO_PRIVATE = " << (void*)easy_request.get_ptr().get() << "]"); #endif // Update timeout administration. - curl_easy_request_w->timeout_done(result); + curl_easy_request_w->httptimeout()->done(curl_easy_request_w, result); // Signal that this easy handle finished. curl_easy_request_w->done(curl_easy_request_w); } +//----------------------------------------------------------------------------- +// HTTPTimeout + +//static +F64 const HTTPTimeout::sClockWidth = 1.0 / calc_clock_frequency(); // Time between two clock ticks, in seconds. +U64 HTTPTimeout::sClockCount; // Clock count, set once per select() exit. + +// CURL-THREAD +// This is called when body data was sent to the server socket. +// <-----mLowSpeedOn------> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ ^ ^ ^ ^ +// | | | | | | +bool HTTPTimeout::data_sent(size_t n) +{ + // Generate events. + if (!mLowSpeedOn) + { + // If we can send data (for the first time) then that's our only way to know we connected. + reset_lowspeed(); + } + // Detect low speed. + return lowspeed(n); +} + +// CURL-THREAD +// This is called when the 'low speed' timer should be started. +// <-----mLowSpeedOn------> <-------mLowSpeedOn--------> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ +// | | +void HTTPTimeout::reset_lowspeed(void) +{ + mLowSpeedClock = sClockCount; + mLowSpeedOn = true; + mLastSecond = -1; // This causes lowspeed to initialize the rest. + mStalled = (U64)-1; // Stop reply delay timer. + DoutCurl("reset_lowspeed: mLowSpeedClock = " << mLowSpeedClock << "; mStalled = -1"); +} + +// CURL-THREAD +// This is called when everything we had to send to the server has been sent. +// <-----mLowSpeedOn------> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ +// | +void HTTPTimeout::upload_finished(void) +{ + llassert(!mUploadFinished); // If we get here twice, then the 'upload finished' detection failed. + mUploadFinished = true; + // We finished uploading (if there was a body to upload at all), so not more transfer rate timeouts. + mLowSpeedOn = false; + // Timeout if the server doesn't reply quick enough. + mStalled = sClockCount + mPolicy->getReplyDelay() / sClockWidth; + DoutCurl("upload_finished: mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (" << mPolicy->getReplyDelay() << " seconds)"); +} + +// CURL-THREAD +// This is called when data was received from the server. +// +// <--------------------------------mNothingReceivedYet------------------------------><-------mLowSpeedOn--------> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ ^ ^ ^ ^ ^ ^ +// | | | | | | | | +bool HTTPTimeout::data_received(size_t n) +{ + // The HTTP header of the reply is the first thing we receive. + if (mNothingReceivedYet && n > 0) + { + if (!mUploadFinished) + { + // mUploadFinished not being set this point should only happen for GET requests (in fact, then it is normal), + // because in that case it is impossible to detect the difference between connecting and waiting for a reply without + // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsGetMethod is only valid when the debug channel 'curlio' is on, + // because it is set in the debug callback function. + Debug(llassert(AICurlEasyRequest_wat(*mLockObj)->mDebugIsGetMethod || !dc::curlio.is_on())); + // 'Upload finished' detection failed, generate it now. + upload_finished(); + } + // Turn this flag off again now that we received data, so that if 'upload_finished()' is called again + // for a future upload on the same descriptor, then that won't trigger an assert. + // Note that because we also set mNothingReceivedYet here, we won't enter this code block anymore, + // so it's safe to do this. + mUploadFinished = false; + // Mark that something was received. + mNothingReceivedYet = false; + // We received something; switch to getLowSpeedLimit()/getLowSpeedTime(). + reset_lowspeed(); + } + return mLowSpeedOn ? lowspeed(n) : false; +} + +// CURL_THREAD +// bytes is the number of bytes we just sent or received (including headers). +// Returns true if the transfer should be aborted. +// +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ +// | | | | | | | | | | | | | | +bool HTTPTimeout::lowspeed(size_t bytes) +{ + DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")"); + + // The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works. + // + // libcurl determines the transfer rate since the last call to an equivalent 'lowspeed' function, and then + // triggers a timeout if CURLOPT_LOW_SPEED_TIME long such a transfer value is less than CURLOPT_LOW_SPEED_LIMIT. + // That doesn't work right because once there IS data it can happen that this function is called a few + // times (with less than a milisecond in between) causing seemingly VERY high "transfer rate" spikes. + // The only correct way to determine the transfer rate is to actually average over CURLOPT_LOW_SPEED_TIME + // seconds. + // + // We do this as follows: we create low_speed_time (in seconds) buckets and fill them with the number + // of bytes received during that second. We also keep track of the sum of all bytes received between 'now' + // and 'now - llmax(starttime, low_speed_time)'. Then if that period reaches at least low_speed_time + // seconds, and the transfer rate (sum / low_speed_time) is less than low_speed_limit, we abort. + + // When are we? + S32 second = (sClockCount - mLowSpeedClock) * sClockWidth; + llassert(sClockWidth > 0.0); + // This REALLY should never happen, but due to another bug it did happened + // and caused something so evil and hard to find that... NEVER AGAIN! + llassert(second >= 0); + + // If this is the same second as last time, just add the number of bytes to the current bucket. + if (second == mLastSecond) + { + mTotalBytes += bytes; + mBuckets[mBucket] += bytes; + return false; + } + + // We arrived at a new second. + // The below is at most executed once per second, even though for + // every currently connected transfer, CPU is not a big issue. + + // Determine the number of buckets needed and increase the number of buckets if needed. + U16 const low_speed_time = mPolicy->getLowSpeedTime(); + if (low_speed_time > mBuckets.size()) + { + mBuckets.resize(low_speed_time, 0); + } + + S32 s = mLastSecond; + mLastSecond = second; + + // If this is the first time this function is called, we need to do some initialization. + if (s == -1) + { + mBucket = 0; // It doesn't really matter where we start. + mTotalBytes = bytes; + mBuckets[mBucket] = bytes; + return false; + } + + // Update all administration. + U16 bucket = mBucket; + while(1) // Run over all the seconds that were skipped. + { + if (++bucket == low_speed_time) + bucket = 0; + if (++s == second) + break; + mTotalBytes -= mBuckets[bucket]; + mBuckets[bucket] = 0; + } + mBucket = bucket; + mTotalBytes -= mBuckets[mBucket]; + mTotalBytes += bytes; + mBuckets[mBucket] = bytes; + + // Check if we timed out. + U32 const low_speed_limit = mPolicy->getLowSpeedLimit(); + U32 mintotalbytes = low_speed_limit * low_speed_time; + DoutCurl("Transfered " << mTotalBytes << " bytes in " << llmin(second, (S32)low_speed_time) << " seconds after " << second << " second" << ((second == 1) ? "" : "s") << "."); + if (second >= low_speed_time) + { + DoutCurl("Average transfer rate is " << (mTotalBytes / low_speed_time) << " bytes/s (low speed limit is " << low_speed_limit << " bytes/s)"); + if (mTotalBytes < mintotalbytes) + { + // The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer. + llwarns << +#ifdef CWDEBUG + (void*)get_lockobj() << ": " +#endif + "aborting slow connection (average transfer rate below " << low_speed_limit << + " for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << ")." << llendl; + return true; + } + } + + // Calculate how long the data transfer may stall until we should timeout. + llassert_always(mintotalbytes > 0); + S32 max_stall_time = 0; + U32 dropped_bytes = 0; + while(1) + { + if (++bucket == low_speed_time) // The next second the next bucket will be emptied. + bucket = 0; + ++max_stall_time; + dropped_bytes += mBuckets[bucket]; + // Note how, when max_stall_time == low_speed_time, dropped_bytes has + // to be equal to mTotalBytes, the sum of all vector elements. + llassert_always(max_stall_time < low_speed_time || dropped_bytes == mTotalBytes); + // And thus the following will certainly abort. + if (second + max_stall_time >= low_speed_time && mTotalBytes - dropped_bytes < mintotalbytes) + break; + } + // If this function isn't called again within max_stall_time seconds, we stalled. + mStalled = sClockCount + max_stall_time / sClockWidth; + DoutCurl("mStalled set to sClockCount (" << sClockCount << ") + " << (mStalled - sClockCount) << " (" << max_stall_time << " seconds)"); + + return false; +} + +// CURL-THREAD +// This is called immediately before done() after curl finished, with code. +// <-------mLowSpeedOn--------> +// queued--><--DNS lookup + connect + send headers-->[<--send body (if any)-->]<--replydelay--><--receive headers + body--><--done +// ^ +// | +void HTTPTimeout::done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code) +{ + if (code == CURLE_OPERATION_TIMEDOUT || code == CURLE_COULDNT_RESOLVE_HOST) + { + bool dns_problem = false; + if (code == CURLE_COULDNT_RESOLVE_HOST) + { + // Note that CURLINFO_OS_ERRNO returns 0; we don't know any more than this. + llwarns << "Failed to resolve hostname " << curlEasyRequest_w->getLowercaseHostname() << llendl; + dns_problem = true; + } + else if (mNothingReceivedYet) + { + // Only consider this to possibly be related to a DNS lookup if we didn't + // resolved the host yet, which can be detected by asking for + // CURLINFO_NAMELOOKUP_TIME which is set when libcurl initiates the + // actual connect and thus knows the IP# (possibly from it's DNS cache). + double namelookup_time; + curlEasyRequest_w->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time); + dns_problem = (namelookup_time == 0); + } + if (dns_problem) + { + // Inform policy object that there might be problems with resolving this host. + // This will increase the connect timeout the next time we try to connect to this host. + AIHTTPTimeoutPolicy::connect_timed_out(curlEasyRequest_w->getLowercaseHostname()); + // AIFIXME: use return value to change priority + } + } + // Make sure no timeout will happen anymore. + mLowSpeedOn = false; + mStalled = (U64)-1; + DoutCurl("done: mStalled set to -1"); +} + +void HTTPTimeout::print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w) +{ + llwarns << "Request to " << curlEasyRequest_w->getLowercaseHostname() << " timed out for " << curlEasyRequest_w->getTimeoutPolicy()->name() << llendl; +} + } // namespace curlthread } // namespace AICurlPrivate @@ -1770,6 +2043,336 @@ void stopCurlThread(void) } } +//----------------------------------------------------------------------------- +// CurlResponderBuffer + +void CurlResponderBuffer::setStatusAndReason(U32 status, std::string const& reason) +{ + mStatus = status; + mReason = reason; +} + +void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) +{ + llerrs << "Unexpected call to added_to_multi_handle()." << llendl; +} + +void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w) +{ + llerrs << "Unexpected call to finished()." << llendl; +} + +void CurlResponderBuffer::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) +{ + DoutCurl("Calling CurlResponderBuffer::removed_from_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); + + // Lock self. + ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); + llassert(dynamic_cast(static_cast(ThreadSafeCurlEasyRequest::wrapper_cast(&*curl_easy_request_w))) == lockobj); + AICurlResponderBuffer_wat buffer_w(*lockobj); + llassert(&*buffer_w == this); + + processOutput(curl_easy_request_w); +} + +void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request_w) +{ + U32 responseCode = 0; + std::string responseReason; + + CURLcode code; + curl_easy_request_w->getResult(&code); + if (code == CURLE_OK) + { + curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode); + // If getResult code is CURLE_OK then we should have decoded the first header line ourselves. + llassert(responseCode == mStatus); + if (responseCode == mStatus) + responseReason = mReason; + else + responseReason = "Unknown reason."; + } + else + { + responseCode = 499; + responseReason = AICurlInterface::strerror(code); + curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); + } + + if (mResponder) + { + if (code == CURLE_OPERATION_TIMEDOUT) + { + curl_easy_request_w->httptimeout()->print_diagnostics(curl_easy_request_w); + } + if (mEventsTarget) + { + // Only the responder registers for these events. + llassert(mEventsTarget == mResponder.get()); + // Allow clients to parse headers before we attempt to parse + // the body and provide completed/result/error calls. + mEventsTarget->completed_headers(responseCode, responseReason); + } + mResponder->completedRaw(responseCode, responseReason, sChannels, mOutput); + mResponder = NULL; + } + + resetState(curl_easy_request_w); +} + +void CurlResponderBuffer::received_HTTP_header(void) +{ + if (mEventsTarget) + mEventsTarget->received_HTTP_header(); +} + +void CurlResponderBuffer::received_header(std::string const& key, std::string const& value) +{ + if (mEventsTarget) + mEventsTarget->received_header(key, value); +} + +void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason) +{ + if (mEventsTarget) + mEventsTarget->completed_headers(status, reason); +} + +//static +size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data) +{ + ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); + + // We need to lock the curl easy request object too, because that lock is used + // to make sure that callbacks and destruction aren't done simultaneously. + AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + + S32 bytes = size * nmemb; // The amount to write. + AICurlResponderBuffer_wat buffer_w(*lockobj); + // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. + //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; + buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); + buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. + if (buffered_easy_request_w->httptimeout()->data_received(bytes)) // Update timeout administration. + { + // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. + return 0; + } + return bytes; +} + +//static +size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) +{ + ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); + + // We need to lock the curl easy request object too, because that lock is used + // to make sure that callbacks and destruction aren't done simultaneously. + AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + + S32 bytes = size * nmemb; // The maximum amount to read. + AICurlResponderBuffer_wat buffer_w(*lockobj); + buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); + buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + if (buffered_easy_request_w->httptimeout()->data_sent(bytes)) // Timeout administration. + { + // Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK. + return CURL_READFUNC_ABORT; + } + return bytes; // Return the amount actually read (might be lowered by readAfter()). +} + +//static +size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data) +{ + ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); + + // We need to lock the curl easy request object, because that lock is used + // to make sure that callbacks and destruction aren't done simultaneously. + AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + + // This used to be headerCallback() in llurlrequest.cpp. + + char const* const header_line = static_cast(data); + size_t const header_len = size * nmemb; + if (buffered_easy_request_w->httptimeout()->data_received(header_len)) // Update timeout administration. + { + // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. + return 0; + } + if (!header_len) + { + return header_len; + } + std::string header(header_line, header_len); + if (!LLStringUtil::_isASCII(header)) + { + return header_len; + } + + // Per HTTP spec the first header line must be the status line. + if (header.substr(0, 5) == "HTTP/") + { + std::string::iterator const begin = header.begin(); + std::string::iterator const end = header.end(); + std::string::iterator pos1 = std::find(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'); + U32 status; + std::string reason; + if (pos3 != end && std::isdigit(*pos1)) + { + status = atoi(&header_line[pos1 - begin]); + reason.assign(pos2, pos3); + } + else + { + status = HTTP_INTERNAL_ERROR; + reason = "Header parse error."; + llwarns << "Received broken header line from server: \"" << header << "\"" << llendl; + } + { + AICurlResponderBuffer_wat curl_responder_buffer_w(*lockobj); + curl_responder_buffer_w->received_HTTP_header(); + curl_responder_buffer_w->setStatusAndReason(status, 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); + + AICurlResponderBuffer_wat(*lockobj)->received_header(key, value); + } + else + { + LLStringUtil::trim(header); + if (!header.empty()) + { + llwarns << "Unable to parse header: " << header << llendl; + } + } + + return header_len; +} + +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr) +{ +#ifdef CWDEBUG + using namespace ::libcwd; + + CurlEasyRequest* request = (CurlEasyRequest*)user_ptr; + std::ostringstream marker; + marker << (void*)request->get_lockobj(); + libcw_do.push_marker(); + libcw_do.marker().assign(marker.str().data(), marker.str().size()); + if (!debug::channels::dc::curlio.is_on()) + debug::channels::dc::curlio.on(); + LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio|cond_nonewline_cf(infotype == CURLINFO_TEXT)) +#else + if (infotype == CURLINFO_TEXT) + { + while (size > 0 && (buf[size - 1] == '\r' || buf[size - 1] == '\n')) + --size; + } + LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio) +#endif + switch (infotype) + { + case CURLINFO_TEXT: + LibcwDoutStream << "* "; + break; + case CURLINFO_HEADER_IN: + LibcwDoutStream << "H> "; + break; + case CURLINFO_HEADER_OUT: + LibcwDoutStream << "H< "; + if (size >= 4 && strncmp(buf, "GET ", 4) == 0) + request->mDebugIsGetMethod = true; + break; + case CURLINFO_DATA_IN: + LibcwDoutStream << "D> "; + break; + case CURLINFO_DATA_OUT: + LibcwDoutStream << "D< "; + break; + case CURLINFO_SSL_DATA_IN: + LibcwDoutStream << "S> "; + break; + case CURLINFO_SSL_DATA_OUT: + LibcwDoutStream << "S< "; + break; + default: + LibcwDoutStream << "?? "; + } + if (infotype == CURLINFO_TEXT) + LibcwDoutStream.write(buf, size); + else if (infotype == CURLINFO_HEADER_IN || infotype == CURLINFO_HEADER_OUT) + LibcwDoutStream << libcwd::buf2str(buf, size); + else if (infotype == CURLINFO_DATA_IN) + { + LibcwDoutStream << size << " bytes"; + bool finished = false; + size_t i = 0; + while (i < size) + { + char c = buf[i]; + if (!('0' <= c && c <= '9') && !('a' <= c && c <= 'f')) + { + if (0 < i && i + 1 < size && buf[i] == '\r' && buf[i + 1] == '\n') + { + // Binary output: "[0-9a-f]*\r\n ...binary data..." + LibcwDoutStream << ": \"" << libcwd::buf2str(buf, i + 2) << "\"..."; + finished = true; + } + break; + } + ++i; + } + if (!finished && size > 9 && buf[0] == '<') + { + // Human readable output: html, xml or llsd. + if (!strncmp(buf, "", 6)) + { + LibcwDoutStream << ": \"" << libcwd::buf2str(buf, size) << '"'; + finished = true; + } + } + if (!finished) + { + // Unknown format. Only print the first and last 20 characters. + if (size > 40UL) + { + LibcwDoutStream << ": \"" << libcwd::buf2str(buf, 20) << "\"...\"" << libcwd::buf2str(&buf[size - 20], 20) << '"'; + } + else + { + LibcwDoutStream << ": \"" << libcwd::buf2str(buf, size) << '"'; + } + } + } + else if (infotype == CURLINFO_DATA_OUT) + LibcwDoutStream << size << " bytes: \"" << libcwd::buf2str(buf, size) << '"'; + else + LibcwDoutStream << size << " bytes"; + LibcwDoutScopeEnd; +#ifdef CWDEBUG + libcw_do.pop_marker(); +#endif + return 0; +} +#endif // defined(CWDEBUG) || defined(DEBUG_CURLIO) + } // namespace AICurlPrivate //----------------------------------------------------------------------------- From 02cffa9a7141175d6788feb3dff939603b23cbe7 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 15 Oct 2012 21:01:16 +0200 Subject: [PATCH 36/64] Replace TimeOut with Timeout everywhere. --- indra/aistatemachine/aicurlthread.cpp | 20 ++-- indra/aistatemachine/aicurlthread.h | 4 +- indra/llmessage/llcurl.cpp | 153 -------------------------- indra/newview/llxmlrpctransaction.cpp | 4 +- 4 files changed, 14 insertions(+), 167 deletions(-) delete mode 100644 indra/llmessage/llcurl.cpp diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 9b27cd042..bb0e4458d 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -850,7 +850,7 @@ class AICurlThread : public LLThread curl_socket_t mWakeUpFd_in; curl_socket_t mWakeUpFd; - int mZeroTimeOut; + int mZeroTimeout; volatile bool mRunning; }; @@ -862,7 +862,7 @@ AICurlThread* AICurlThread::sInstance = NULL; AICurlThread::AICurlThread(void) : LLThread("AICurlThread"), mWakeUpFd_in(CURL_SOCKET_BAD), mWakeUpFd(CURL_SOCKET_BAD), - mZeroTimeOut(0), mRunning(true), mWakeUpFlag(false) + mZeroTimeout(0), mRunning(true), mWakeUpFlag(false) { create_wakeup_fds(); sInstance = this; @@ -1304,27 +1304,27 @@ void AICurlThread::run(void) // We're now entering select(), during which the main thread will write to the pipe/socket // to wake us up, because it can't get the lock. struct timeval timeout; - long timeout_ms = multi_handle_w->getTimeOut(); + long timeout_ms = multi_handle_w->getTimeout(); // If no timeout is set, sleep 1 second. if (LL_UNLIKELY(timeout_ms < 0)) timeout_ms = 1000; if (LL_UNLIKELY(timeout_ms == 0)) { - if (mZeroTimeOut >= 10000) + if (mZeroTimeout >= 10000) { - if (mZeroTimeOut == 10000) + if (mZeroTimeout == 10000) llwarns << "Detected more than 10000 zero-timeout calls of select() by curl thread (more than 101 seconds)!" << llendl; } - else if (mZeroTimeOut >= 1000) + else if (mZeroTimeout >= 1000) timeout_ms = 10; - else if (mZeroTimeOut >= 100) + else if (mZeroTimeout >= 100) timeout_ms = 1; } else { - if (LL_UNLIKELY(mZeroTimeOut >= 10000)) + if (LL_UNLIKELY(mZeroTimeout >= 10000)) llinfos << "Timeout of select() call by curl thread reset (to " << timeout_ms << " ms)." << llendl; - mZeroTimeOut = 0; + mZeroTimeout = 0; } timeout.tv_sec = timeout_ms / 1000; timeout.tv_usec = (timeout_ms % 1000) * 1000; @@ -1497,7 +1497,7 @@ int MultiHandle::timer_callback(CURLM* multi, long timeout_ms, void* userp) { MultiHandle& self = *static_cast(userp); llassert(multi == self.mMultiHandle); - self.mTimeOut = timeout_ms; + self.mTimeout = timeout_ms; Dout(dc::curl, "MultiHandle::timer_callback(): timeout set to " << timeout_ms << " ms."); return 0; } diff --git a/indra/aistatemachine/aicurlthread.h b/indra/aistatemachine/aicurlthread.h index b8800440f..70657e443 100644 --- a/indra/aistatemachine/aicurlthread.h +++ b/indra/aistatemachine/aicurlthread.h @@ -79,7 +79,7 @@ class MultiHandle : public CurlMultiHandle bool mHandleAddedOrRemoved; // Set when an easy handle was added or removed, reset in check_run_count(). int mPrevRunningHandles; // The last value of mRunningHandles that check_run_count() was called with. int mRunningHandles; // The last value returned by curl_multi_socket_action. - long mTimeOut; // The last time out in ms as set by the callback CURLMOPT_TIMERFUNCTION. + long mTimeout; // The last timeout in ms as set by the callback CURLMOPT_TIMERFUNCTION. private: // Store result and trigger events for easy request. @@ -96,7 +96,7 @@ class MultiHandle : public CurlMultiHandle int getRunningHandles(void) const { return mRunningHandles; } // Returns how long to wait for socket action before calling socket_action(CURL_SOCKET_TIMEOUT, 0), in ms. - int getTimeOut(void) const { return mTimeOut; } + int getTimeout(void) const { return mTimeout; } // This is called before sleeping, after calling (one or more times) socket_action. void check_run_count(void); diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp deleted file mode 100644 index 9db6170c9..000000000 --- a/indra/llmessage/llcurl.cpp +++ /dev/null @@ -1,153 +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, 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$ - */ - -////////////////////////////////////////////////////////////////////////////// -/* - 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 MAX_ACTIVE_REQUEST_COUNT = 100; - -//static -F32 LLCurl::sCurlRequestTimeOut = 120.f; //seconds -S32 LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined). - -////////////////////////////////////////////////////////////////////////////// - -AIThreadSafeSimpleDC LLCurl::Easy::sHandles; - -//static -CURL* LLCurl::Easy::allocEasyHandle() -{ - llassert(*AIAccess(LLCurl::getCurlThread())) ; - - CURL* ret = NULL; - - //*** Multi-threaded. - AIAccess handles_w(sHandles); - - if (handles_w->free.empty()) - { - ret = LLCurl::newEasyHandle(); - } - else - { - ret = *(handles_w->free.begin()); - handles_w->free.erase(ret); - } - - if (ret) - { - handles_w->active.insert(ret); - } - - return ret; -} - -//static -void LLCurl::Easy::releaseEasyHandle(CURL* handle) -{ - DoutEntering(dc::curl, "LLCurl::Easy::releaseEasyHandle(" << (void*)handle << ")"); - BACKTRACE; - - static const S32 MAX_NUM_FREE_HANDLES = 32 ; - - if (!handle) - { - return ; //handle allocation failed. - //llerrs << "handle cannot be NULL!" << llendl; - } - - //*** Multi-Threaded (logout only?) - AIAccess handles_w(sHandles); - - if (handles_w->active.find(handle) != handles_w->active.end()) - { - handles_w->active.erase(handle); - - if (handles_w->free.size() < MAX_NUM_FREE_HANDLES) - { - curl_easy_reset(handle); - handles_w->free.insert(handle); - } - else - { - LLCurl::deleteEasyHandle(handle) ; - } - } - else - { - llerrs << "Invalid handle." << llendl; - } -} - -LLCurl::Easy::~Easy() -{ - AISTAccess responder_w(mResponder); - if (*responder_w && LLCurl::getNotQuitting()) //aborted - { - std::string reason("Request timeout, aborted.") ; - (*responder_w)->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort - reason, mChannels, mOutput); - } - *responder_w = NULL; -} - -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; -} diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index e96dc1f2f..fe8b88d73 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -326,11 +326,11 @@ void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success) if (LLApp::isRunning()) { std::ostringstream msg; - F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeOut"); + F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeout"); msg << "Connection to " << mURI << " timed out (" << timeout_value << " s)!"; if (timeout_value < 40) { - msg << "\nTry increasing CurlRequestTimeOut in Debug Settings."; + msg << "\nTry increasing CurlRequestTimeout in Debug Settings."; } setStatus(LLXMLRPCTransaction::StatusOtherError, msg.str()); } From bb8ea493d64a2a4ae9e7deffa0a545823118d906 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 15 Oct 2012 21:03:08 +0200 Subject: [PATCH 37/64] Fix top check in MultiHandle::check_run_count. This check isn't really needed at all, since curl_multi_info_read is fast enough, but well... The old check was flawed anyway. --- indra/aistatemachine/aicurlthread.cpp | 9 +++------ indra/aistatemachine/aicurlthread.h | 7 ++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index bb0e4458d..a973e4260 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1420,7 +1420,7 @@ void AICurlThread::run(void) //----------------------------------------------------------------------------- // MultiHandle -MultiHandle::MultiHandle(void) : mHandleAddedOrRemoved(false), mPrevRunningHandles(0), mRunningHandles(0), mTimeOut(-1), mReadPollSet(NULL), mWritePollSet(NULL) +MultiHandle::MultiHandle(void) : mRunningHandles(0), mTimeout(-1), mReadPollSet(NULL), mWritePollSet(NULL) { mReadPollSet = new PollSet; mWritePollSet = new PollSet; @@ -1543,7 +1543,6 @@ void MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request) } if (ret == CURLM_OK) { - mHandleAddedOrRemoved = true; std::pair res = mAddedEasyRequests.insert(easy_request); llassert(res.second); // May not have been added before. Dout(dc::curl, "MultiHandle::add_easy_request: Added AICurlEasyRequest " << (void*)easy_request.get_ptr().get() << "; now processing " << mAddedEasyRequests.size() << " easy handles."); @@ -1603,7 +1602,6 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons ThreadSafeCurlEasyRequest* lockobj = iter->get_ptr().get(); #endif mAddedEasyRequests.erase(iter); - mHandleAddedOrRemoved = true; Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles."); // Attempt to add a queued request, if any. @@ -1618,7 +1616,8 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons void MultiHandle::check_run_count(void) { - if (mHandleAddedOrRemoved || mRunningHandles < mPrevRunningHandles) + llassert(mAddedEasyRequests.size() >= mRunningHandles); + if (mAddedEasyRequests.size() - mRunningHandles > 0) // There is no need to do this when all easy handles are accounted for. { CURLMsg const* msg; int msgs_left; @@ -1652,9 +1651,7 @@ void MultiHandle::check_run_count(void) // Destruction of easy_request at this point, causes the CurlEasyRequest to be deleted. } } - mHandleAddedOrRemoved = false; } - mPrevRunningHandles = mRunningHandles; } void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result) diff --git a/indra/aistatemachine/aicurlthread.h b/indra/aistatemachine/aicurlthread.h index 70657e443..1ca677990 100644 --- a/indra/aistatemachine/aicurlthread.h +++ b/indra/aistatemachine/aicurlthread.h @@ -74,11 +74,8 @@ class MultiHandle : public CurlMultiHandle private: typedef std::set addedEasyRequests_type; - addedEasyRequests_type mAddedEasyRequests; - - bool mHandleAddedOrRemoved; // Set when an easy handle was added or removed, reset in check_run_count(). - int mPrevRunningHandles; // The last value of mRunningHandles that check_run_count() was called with. - int mRunningHandles; // The last value returned by curl_multi_socket_action. + addedEasyRequests_type mAddedEasyRequests; // All easy requests currently added to the multi handle. + int mRunningHandles; // The last value returned by curl_multi_socket_action. long mTimeout; // The last timeout in ms as set by the callback CURLMOPT_TIMERFUNCTION. private: From 8ba127d4c5d141218ff35c223a75fbe036615dcd Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 15 Oct 2012 21:07:17 +0200 Subject: [PATCH 38/64] HTTPTimeout work in progress * Avoid using CurlEasyRequest::mTimeout for HTTPTime::done and HTTPTime::print_diagnostics when it might be NULL. * Comment fixes. * Indentation fix. --- indra/aistatemachine/aicurl.cpp | 13 +++++++++++++ indra/aistatemachine/aicurlprivate.h | 17 ++++++++++++++--- indra/aistatemachine/aicurlthread.cpp | 11 +++++------ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index f4d65c49e..40d417007 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1260,6 +1260,19 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy mEventsTarget->removed_from_multi_handle(curl_easy_request_w); } +void CurlEasyRequest::print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code) +{ + if (code == CURLE_OPERATION_TIMEDOUT) + { + // mTimeout SHOULD always be set, but I see no reason not to test it, as + // this is far from the code that guaranteeds that it is set. + if (mTimeout) + { + mTimeout->print_diagnostics(curlEasyRequest_w); + } + } +} + //----------------------------------------------------------------------------- // CurlResponderBuffer diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index dc244da42..b4741eca0 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -337,11 +337,22 @@ class CurlEasyRequest : public CurlEasyHandle { void set_timeout_opts(void); public: - // Called by MultiHandle::check_run_count() to store result code that is returned by getResult. + // Called by MultiHandle::finish_easy_request() to store result code that is returned by getResult. void storeResult(CURLcode result) { mResult = result; } - // Called by MultiHandle::check_run_count() when the curl easy handle is done. - void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); } + // Called by MultiHandle::finish_easy_request() when the curl easy handle is done. + void done(AICurlEasyRequest_wat& curl_easy_request_w, CURLcode result) + { + if (mTimeout) + { + // Update timeout administration. + mTimeout->done(curl_easy_request_w, result); + } + finished(curl_easy_request_w); + } + + // Called by in case of an error. + void print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code); // Called by MultiHandle::check_run_count() to fill info with the transfer info. void getTransferInfo(AICurlInterface::TransferInfo* info); diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index a973e4260..22925613c 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1713,10 +1713,8 @@ void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CUR Dout(dc::finish, "pretransfer_time: " << pretransfer_time << ", starttransfer_time: " << starttransfer_time << ". [CURLINFO_PRIVATE = " << (void*)easy_request.get_ptr().get() << "]"); #endif - // Update timeout administration. - curl_easy_request_w->httptimeout()->done(curl_easy_request_w, result); // Signal that this easy handle finished. - curl_easy_request_w->done(curl_easy_request_w); + curl_easy_request_w->done(curl_easy_request_w, result); } //----------------------------------------------------------------------------- @@ -2096,13 +2094,14 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); } + llassert(mResponder); // AIFIXME: We always have a responder now, no? if (mResponder) { - if (code == CURLE_OPERATION_TIMEDOUT) + if (code != CURLE_OK) { - curl_easy_request_w->httptimeout()->print_diagnostics(curl_easy_request_w); + curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); } - if (mEventsTarget) + if (mEventsTarget) { // Only the responder registers for these events. llassert(mEventsTarget == mResponder.get()); From 605843b5270c9c79562621c0b39ac0c223c9605c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 20 Oct 2012 21:47:31 +0200 Subject: [PATCH 39/64] HTTP status of 400 is an error too. --- indra/newview/llmeshrepository.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index dfdd3e4ec..cc2b7306f 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1811,7 +1811,7 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status > 400) + if (status < 200 || status >= 400) { llwarns << status << ": " << reason << llendl; } @@ -1865,7 +1865,7 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason { S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status > 400) + if (status < 200 || status >= 400) { llwarns << status << ": " << reason << llendl; } @@ -1919,7 +1919,7 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r { S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status > 400) + if (status < 200 || status >= 400) { llwarns << status << ": " << reason << llendl; } @@ -1973,7 +1973,7 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re { S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status > 400) + if (status < 200 || status >= 400) { llwarns << status << ": " << reason << llendl; } @@ -2025,7 +2025,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - if (status < 200 || status > 400) + if (status < 200 || status >= 400) { //llwarns // << "Header responder failed with status: " From f8273e977edd1f862d9b3fcaae41a61a6f4ef1d1 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 20 Oct 2012 23:28:33 +0200 Subject: [PATCH 40/64] Make NoVerifySSLCert work for all LLURLRequest Moved CURLOPT_ENCODING from CurlEasyRequest::setPost_raw, and CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST from CurlResponderBuffer::prepRequest, to LLURLRequest::configure, enabling the debug setting NoVerifySSLCert for the latter two to work as follows: old behavior if "NoVerifySSLCert" is not set, and check neither if it is set. However, if the (new) bool mIsAuth is set the behavior of LLXMLRPCTransaction::Impl::init is used. This is so in a next commit we can replace LLXMLRPCTransaction with LLURLRequest: LLXMLRPCTransaction::Impl::init will be removed. For the same reason, when the new boolean mNoCompression is set then CURLOPT_ENCODING is set to "identity", otherwise the old behavior (of clearing it) is used. --- indra/aistatemachine/aicurl.cpp | 13 ++++++------- indra/aistatemachine/aicurl.h | 4 +++- indra/aistatemachine/aicurlthread.cpp | 3 ++- indra/llmessage/llhttpclient.cpp | 6 ++++-- indra/llmessage/llurlrequest.cpp | 15 ++++++++++++--- indra/llmessage/llurlrequest.h | 4 +++- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llappviewer.cpp | 2 +- 8 files changed, 32 insertions(+), 17 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 40d417007..128110080 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -59,6 +59,12 @@ #include "aihttptimeoutpolicy.h" #include "aicurleasyrequeststatemachine.h" +//================================================================================== +// Debug Settings +// + +bool gNoVerifySSLCert; + //================================================================================== // Local variables. // @@ -828,9 +834,6 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data) DoutCurl("POST size is " << size << " bytes."); } - // Accept everything (send an Accept-Encoding header containing all encodings we support (zlib and gzip)). - setoptString(CURLOPT_ENCODING, ""); // CURLOPT_ACCEPT_ENCODING - // The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default. addHeader("Expect:"); if (size > 0) @@ -1367,10 +1370,6 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); } - curl_easy_request_w->setopt(CURLOPT_SSL_VERIFYPEER, 1); - // Don't verify host name so urls with scrubbed host names will work (improves DNS performance). - curl_easy_request_w->setopt(CURLOPT_SSL_VERIFYHOST, 0); - // Keep responder alive. mResponder = responder; // Send header events to responder if needed. diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 595127532..e1a999c9c 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -54,6 +54,8 @@ #include "aithreadsafe.h" #include "aihttpheaders.h" +extern bool gNoVerifySSLCert; + class LLSD; class LLBufferArray; class LLChannelDescriptors; @@ -147,7 +149,7 @@ struct TransferInfo { void initCurl(void (*)(void) = NULL); // Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread. -void startCurlThread(U32 CurlConcurrentConnections); +void startCurlThread(U32 CurlConcurrentConnections, bool NoVerifySSLCert); // Called once at end of application (from newview/llappviewer.cpp by main thread), // with purpose to stop curl threads, free curl resources and deinitialize curl. diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 22925613c..a70f8e820 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -2482,12 +2482,13 @@ void AICurlEasyRequest::removeRequest(void) namespace AICurlInterface { -void startCurlThread(U32 CurlConcurrentConnections) +void startCurlThread(U32 CurlConcurrentConnections, bool NoVerifySSLCert) { using namespace AICurlPrivate::curlthread; llassert(is_main_thread()); curl_concurrent_connections = CurlConcurrentConnections; // Debug Setting. + gNoVerifySSLCert = NoVerifySSLCert; // Debug Setting. AICurlThread::sInstance = new AICurlThread; AICurlThread::sInstance->start(); } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 5ec98b5e3..e7becc520 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -149,7 +149,9 @@ static void request( LLURLRequest::ERequestAction method, Injector* body_injector, LLCurl::ResponderPtr responder, - AIHTTPHeaders& headers) + AIHTTPHeaders& headers, + bool is_auth = false, + bool no_compression = false) { if (responder) { @@ -160,7 +162,7 @@ static void request( LLURLRequest* req; try { - req = new LLURLRequest(method, url, body_injector, responder, headers); + req = new LLURLRequest(method, url, body_injector, responder, headers, is_auth, no_compression); } catch(AICurlNoEasyHandle& error) { diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 1ea9c02ad..17c393b02 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -113,8 +113,10 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) } // This might throw AICurlNoEasyHandle. -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers) : - AICurlEasyRequestStateMachine(true), mAction(action), mURL(url), mBody(body), mResponder(responder), mHeaders(headers) +LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, + AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) : + AICurlEasyRequestStateMachine(true), mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression), + mBody(body), mResponder(responder), mHeaders(headers) { } @@ -507,7 +509,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1); // Set Accept-Encoding to allow response compression - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, ""); + curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); rv = true; break; @@ -525,6 +527,9 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) { // Set the handle for an http post curlEasyRequest_w->setPost(mBodySize); + + // Set Accept-Encoding to allow response compression + curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); rv = true; break; } @@ -546,6 +551,10 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) } if(rv) { + curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, gNoVerifySSLCert ? 0L : 1L); + // Don't verify host name if this is not an authentication request, + // so urls with scrubbed host names will work (improves DNS performance). + curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, (gNoVerifySSLCert || !mIsAuth) ? 0L : 2L); curlEasyRequest_w->finalizeRequest(mURL, mResponder->getHTTPTimeoutPolicy(), this); } } diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 1c078b907..5ae4d64aa 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -75,7 +75,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { * @param action One of the ERequestAction enumerations. * @param url The url of the request. It should already be encoded. */ - LLURLRequest(ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers); + LLURLRequest(ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression); /** * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE. @@ -109,6 +109,8 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { private: ERequestAction mAction; std::string mURL; + bool mIsAuth; // Set for authentication messages (login, buy land, buy currency). + bool mNoCompression; // Set to disable using gzip. Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT. U32 mBodySize; AICurlInterface::ResponderPtr mResponder; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2b7064536..ef6ad1679 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9059,7 +9059,7 @@ NoVerifySSLCert Comment - Do not verify SSL peers. + Do not verify SSL peers (requires restart) Persist 1 Type diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 99f900d3e..b2c82a738 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1835,7 +1835,7 @@ bool LLAppViewer::initThreads() LLWatchdog::getInstance()->init(watchdog_killer_callback); } - AICurlInterface::startCurlThread(gSavedSettings.getU32("CurlConcurrentConnections")); + AICurlInterface::startCurlThread(gSavedSettings.getU32("CurlConcurrentConnections"), gSavedSettings.getBOOL("NoVerifySSLCert")); LLImage::initClass(); From 1e745ba48bcabf9a4a52a28689f5612019167040 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 20 Oct 2012 23:48:30 +0200 Subject: [PATCH 41/64] Curl work in progress. Minor changes like comment fixes and addition of accessors that will be needed for future commits. Also removed Responder::fatalError as it was never used. --- indra/aistatemachine/aicurl.cpp | 8 +------- indra/aistatemachine/aicurl.h | 12 +++++------- indra/aistatemachine/aicurlprivate.h | 2 +- indra/aistatemachine/aicurlthread.cpp | 2 +- indra/llmessage/llbuffer.cpp | 16 +++++++++++++++- indra/llmessage/llbuffer.h | 2 ++ indra/llmessage/llurlrequest.cpp | 2 +- indra/llmessage/llurlrequest.h | 5 +++++ 8 files changed, 31 insertions(+), 18 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 128110080..7217a3409 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -479,12 +479,6 @@ void Responder::completedRaw(U32 status, std::string const& reason, LLChannelDes completed(status, reason, content); } -void Responder::fatalError(std::string const& reason) -{ - llwarns << "Responder::fatalError(\"" << reason << "\") is called (" << mURL << "). Passing it to Responder::completed with fake HTML error status and empty HTML body!" << llendl; - completed(U32_MAX, reason, LLSD()); -} - // virtual void Responder::completed(U32 status, std::string const& reason, LLSD const& content) { @@ -1364,7 +1358,7 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w curl_easy_request_w->setHeaderCallback(&curlHeaderCallback, lockobj); // Allow up to ten redirects. - if (responder && responder->followRedir()) + if (responder->followRedir()) { curl_easy_request_w->setopt(CURLOPT_FOLLOWLOCATION, 1); curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index e1a999c9c..a41e544ec 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -204,7 +204,7 @@ class Responder : public AICurlResponderBufferEvents { Responder(void); virtual ~Responder(); - private: + protected: // Associated URL, used for debug output. std::string mURL; @@ -216,6 +216,9 @@ class Responder : public AICurlResponderBufferEvents { // used only when printing debug output regarding activity of the Responder. void setURL(std::string const& url); + // Accessor. + std::string const& getURL(void) const { return mURL; } + protected: // Called when the "HTTP/1.0 " header is received. /*virual*/ void received_HTTP_header(void) @@ -237,7 +240,7 @@ class Responder : public AICurlResponderBufferEvents { completedHeaders(status, reason, mReceivedHeaders); } - // Derived classes can override this to get the HTML header that was received, when the message is completed. + // Derived classes can override this to get the HTML headers that were received, when the message is completed. // The default does nothing. virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers); @@ -252,11 +255,6 @@ class Responder : public AICurlResponderBufferEvents { // The default is to interpret the content as LLSD and call completed(). virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); - // Called from LLHTTPClient request calls, if an error occurs even before we can call one of the above. - // It calls completed() with a fake status U32_MAX, as that is what some derived clients expect (bad design). - // This means that if a derived class overrides completedRaw() it now STILL has to override completed() to catch this error. - void fatalError(std::string const& reason); - // A derived class should return true if curl should follow redirections. // The default is not to follow redirections. virtual bool followRedir(void) { return false; } diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index b4741eca0..f6a1642ca 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -366,7 +366,7 @@ class CurlEasyRequest : public CurlEasyHandle { private: curl_slist* mHeaders; AICurlEasyHandleEvents* mEventsTarget; - CURLcode mResult; + CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object. AIHTTPTimeoutPolicy const* mTimeoutPolicy; std::string mLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index a70f8e820..e303a4a44 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -2105,7 +2105,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request { // Only the responder registers for these events. llassert(mEventsTarget == mResponder.get()); - // Allow clients to parse headers before we attempt to parse + // Allow clients to parse result codes and headers before we attempt to parse // the body and provide completed/result/error calls. mEventsTarget->completed_headers(responseCode, responseReason); } diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 437674775..0f31f7065 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -393,7 +393,14 @@ LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address) mSegments.insert(it, segment2); return rv; } - + +//mMutexp should be locked before calling this. +LLBufferArray::const_segment_iterator_t LLBufferArray::beginSegment() const +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED + return mSegments.begin(); +} + //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::beginSegment() { @@ -401,6 +408,13 @@ LLBufferArray::segment_iterator_t LLBufferArray::beginSegment() return mSegments.begin(); } +//mMutexp should be locked before calling this. +LLBufferArray::const_segment_iterator_t LLBufferArray::endSegment() const +{ + ASSERT_LLBUFFERARRAY_MUTEX_LOCKED + return mSegments.end(); +} + //mMutexp should be locked before calling this. LLBufferArray::segment_iterator_t LLBufferArray::endSegment() { diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index 7f83896a7..4940da2fe 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -495,6 +495,7 @@ public: * @return Returns the segment if there is one. */ segment_iterator_t beginSegment(); + const_segment_iterator_t beginSegment() const; /** * @brief Get the one-past-the-end segment in the buffer array @@ -502,6 +503,7 @@ public: * @return Returns the iterator for an invalid segment location. */ segment_iterator_t endSegment(); + const_segment_iterator_t endSegment() const; /** * @brief Get the segment which holds the given address. diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 17c393b02..d1ce88672 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -516,7 +516,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) 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. + // to using this, causing the broken server to get confused. curlEasyRequest_w->addHeader("Expect:"); curlEasyRequest_w->setopt(CURLOPT_UPLOAD, 1); curlEasyRequest_w->setopt(CURLOPT_INFILESIZE, mBodySize); diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 5ae4d64aa..3244f0035 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -77,6 +77,11 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { */ LLURLRequest(ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression); + protected: + // Call abort(), not delete. + /*virtual*/ ~LLURLRequest() { } + + public: /** * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE. */ From a4bf92dae4b0f9ee93739cd5afd772bbcf848288 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 20 Oct 2012 23:56:19 +0200 Subject: [PATCH 42/64] Add CURLcode and TransferInfo to completed_headers event. --- indra/aistatemachine/aicurl.h | 7 +++++-- indra/aistatemachine/aicurlprivate.h | 2 +- indra/aistatemachine/aicurlthread.cpp | 9 +++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index a41e544ec..c41916339 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -122,11 +122,14 @@ class AICurlNoBody : public AICurlError { // End Exceptions. //----------------------------------------------------------------------------- +// Forward declaration. +namespace AICurlInterface { struct TransferInfo; } + // Events generated by AICurlPrivate::CurlResponderBuffer. struct AICurlResponderBufferEvents { virtual void received_HTTP_header(void) = 0; // For example "HTTP/1.0 200 OK", the first header of a reply. virtual void received_header(std::string const& key, std::string const& value) = 0; // Subsequent headers. - virtual void completed_headers(U32 status, std::string const& reason) = 0; // Transaction completed. + virtual void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) = 0; // Transaction completed. }; // Things defined in this namespace are called from elsewhere in the viewer code. @@ -235,7 +238,7 @@ class Responder : public AICurlResponderBufferEvents { } // Called when the whole transaction is completed (also the body was received), but before the body is processed. - /*virtual*/ void completed_headers(U32 status, std::string const& reason) + /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, TransferInfo* info) { completedHeaders(status, reason, mReceivedHeaders); } diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index f6a1642ca..d6f941a5d 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -458,7 +458,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC // Events from this class. /*virtual*/ void received_HTTP_header(void); /*virtual*/ void received_header(std::string const& key, std::string const& value); - /*virtual*/ void completed_headers(U32 status, std::string const& reason); + /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); // CurlEasyHandle events. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index e303a4a44..080908538 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -2076,7 +2076,8 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request std::string responseReason; CURLcode code; - curl_easy_request_w->getResult(&code); + AICurlInterface::TransferInfo info; + curl_easy_request_w->getResult(&code, &info); if (code == CURLE_OK) { curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode); @@ -2107,7 +2108,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request llassert(mEventsTarget == mResponder.get()); // Allow clients to parse result codes and headers before we attempt to parse // the body and provide completed/result/error calls. - mEventsTarget->completed_headers(responseCode, responseReason); + mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); } mResponder->completedRaw(responseCode, responseReason, sChannels, mOutput); mResponder = NULL; @@ -2128,10 +2129,10 @@ void CurlResponderBuffer::received_header(std::string const& key, std::string co mEventsTarget->received_header(key, value); } -void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason) +void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) { if (mEventsTarget) - mEventsTarget->completed_headers(status, reason); + mEventsTarget->completed_headers(status, reason, code, info); } //static From f7626699dac7e02865ae229b18e8802d16808efb Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 21 Oct 2012 17:26:57 +0200 Subject: [PATCH 43/64] Bug fix: (correctly) revoke CurlResponderBuffer events. --- indra/aistatemachine/aicurl.cpp | 2 +- indra/aistatemachine/aicurl.h | 4 ++-- indra/aistatemachine/aicurleasyrequeststatemachine.cpp | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 7217a3409..6563bbdb8 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1294,7 +1294,7 @@ CurlResponderBuffer::~CurlResponderBuffer() { ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); AICurlEasyRequest_wat curl_easy_request_w(*lockobj); // Wait 'til possible callbacks have returned. - curl_easy_request_w->send_events_to(NULL); + send_events_to(NULL); curl_easy_request_w->revokeCallbacks(); if (mResponder) { diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index c41916339..655f6ecaa 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -223,8 +223,8 @@ class Responder : public AICurlResponderBufferEvents { std::string const& getURL(void) const { return mURL; } protected: - // Called when the "HTTP/1.0 " header is received. - /*virual*/ void received_HTTP_header(void) + // Called when the "HTTP/1.x " header is received. + /*virtual*/ void received_HTTP_header(void) { // It's possible that this page was moved (302), so we already saw headers // from the 302 page and are starting over on the new page now. diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp index 85a993351..c45e34335 100644 --- a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp +++ b/indra/aistatemachine/aicurleasyrequeststatemachine.cpp @@ -235,6 +235,11 @@ void AICurlEasyRequestStateMachine::finish_impl(void) // Revoke callbacks. { AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest); + if (mBuffered) + { + AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest); + buffered_easy_request_w->send_events_to(NULL); + } curl_easy_request_w->send_events_to(NULL); curl_easy_request_w->revokeCallbacks(); } From 937a60c8f9f1ee2cc2b09635f77b8fa2005a84dd Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 21 Oct 2012 17:45:46 +0200 Subject: [PATCH 44/64] Add AIHTTPReceivedHeaders This fixes the problem that existed with received headers: The server sends some headers ("set-cookie") more than once in the same reply, which cannot be stored in std::map. The old code just ignored the additional cookies, while curlthreading3 (since the introduction of AIHTTPHeaders) caused an assertion. AIHTTPReceivedHeaders is written around a std::multimap and allows to retrieve multiple headers with the same key. Also, it is case insensitive so that if a server sends "Content-Type" it will still find it (the viewer looks for "content-type"). --- indra/aistatemachine/aicurl.cpp | 2 +- indra/aistatemachine/aicurl.h | 4 +- indra/llmessage/aihttpheaders.cpp | 54 ++++++++++++++++++-- indra/llmessage/aihttpheaders.h | 71 ++++++++++++++++++++++++++- indra/llmessage/llavatarnamecache.cpp | 33 +++++-------- indra/llmessage/llavatarnamecache.h | 4 +- indra/newview/llfloaterurlentry.cpp | 4 +- indra/newview/llviewerdisplayname.cpp | 2 +- indra/newview/llviewermedia.cpp | 22 +++++---- 9 files changed, 152 insertions(+), 44 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 6563bbdb8..58e2eaf37 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -458,7 +458,7 @@ AIHTTPTimeoutPolicy const& Responder::getHTTPTimeoutPolicy(void) const // Called with HTML header. // virtual -void Responder::completedHeaders(U32, std::string const&, AIHTTPHeaders const&) +void Responder::completedHeaders(U32, std::string const&, AIHTTPReceivedHeaders const&) { // This should not be called unless a derived class implemented it. llerrs << "Unexpected call to completedHeaders()." << llendl; diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 655f6ecaa..f2ed94347 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -212,7 +212,7 @@ class Responder : public AICurlResponderBufferEvents { std::string mURL; // Headers received from the server. - AIHTTPHeaders mReceivedHeaders; + AIHTTPReceivedHeaders mReceivedHeaders; public: // Called to set the URL of the current request for this Responder, @@ -245,7 +245,7 @@ class Responder : public AICurlResponderBufferEvents { // Derived classes can override this to get the HTML headers that were received, when the message is completed. // The default does nothing. - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers); + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers); public: // Derived classes that implement completedHeaders() should return true here. diff --git a/indra/llmessage/aihttpheaders.cpp b/indra/llmessage/aihttpheaders.cpp index 1c6c6bc07..0c6009cad 100644 --- a/indra/llmessage/aihttpheaders.cpp +++ b/indra/llmessage/aihttpheaders.cpp @@ -35,10 +35,6 @@ #include "debug_libcurl.h" #endif -AIHTTPHeaders::AIHTTPHeaders(void) -{ -} - AIHTTPHeaders::AIHTTPHeaders(std::string const& key, std::string const& value) : mContainer(new Container) { addHeader(key, value); @@ -105,3 +101,53 @@ std::ostream& operator<<(std::ostream& os, AIHTTPHeaders const& headers) return os; } +void AIHTTPReceivedHeaders::addHeader(std::string const& key, std::string const& value) +{ + if (!mContainer) + { + mContainer = new Container; + } + mContainer->mKeyValuePairs.insert(container_t::value_type(key, value)); +} + +bool AIHTTPReceivedHeaders::hasHeader(std::string const& key) const +{ + return !mContainer ? false : (mContainer->mKeyValuePairs.find(key) != mContainer->mKeyValuePairs.end()); +} + +bool AIHTTPReceivedHeaders::getFirstValue(std::string const& key, std::string& value_out) const +{ + AIHTTPReceivedHeaders::container_t::const_iterator iter; + if (!mContainer || (iter = mContainer->mKeyValuePairs.find(key)) == mContainer->mKeyValuePairs.end()) + return false; + value_out = iter->second; + return true; +} + +bool AIHTTPReceivedHeaders::getValues(std::string const& key, range_type& value_out) const +{ + if (!mContainer) + return false; + value_out = mContainer->mKeyValuePairs.equal_range(key); + return value_out.first != value_out.second; +} + +std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers) +{ + os << '{'; + if (headers.mContainer) + { + bool first = true; + AIHTTPReceivedHeaders::container_t::const_iterator const end = headers.mContainer->mKeyValuePairs.end(); + for (AIHTTPReceivedHeaders::container_t::const_iterator iter = headers.mContainer->mKeyValuePairs.begin(); iter != end; ++iter) + { + if (!first) + os << ", "; + os << '"' << iter->first << ": " << iter->second << '"'; + first = false; + } + } + os << '}'; + return os; +} + diff --git a/indra/llmessage/aihttpheaders.h b/indra/llmessage/aihttpheaders.h index 3fdce0582..95766c3e9 100644 --- a/indra/llmessage/aihttpheaders.h +++ b/indra/llmessage/aihttpheaders.h @@ -26,6 +26,8 @@ * * 15/08/2012 * Initial version, written by Aleric Inglewood @ SL + * 21/10/2012 + * Added AIHTTPReceivedHeaders */ #ifndef AIHTTPHEADERS_H @@ -34,6 +36,7 @@ #include #include #include +#include #include "llpointer.h" #include "llthread.h" // LLThreadSafeRefCount @@ -49,7 +52,7 @@ class AIHTTPHeaders { }; // Construct an empty container. - AIHTTPHeaders(void); + AIHTTPHeaders(void) { } // Construct a container with a single header. AIHTTPHeaders(std::string const& key, std::string const& value); @@ -86,4 +89,70 @@ class AIHTTPHeaders { LLPointer mContainer; }; +// Functor that returns true if c1 is less than c2, ignoring bit 5. +// The effect is that characters in the range a-z equivalent ordering with A-Z. +// This function assumes UTF-8 or ASCII encoding! +// +// Note that other characters aren't important in the case of HTTP header keys; +// however if one considers all printable ASCII characters, then this functor +// also compares "@[\]^" equal to "`{|}~" (any other is either not printable or +// would be equal to a not printable character). +struct AIHTTPReceivedHeadersCharCompare { + bool operator()(std::string::value_type c1, std::string::value_type c2) const + { + static std::string::value_type const bit5 = 0x20; + return (c1 | bit5) < (c2 | bit5); + } +}; + +// Functor to lexiographically compare two HTTP header keys using the above predicate. +// This means that for example "Content-Type" and "content-type" will have equivalent ordering. +struct AIHTTPReceivedHeadersCompare { + bool operator()(std::string const& h1, std::string const& h2) const + { + static AIHTTPReceivedHeadersCharCompare const predicate; + return std::lexicographical_compare(h1.begin(), h1.end(), h2.begin(), h2.end(), predicate); + } +}; + +class AIHTTPReceivedHeaders { + private: + typedef std::multimap container_t; + + public: + typedef container_t::const_iterator iterator_type; + typedef std::pair range_type; + + // Construct an empty container. + AIHTTPReceivedHeaders(void) { } + + // Clear all headers. + void clear(void) { if (mContainer) mContainer->mKeyValuePairs.clear(); } + + // Add a header. + void addHeader(std::string const& key, std::string const& value); + + // Return true if there are no headers associated with this object. + bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); } + + // Return true if the header exists. + bool hasHeader(std::string const& key) const; + + // Return true if key exists and fill value_out with the value. Return false otherwise. + bool getFirstValue(std::string const& key, std::string& value_out) const; + + // Return true if key exists and fill value_out with all values. Return false otherwise. + bool getValues(std::string const& key, range_type& value_out) const; + + // For debug purposes. + friend std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers); + + private: + struct Container : public LLThreadSafeRefCount { + container_t mKeyValuePairs; + }; + + LLPointer mContainer; +}; + #endif // AIHTTPHEADERS_H diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index fb4eed79a..57affabfe 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -129,7 +129,7 @@ namespace LLAvatarNameCache // Erase expired names from cache void eraseUnrefreshed(); - bool expirationFromCacheControl(AIHTTPHeaders const& headers, F64* expires); + bool expirationFromCacheControl(AIHTTPReceivedHeaders const& headers, F64* expires); } /* Sample response: @@ -182,7 +182,7 @@ private: std::vector mAgentIDs; // Need the headers to look up Expires: and Retry-After: - AIHTTPHeaders mHeaders; + AIHTTPReceivedHeaders mHeaders; public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return avatarNameResponder_timeout; } @@ -191,7 +191,7 @@ public: : mAgentIDs(agent_ids) { } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) + /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { mHeaders = headers; } @@ -791,42 +791,33 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na sCache[agent_id] = av_name; } -F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPHeaders const& headers) +F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPReceivedHeaders const& 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; - } + F64 expires; + expirationFromCacheControl(headers, &expires); + return expires; } -bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPHeaders const& headers, F64* expires) +bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const& headers, F64* expires) { bool fromCacheControl = false; + S32 max_age = 3600; // With no expiration info, default to an hour. F64 now = LLFrameTimer::getTotalSeconds(); // Allow the header to override the default std::string cache_control; - if (headers.getValue("cache-control", cache_control)) + if (headers.getFirstValue("cache-control", cache_control)) { - S32 max_age = 0; if (max_age_from_cache_control(cache_control, &max_age)) { - *expires = now + (F64)max_age; fromCacheControl = true; } } + *expires = now + (F64)max_age; LL_DEBUGS("AvNameCache") << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) << "in " << *expires - now << " seconds" << LL_ENDL; - + return fromCacheControl; } diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 268133b02..75f613e74 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -33,7 +33,7 @@ #include class LLUUID; -class AIHTTPHeaders; +class AIHTTPReceivedHeaders; namespace LLAvatarNameCache { @@ -98,7 +98,7 @@ namespace LLAvatarNameCache // Compute name expiration time from HTTP Cache-Control header, // or return default value, in seconds from epoch. - F64 nameExpirationFromHeaders(AIHTTPHeaders const& headers); + F64 nameExpirationFromHeaders(AIHTTPReceivedHeaders const& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); } diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index baf90fc7e..f43619553 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -64,10 +64,10 @@ public: virtual bool needsHeaders(void) const { return true; } - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { std::string media_type; - bool content_type_found = headers.getValue("content-type", media_type); + bool content_type_found = headers.getFirstValue("content-type", media_type); llassert_always(content_type_found); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index a9b3a27f3..e5590de87 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -184,7 +184,7 @@ class LLDisplayNameUpdate : public LLHTTPNode // *TODO: get actual headers out of ResponsePtr //LLSD headers = response->mHeaders; av_name.mExpires = - LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPHeaders()); + LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPReceivedHeaders()); LLAvatarNameCache::insert(agent_id, av_name); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 093a3989b..25acb0b83 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -82,10 +82,10 @@ public: virtual bool needsHeaders(void) const { return true; } - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { std::string media_type; - bool content_type_found = headers.getValue("content-type", media_type); + bool content_type_found = headers.getFirstValue("content-type", media_type); llassert_always(content_type_found); std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); @@ -125,14 +125,15 @@ public: /* virtual */ bool needsHeaders(void) const { return true; } - /* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) + /* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; LL_DEBUGS("MediaAuth") << headers << LL_ENDL; - std::string cookie; - if (headers.getValue("set-cookie", cookie)) + AIHTTPReceivedHeaders::range_type cookies; + if (headers.getValues("set-cookie", cookies)) { - LLViewerMedia::openIDCookieResponse(cookie); + for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie) + LLViewerMedia::openIDCookieResponse(cookie->second); } } @@ -164,15 +165,16 @@ public: /* virtual */ bool needsHeaders(void) const { return true; } - /* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPHeaders const& headers) + /* virtual */ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; LL_INFOS("MediaAuth") << headers << LL_ENDL; - std::string cookie; - if (headers.getValue("set-cookie", cookie)) + AIHTTPReceivedHeaders::range_type cookies; + if (headers.getValues("set-cookie", cookies)) { - LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie) + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie->second, mHost); } } From c35bc713346ea40ab93d1a44879c438e30bc4ace Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 22 Oct 2012 00:44:19 +0200 Subject: [PATCH 45/64] Fix crash when libcurl calls read callback before calling socket callback. In days of usage this has never happened before, but apparently it's possible. The solution chosen is to create the AIHTTPTimeout object on the fly when it doesn't exist and let it be picked up later when the CurlSocketInfo for the transfer is created. --- indra/aistatemachine/aicurl.cpp | 19 +++++++++++++++++++ indra/aistatemachine/aicurlprivate.h | 15 ++++++++++----- indra/aistatemachine/aicurlthread.cpp | 11 +++++++---- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 58e2eaf37..c9f393ff5 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -1202,6 +1202,25 @@ void CurlEasyRequest::set_timeout_opts(void) setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); } +void CurlEasyRequest::create_timeout_object(ThreadSafeCurlEasyRequest* lockobj) +{ + mTimeout = new curlthread::HTTPTimeout(mTimeoutPolicy, lockobj); +} + +LLPointer& CurlEasyRequest::get_timeout_object(ThreadSafeCurlEasyRequest* lockobj) +{ + if (mTimeoutIsOrphan) + { + mTimeoutIsOrphan = false; + llassert_always(mTimeout); + } + else + { + create_timeout_object(lockobj); + } + return mTimeout; +} + void CurlEasyRequest::print_curl_timings(void) const { double t; diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index d6f941a5d..fbf70fcce 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -325,6 +325,9 @@ class CurlEasyRequest : public CurlEasyHandle { // Used in applyDefaultOptions. static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); + // Called from get_timeout_object and httptimeout. + void create_timeout_object(ThreadSafeCurlEasyRequest* lockobj); + public: // Set default options that we want applied to all curl easy handles. void applyDefaultOptions(void); @@ -370,7 +373,8 @@ class CurlEasyRequest : public CurlEasyHandle { AIHTTPTimeoutPolicy const* mTimeoutPolicy; std::string mLowercaseHostname; // Lowercase hostname (canonicalized) extracted from the url. - LLPointer mTimeout; + LLPointer mTimeout;// Timeout administration object associated with last created CurlSocketInfo. + bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo. #if defined(CWDEBUG) || defined(DEBUG_CURLIO) public: bool mDebugIsGetMethod; @@ -381,9 +385,10 @@ class CurlEasyRequest : public CurlEasyHandle { AIHTTPTimeoutPolicy const* getTimeoutPolicy(void) const { return mTimeoutPolicy; } std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; } // Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request. - void set_timeout_object(LLPointer& timeout) { mTimeout = timeout; } - // And the accessor for it. - LLPointer& httptimeout(void) { return mTimeout; } + // This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan). + LLPointer& get_timeout_object(ThreadSafeCurlEasyRequest* lockobj); + // Accessor for mTimeout with optional creation of orphaned object (if lockobj != NULL). + LLPointer& httptimeout(ThreadSafeCurlEasyRequest* lockobj = NULL) { if (lockobj && !mTimeout) create_timeout_object(lockobj); return mTimeout; } // Return true if no data has been received on the latest socket (if any) for too long. bool has_stalled(void) const { return mTimeout && mTimeout->has_stalled(); } @@ -391,7 +396,7 @@ class CurlEasyRequest : public CurlEasyHandle { // This class may only be created by constructing a ThreadSafeCurlEasyRequest. friend class ThreadSafeCurlEasyRequest; // Throws AICurlNoEasyHandle. - CurlEasyRequest(void) : mHeaders(NULL), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL) + CurlEasyRequest(void) : mHeaders(NULL), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) , mDebugIsGetMethod(false) #endif diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 080908538..e03d92e7f 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -773,8 +773,7 @@ CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socke // CurlSocketInfo objects for a request and we need upload_finished() to be called on the HTTPTimeout // object related to THIS CurlSocketInfo. AICurlEasyRequest_wat easy_request_w(*lockobj); - mTimeout = new HTTPTimeout(easy_request_w->getTimeoutPolicy(), lockobj); - easy_request_w->set_timeout_object(mTimeout); + mTimeout = easy_request_w->get_timeout_object(lockobj); } CurlSocketInfo::~CurlSocketInfo() @@ -2170,8 +2169,12 @@ size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nme S32 bytes = size * nmemb; // The maximum amount to read. AICurlResponderBuffer_wat buffer_w(*lockobj); buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); - buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. - if (buffered_easy_request_w->httptimeout()->data_sent(bytes)) // Timeout administration. + buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + // Timeout administration. Note that it can happen that we get here + // before the socket callback has been called, because the silly libcurl + // writes headers without informing us. In that case it's OK to create + // the Timeout object on the fly, so pass lockobj. + if (buffered_easy_request_w->httptimeout(lockobj)->data_sent(bytes)) { // Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK. return CURL_READFUNC_ABORT; From 7f50b2ba7b529207491a0fa16e4553b0a490d0da Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 22 Oct 2012 01:59:17 +0200 Subject: [PATCH 46/64] Add XMLRPC support to LLHTTPClient and that instead of LLXMLRPCTransaction --- indra/aistatemachine/aicurl.h | 2 +- indra/llmessage/aihttptimeoutpolicy.cpp | 2 +- indra/llmessage/llhttpclient.cpp | 40 ++ indra/llmessage/llhttpclient.h | 11 + indra/newview/CMakeLists.txt | 4 +- indra/newview/llcurrencyuimanager.cpp | 42 +- indra/newview/llfloaterbuyland.cpp | 44 +- indra/newview/lluserauth.cpp | 45 +- indra/newview/lluserauth.h | 12 +- indra/newview/llxmlrpcresponder.cpp | 322 ++++++++++ ...mlrpctransaction.h => llxmlrpcresponder.h} | 94 ++- indra/newview/llxmlrpctransaction.cpp | 577 ------------------ 12 files changed, 479 insertions(+), 716 deletions(-) create mode 100644 indra/newview/llxmlrpcresponder.cpp rename indra/newview/{llxmlrpctransaction.h => llxmlrpcresponder.h} (59%) delete mode 100644 indra/newview/llxmlrpctransaction.cpp diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index f2ed94347..db1da9a10 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -136,7 +136,7 @@ struct AICurlResponderBufferEvents { namespace AICurlInterface { // Output parameter of AICurlPrivate::CurlEasyRequest::getResult. -// Only used by LLXMLRPCTransaction::Impl. +// Used in XMLRPCResponder. struct TransferInfo { TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) { } F64 mSizeDownload; diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 55a2e7ad4..1a601db07 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -729,5 +729,5 @@ P(voiceCallCapResponder); P(voiceClientCapResponder); P(wholeModelFeeResponder); P(wholeModelUploadResponder); -P2(XMLRPCTransaction, connect_40s); +P2(XMLRPCResponder, connect_40s); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index e7becc520..03e9e50e5 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include +#include #include "llhttpclient.h" #include "llbufferstream.h" @@ -40,6 +41,29 @@ extern AIHTTPTimeoutPolicy blockingPost_timeout; //////////////////////////////////////////////////////////////////////////// +class XMLRPCInjector : public Injector { +public: + XMLRPCInjector(XMLRPC_REQUEST request) : mRequest(request), mRequestText(NULL) { } + ~XMLRPCInjector() { XMLRPC_RequestFree(mRequest, 1); XMLRPC_Free(const_cast(mRequestText)); } + + /*virtual*/ char const* contentType(void) const { return "text/xml"; } + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) + { + int requestTextSize; + mRequestText = XMLRPC_REQUEST_ToXML(mRequest, &requestTextSize); + if (!mRequestText) + throw AICurlNoBody("XMLRPC_REQUEST_ToXML returned NULL."); + LLBufferStream ostream(channels, buffer.get()); + ostream.write(mRequestText, requestTextSize); + ostream << std::flush; // Always flush a LLBufferStream when done writing to it. + return requestTextSize; + } + +private: + XMLRPC_REQUEST const mRequest; + char const* mRequestText; +}; + class LLSDInjector : public Injector { public: @@ -369,6 +393,22 @@ void LLHTTPClient::post4(std::string const& url, LLSD const& body, ResponderPtr request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers); } +void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers) +{ + request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, false); // Does use compression. +} + +void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers) +{ + XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew(); + XMLRPC_RequestSetMethodName(xmlrpc_request, method); + XMLRPC_RequestSetRequestType(xmlrpc_request, xmlrpc_request_call); + XMLRPC_RequestSetData(xmlrpc_request, value); + // XMLRPCInjector takes ownership of xmlrpc_request and will free it when done. + // LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done. + request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression. +} + void LLHTTPClient::postRaw4(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers); diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 0dcd0767f..d6ffad888 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -43,6 +43,8 @@ class LLSD; class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy responderIgnore_timeout; +typedef struct _xmlrpc_request* XMLRPC_REQUEST; +typedef struct _xmlrpc_value* XMLRPC_VALUE; class LLHTTPClient { @@ -84,6 +86,15 @@ public: static void post4(std::string const& url, LLSD const& body, ResponderPtr responder) { AIHTTPHeaders headers; post4(url, body, responder, headers); } + /** Takes ownership of request and deletes it when sent */ + static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers); + static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder) + { AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers); } + + static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers); + static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder) + { AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); } + /** Takes ownership of data and deletes it when sent */ static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers); static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b87eba3fe..8d7f6c323 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -544,7 +544,7 @@ set(viewer_SOURCE_FILES llworldmap.cpp llworldmipmap.cpp llworldmapview.cpp - llxmlrpctransaction.cpp + llxmlrpcresponder.cpp m7wlinterface.cpp NACLantispam.cpp noise.cpp @@ -1051,7 +1051,7 @@ set(viewer_HEADER_FILES llworldmap.h llworldmipmap.h llworldmapview.h - llxmlrpctransaction.h + llxmlrpcresponder.h m7wlinterface.h macmain.h NACLantispam.h diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index e31e9d114..5ba0c5980 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -44,7 +44,8 @@ #include "llframetimer.h" #include "lllineeditor.h" #include "llviewchildren.h" -#include "llxmlrpctransaction.h" +#include "llxmlrpcresponder.h" +#include "llhttpclient.h" #include "llviewernetwork.h" #include "hippogridmanager.h" @@ -89,8 +90,8 @@ public: }; TransactionType mTransactionType; - LLXMLRPCTransaction* mTransaction; - + boost::intrusive_ptr mResponder; + bool mCurrencyChanged; LLFrameTimer mCurrencyKeyTimer; @@ -128,14 +129,13 @@ LLCurrencyUIManager::Impl::Impl(LLPanel& dialog) mSiteCurrencyEstimated(false), mSiteCurrencyEstimatedCost(0), mBought(false), - mTransactionType(TransactionNone), mTransaction(0), + mTransactionType(TransactionNone), mCurrencyChanged(false) { } LLCurrencyUIManager::Impl::~Impl() { - delete mTransaction; } void LLCurrencyUIManager::Impl::updateCurrencyInfo() @@ -166,7 +166,7 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo() void LLCurrencyUIManager::Impl::finishCurrencyInfo() { - LLXMLRPCValue result = mTransaction->responseValue(); + LLXMLRPCValue result = mResponder->responseValue(); bool success = result["success"].asBool(); if (!success) @@ -219,7 +219,7 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) void LLCurrencyUIManager::Impl::finishCurrencyBuy() { - LLXMLRPCValue result = mTransaction->responseValue(); + LLXMLRPCValue result = mResponder->responseValue(); bool success = result["success"].asBool(); if (!success) @@ -246,34 +246,28 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type, transactionURI = LLViewerLogin::getInstance()->getHelperURI() + "currency.php"; } - delete mTransaction; - mTransactionType = type; - mTransaction = new LLXMLRPCTransaction( - transactionURI, - method, - params, - false /* don't use gzip */ - ); + mResponder = new XMLRPCResponder; + LLHTTPClient::postXMLRPC(transactionURI, method, params.getValue(), mResponder); clearError(); } bool LLCurrencyUIManager::Impl::checkTransaction() { - if (!mTransaction) + if (!mResponder) { return false; } - if (!mTransaction->is_finished()) + if (!mResponder->is_finished()) { return false; } - if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete) + if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400) { - setError(mTransaction->statusMessage(), mTransaction->statusURI()); + setError(mResponder->reason(), mResponder->getURL()); } else { switch (mTransactionType) @@ -283,11 +277,11 @@ bool LLCurrencyUIManager::Impl::checkTransaction() default: ; } } - - delete mTransaction; - mTransaction = NULL; + + // We're done with this data. + mResponder = NULL; mTransactionType = TransactionNone; - + return true; } @@ -309,7 +303,7 @@ void LLCurrencyUIManager::Impl::clearError() bool LLCurrencyUIManager::Impl::considerUpdateCurrency() { if (mCurrencyChanged - && !mTransaction + && !mResponder && mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY) { updateCurrencyInfo(); diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 909111ee3..a5a1b62a2 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -62,8 +62,9 @@ #include "llweb.h" #include "llwindow.h" #include "llworld.h" -#include "llxmlrpctransaction.h" +#include "llxmlrpcresponder.h" #include "llviewernetwork.h" +#include "llhttpclient.h" #include "roles_constants.h" #include "hippogridmanager.h" @@ -158,7 +159,7 @@ private: TransactionCurrency, TransactionBuy }; - LLXMLRPCTransaction* mTransaction; + boost::intrusive_ptr mResponder; TransactionType mTransactionType; LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo; @@ -283,7 +284,7 @@ LLFloaterBuyLandUI::LLFloaterBuyLandUI() mParcel(0), mBought(false), mParcelValid(false), mSiteValid(false), - mChildren(*this), mCurrency(*this), mTransaction(0), + mChildren(*this), mCurrency(*this), mParcelBuyInfo(0) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_land.xml"); @@ -294,8 +295,6 @@ LLFloaterBuyLandUI::~LLFloaterBuyLandUI() { LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver); LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo); - - delete mTransaction; } // virtual @@ -619,7 +618,7 @@ void LLFloaterBuyLandUI::updateWebSiteInfo() S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea; S32 askCurrencyBuy = mCurrency.getAmount(); - if (mTransaction && mTransactionType == TransactionPreflight + if (mResponder && mTransactionType == TransactionPreflight && mPreflightAskBillableArea == askBillableArea && mPreflightAskCurrencyBuy == askCurrencyBuy) { @@ -660,7 +659,7 @@ void LLFloaterBuyLandUI::updateWebSiteInfo() void LLFloaterBuyLandUI::finishWebSiteInfo() { - LLXMLRPCValue result = mTransaction->responseValue(); + LLXMLRPCValue result = mResponder->responseValue(); mSiteValid = result["success"].asBool(); if (!mSiteValid) @@ -755,7 +754,7 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password) void LLFloaterBuyLandUI::finishWebSitePrep() { - LLXMLRPCValue result = mTransaction->responseValue(); + LLXMLRPCValue result = mResponder->responseValue(); bool success = result["success"].asBool(); if (!success) @@ -825,9 +824,6 @@ void LLFloaterBuyLandUI::updateName(const LLUUID& id, void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params) { - delete mTransaction; - mTransaction = NULL; - mTransactionType = type; // Select a URI and method appropriate for the transaction type. @@ -851,29 +847,25 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa return; } - mTransaction = new LLXMLRPCTransaction( - transaction_uri, - method, - params, - false /* don't use gzip */ - ); + mResponder = new XMLRPCResponder; + LLHTTPClient::postXMLRPC(transaction_uri, method, params.getValue(), mResponder); } bool LLFloaterBuyLandUI::checkTransaction() { - if (!mTransaction) + if (!mResponder) { return false; } - if (!mTransaction->is_finished()) + if (!mResponder->is_finished()) { return false; } - if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete) + if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400) { - tellUserError(mTransaction->statusMessage(), mTransaction->statusURI()); + tellUserError(mResponder->reason(), mResponder->getURL()); } else { switch (mTransactionType) @@ -884,8 +876,8 @@ bool LLFloaterBuyLandUI::checkTransaction() } } - delete mTransaction; - mTransaction = NULL; + // We're done with this data. + mResponder = NULL; return true; } @@ -918,7 +910,7 @@ BOOL LLFloaterBuyLandUI::postBuild() void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel) { - if (mTransaction && mTransactionType == TransactionBuy) + if (mResponder && mTransactionType == TransactionBuy) { // the user is buying, don't change the selection return; @@ -968,7 +960,7 @@ void LLFloaterBuyLandUI::draw() // virtual BOOL LLFloaterBuyLandUI::canClose() { - bool can_close = (mTransaction ? FALSE : TRUE) && mCurrency.canCancel(); + bool can_close = !mResponder && mCurrency.canCancel(); if (!can_close) { // explain to user why they can't do this, see DEV-9605 @@ -1285,7 +1277,7 @@ void LLFloaterBuyLandUI::refreshUI() } childSetEnabled("buy_btn", - mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant); + mCanBuy && mSiteValid && willHaveEnough && !mResponder && agrees_to_covenant); } void LLFloaterBuyLandUI::startBuyPreConfirm() diff --git a/indra/newview/lluserauth.cpp b/indra/newview/lluserauth.cpp index a10c66fca..a692f9575 100644 --- a/indra/newview/lluserauth.cpp +++ b/indra/newview/lluserauth.cpp @@ -42,8 +42,9 @@ #include "llappviewer.h" #include "llviewerbuild.h" #include "llviewercontrol.h" -#include "llxmlrpctransaction.h" +#include "llxmlrpcresponder.h" #include "llsdutil.h" +#include "llhttpclient.h" #include "stringize.h" // NOTE: MUST include these after otherincludes since queue gets redefined!?!! @@ -73,7 +74,6 @@ static const char* PLATFORM_STRING = "Sol"; LLUserAuth::LLUserAuth() : - mTransaction(NULL), mLastTransferRateBPS(0), mResult(LLSD()) { @@ -87,13 +87,11 @@ LLUserAuth::~LLUserAuth() void LLUserAuth::reset() { - delete mTransaction; - mTransaction = NULL; + mResponder = NULL; mResponses.clear(); mResult.clear(); } - void LLUserAuth::authenticate( const std::string& auth_uri, const std::string& method, @@ -168,15 +166,13 @@ void LLUserAuth::authenticate( // put the parameters on the request XMLRPC_RequestSetData(request, params); - mTransaction = new LLXMLRPCTransaction(auth_uri, request); - - XMLRPC_RequestFree(request, 1); + mResponder = new XMLRPCResponder; + LLHTTPClient::postXMLRPC(auth_uri, request, mResponder); LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL; } - // Legacy version of constructor // passwd is already MD5 hashed by the time we get to it. @@ -258,25 +254,25 @@ void LLUserAuth::authenticate( // put the parameters on the request XMLRPC_RequestSetData(request, params); - mTransaction = new LLXMLRPCTransaction(auth_uri, request); + // Post the XML RPC. + mResponder = new XMLRPCResponder; + LLHTTPClient::postXMLRPC(auth_uri, request, mResponder); - XMLRPC_RequestFree(request, 1); - LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL; } LLUserAuth::UserAuthcode LLUserAuth::authResponse() { - if (!mTransaction) + if (!mResponder) { return mAuthResponse; } - bool done = mTransaction->is_finished(); + bool done = mResponder->is_finished(); if (!done) { - if (LLXMLRPCTransaction::StatusDownloading == mTransaction->status(0)) + if (mResponder->is_downloading()) { mAuthResponse = E_DOWNLOADING; } @@ -284,14 +280,11 @@ LLUserAuth::UserAuthcode LLUserAuth::authResponse() return mAuthResponse; } - - mLastTransferRateBPS = mTransaction->transferRate(); + mLastTransferRateBPS = mResponder->transferRate(); + mErrorMessage = mResponder->reason(); - int result; - mTransaction->status(&result); - mErrorMessage = mTransaction->statusMessage(); - // if curl was ok, parse the download area. + CURLcode result = mResponder->result_code(); switch (result) { case CURLE_OK: @@ -313,12 +306,12 @@ LLUserAuth::UserAuthcode LLUserAuth::authResponse() mAuthResponse = E_UNHANDLED_ERROR; break; } - + LL_INFOS2("AppInit", "Authentication") << "Processed response: " << result << LL_ENDL; - delete mTransaction; - mTransaction = NULL; - + // We're done with this data. + mResponder = NULL; + return mAuthResponse; } @@ -329,7 +322,7 @@ LLUserAuth::UserAuthcode LLUserAuth::parseResponse() // mOptions. For now, we will only be looking at mResponses, which // will all be string => string pairs. UserAuthcode rv = E_UNHANDLED_ERROR; - XMLRPC_REQUEST response = mTransaction->response(); + XMLRPC_REQUEST response = mResponder->response(); if(!response) return rv; // clear out any old parsing diff --git a/indra/newview/lluserauth.h b/indra/newview/lluserauth.h index e0160d874..12cf1f956 100644 --- a/indra/newview/lluserauth.h +++ b/indra/newview/lluserauth.h @@ -36,10 +36,13 @@ #include #include #include -typedef struct _xmlrpc_value* XMLRPC_VALUE; -// forward ecl of types from xlrpc.h +#include -class LLXMLRPCTransaction; +class LLURLRequest; +class XMLRPCResponder; + +// forward decl of types from xlrpc.h +typedef struct _xmlrpc_value* XMLRPC_VALUE; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLUserAuth @@ -142,8 +145,7 @@ public: F64 getLastTransferRateBPS() const { return mLastTransferRateBPS; } private: - LLXMLRPCTransaction* mTransaction; - + boost::intrusive_ptr mResponder; std::string mErrorMessage; diff --git a/indra/newview/llxmlrpcresponder.cpp b/indra/newview/llxmlrpcresponder.cpp new file mode 100644 index 000000000..ddf4afee9 --- /dev/null +++ b/indra/newview/llxmlrpcresponder.cpp @@ -0,0 +1,322 @@ +/** + * @file llxmlrpcresponder.cpp + * @brief LLXMLRPCResponder and related class implementations + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * Copyright (c) 2012, Aleric Inglewood. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llxmlrpcresponder.h" +#include "llhttpclient.h" + +#include "llcurl.h" +#include "llviewercontrol.h" +#include "llbufferstream.h" + +// Have to include these last to avoid queue redefinition! +#include + +#include "llappviewer.h" + +#include "hippogridmanager.h" +#include "aicurleasyrequeststatemachine.h" + +#ifdef CWDEBUG +#include +#endif + +LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const +{ + return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id)); +} + +std::string LLXMLRPCValue::asString() const +{ + const char* s = XMLRPC_GetValueString(mV); + return s ? s : ""; +} + +int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); } +bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; } +double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); } + +LLXMLRPCValue LLXMLRPCValue::rewind() +{ + return LLXMLRPCValue(XMLRPC_VectorRewind(mV)); +} + +LLXMLRPCValue LLXMLRPCValue::next() +{ + return LLXMLRPCValue(XMLRPC_VectorNext(mV)); +} + +bool LLXMLRPCValue::isValid() const +{ + return mV != NULL; +} + +LLXMLRPCValue LLXMLRPCValue::createArray() +{ + return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array)); +} + +LLXMLRPCValue LLXMLRPCValue::createStruct() +{ + return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct)); +} + + +void LLXMLRPCValue::append(LLXMLRPCValue& v) +{ + XMLRPC_AddValueToVector(mV, v.mV); +} + +void LLXMLRPCValue::appendString(const std::string& v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0)); +} + +void LLXMLRPCValue::appendInt(int v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v)); +} + +void LLXMLRPCValue::appendBool(bool v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v)); +} + +void LLXMLRPCValue::appendDouble(double v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v)); +} + + +void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v) +{ + XMLRPC_SetValueID(v.mV, id, 0); + XMLRPC_AddValueToVector(mV, v.mV); +} + +void LLXMLRPCValue::appendString(const char* id, const std::string& v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0)); +} + +void LLXMLRPCValue::appendInt(const char* id, int v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v)); +} + +void LLXMLRPCValue::appendBool(const char* id, bool v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v)); +} + +void LLXMLRPCValue::appendDouble(const char* id, double v) +{ + XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v)); +} + +void LLXMLRPCValue::cleanup() +{ + XMLRPC_CleanupValue(mV); + mV = NULL; +} + +XMLRPC_VALUE LLXMLRPCValue::getValue() const +{ + return mV; +} + +void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) +{ + mCode = code; + if (info) + { + mTransferInfo = *info; + } + mStatus = status; + mReason = reason; + // Note: 'status' and 'reason' are the same as what is passed to completedRaw. +} + +void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +{ + if (mCode == CURLE_OK) + { + mBufferSize = buffer->count(channels.in()); + if (200 <= status && status < 400) + { + char* ptr; + char* buf = NULL; + LLMutexLock lock(buffer->getMutex()); + LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); + for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter) + { + LLSegment const& segment = *iter; + if (segment.isOnChannel(channels.in())) + { + S32 const segment_size = segment.size(); + if (!buf) + { + if (segment_size == mBufferSize) + { + // It's contiguous, no need for copying. + mResponse = XMLRPC_REQUEST_FromXML((char const*)segment.data(), mBufferSize, NULL); + break; + } + ptr = buf = new char [mBufferSize]; + } + llassert(ptr + segment_size <= buf + mBufferSize); + memcpy(ptr, segment.data(), segment_size); + ptr += segment_size; + } + } + if (buf) + { + mResponse = XMLRPC_REQUEST_FromXML(buf, mBufferSize, NULL); + delete [] buf; + } + } + } + mFinished = true; +} + +LLXMLRPCValue XMLRPCResponder::responseValue(void) const +{ + return LLXMLRPCValue(XMLRPC_RequestGetData(mResponse)); +} + +#ifdef AI_UNUSED +void LLXMLRPCTransaction::Impl::setStatus(Status status, + const std::string& message, const std::string& uri) +{ + mStatus = status; + mStatusMessage = message; + mStatusURI = uri; + + if (mStatusMessage.empty()) + { + switch (mStatus) + { + case StatusNotStarted: + mStatusMessage = "(not started)"; + break; + + case StatusStarted: + mStatusMessage = "(waiting for server response)"; + break; + + case StatusDownloading: + mStatusMessage = "(reading server response)"; + break; + + case StatusComplete: + mStatusMessage = "(done)"; + break; + + default: + // Usually this means that there's a problem with the login server, + // not with the client. Direct user to status page. + // NOTE: these should really be gHippoGridManager->getCurrentGrid()->getGridName() + // but apparently that's broken as of 1.3 b2 -- MC + mStatusMessage = + "Despite our best efforts, something unexpected has gone wrong. \n" + " \n" + "Please check " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s status \n" + "to see if there is a known problem with the service."; + + //mStatusURI = "http://secondlife.com/status/"; + } + } +} + +void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) +{ + std::string message; + std::string uri = gHippoGridManager->getCurrentGrid()->getSupportUrl(); + + switch (code) + { + case CURLE_COULDNT_RESOLVE_HOST: + message = + "DNS could not resolve the host name.\n" + "Please verify that you can connect to " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s\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 " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s 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" + "\n" + "If you continue to receive this error, please go\n" + "to the Support section of " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s web site\n" + "and report the problem."; + break; + + default: + break; + } + + mCurlCode = code; + setStatus(StatusCURLError, message, uri); +} +#endif // AI_UNUSED + +F64 XMLRPCResponder::transferRate(void) const +{ + if (mTransferInfo.mSpeedDownload == 0.0) // Don't print the below stats if this wasn't initialized. + { + return 0.0; + } + + F64 rate_bits_per_sec = mTransferInfo.mSpeedDownload * 8.0; + + LL_INFOS("AppInit") << "Buffer size: " << mBufferSize << " B" << LL_ENDL; + LL_DEBUGS("AppInit") << "Transfer size: " << mTransferInfo.mSizeDownload << " B" << LL_ENDL; + LL_DEBUGS("AppInit") << "Transfer time: " << mTransferInfo.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/llxmlrpcresponder.h similarity index 59% rename from indra/newview/llxmlrpctransaction.h rename to indra/newview/llxmlrpcresponder.h index 6d70f8ff1..23973b6db 100644 --- a/indra/newview/llxmlrpctransaction.h +++ b/indra/newview/llxmlrpcresponder.h @@ -1,10 +1,11 @@ /** - * @file llxmlrpctransaction.h - * @brief LLXMLRPCTransaction and related class header file + * @file llxmlrpcresponder.h + * @brief LLXMLRPCResponder and related class header file * * $LicenseInfo:firstyear=2006&license=viewergpl$ * * Copyright (c) 2006-2009, Linden Research, Inc. + * Copyright (c) 2012, Aleric Inglewood. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -30,10 +31,16 @@ * $/LicenseInfo$ */ -#ifndef LLXMLRPCTRANSACTION_H -#define LLXMLRPCTRANSACTION_H +#ifndef LLXMLRPCRESPONDER_H +#define LLXMLRPCRESPONDER_H #include +#include "llurlrequest.h" // Injector +#include "llcurl.h" +#include "llhttpstatuscodes.h" + +class AIHTTPTimeoutPolicy; +extern AIHTTPTimeoutPolicy XMLRPCResponder_timeout; typedef struct _xmlrpc_request* XMLRPC_REQUEST; typedef struct _xmlrpc_value* XMLRPC_VALUE; @@ -84,56 +91,35 @@ private: XMLRPC_VALUE mV; }; - -class LLXMLRPCTransaction - // an asynchronous request and respones via XML-RPC -{ -public: - LLXMLRPCTransaction(const std::string& uri, - XMLRPC_REQUEST request, bool useGzip = true); - // does not take ownership of the request object - // request can be freed as soon as the transaction is constructed - - LLXMLRPCTransaction(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip = true); - // *does* take control of the request value, you must not free it - - ~LLXMLRPCTransaction(); - - typedef enum { - StatusNotStarted, - StatusStarted, - StatusDownloading, - StatusComplete, - StatusCURLError, - StatusXMLRPCError, - StatusOtherError - } Status; - - bool is_finished(void) const; - // Returns true when done. - - Status status(int* curlCode); - // return status, and extended CURL code, if code isn't null - std::string statusMessage(); - // return a message string, suitable for showing the user - std::string statusURI(); - // return a URI for the user with more information - // can be empty - - XMLRPC_REQUEST response(); - LLXMLRPCValue responseValue(); - // only valid if StatusComplete, otherwise NULL - // retains ownership of the result object, don't free it - - F64 transferRate(); - // only valid if StatusComplete, otherwise 0.0 - +class XMLRPCResponder : public LLCurl::Responder { private: - class Impl; - Impl& impl; + CURLcode mCode; + U32 mStatus; + AICurlInterface::TransferInfo mTransferInfo; + S32 mBufferSize; + bool mReceivedHTTPHeader; + bool mFinished; + std::string mReason; + XMLRPC_REQUEST mResponse; + +public: + XMLRPCResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mReceivedHTTPHeader(false), mFinished(false) { } + + // Accessors. + CURLcode result_code(void) const { return mCode; } + U32 http_result(void) const { return mStatus; } + F64 transferRate(void) const; + bool is_downloading(void) const { return mReceivedHTTPHeader; } + bool is_finished(void) const { return mFinished; } + std::string const& reason(void) const { return mReason; } + XMLRPC_REQUEST response(void) const { return mResponse; } + LLXMLRPCValue responseValue(void) const; + + /*virtual*/ bool needsHeaders(void) const { return true; } + /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::Responder::received_HTTP_header(); } + /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return XMLRPCResponder_timeout; } }; - - -#endif // LLXMLRPCTRANSACTION_H +#endif // LLXMLRPCRESPONDER_H diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp deleted file mode 100644 index fe8b88d73..000000000 --- a/indra/newview/llxmlrpctransaction.cpp +++ /dev/null @@ -1,577 +0,0 @@ -/** - * @file llxmlrpctransaction.cpp - * @brief LLXMLRPCTransaction and related class implementations - * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llxmlrpctransaction.h" - -#include "llcurl.h" -#include "llviewercontrol.h" - -// Have to include these last to avoid queue redefinition! -#include - -#include "llappviewer.h" - -#include "hippogridmanager.h" -#include "aicurleasyrequeststatemachine.h" - -#ifdef CWDEBUG -#include -#endif - -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy XMLRPCTransaction_timeout; - -LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const -{ - return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id)); -} - -std::string LLXMLRPCValue::asString() const -{ - const char* s = XMLRPC_GetValueString(mV); - return s ? s : ""; -} - -int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); } -bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; } -double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); } - -LLXMLRPCValue LLXMLRPCValue::rewind() -{ - return LLXMLRPCValue(XMLRPC_VectorRewind(mV)); -} - -LLXMLRPCValue LLXMLRPCValue::next() -{ - return LLXMLRPCValue(XMLRPC_VectorNext(mV)); -} - -bool LLXMLRPCValue::isValid() const -{ - return mV != NULL; -} - -LLXMLRPCValue LLXMLRPCValue::createArray() -{ - return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array)); -} - -LLXMLRPCValue LLXMLRPCValue::createStruct() -{ - return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct)); -} - - -void LLXMLRPCValue::append(LLXMLRPCValue& v) -{ - XMLRPC_AddValueToVector(mV, v.mV); -} - -void LLXMLRPCValue::appendString(const std::string& v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0)); -} - -void LLXMLRPCValue::appendInt(int v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v)); -} - -void LLXMLRPCValue::appendBool(bool v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v)); -} - -void LLXMLRPCValue::appendDouble(double v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v)); -} - - -void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v) -{ - XMLRPC_SetValueID(v.mV, id, 0); - XMLRPC_AddValueToVector(mV, v.mV); -} - -void LLXMLRPCValue::appendString(const char* id, const std::string& v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0)); -} - -void LLXMLRPCValue::appendInt(const char* id, int v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v)); -} - -void LLXMLRPCValue::appendBool(const char* id, bool v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v)); -} - -void LLXMLRPCValue::appendDouble(const char* id, double v) -{ - XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v)); -} - -void LLXMLRPCValue::cleanup() -{ - XMLRPC_CleanupValue(mV); - mV = NULL; -} - -XMLRPC_VALUE LLXMLRPCValue::getValue() const -{ - return mV; -} - - -class LLXMLRPCTransaction::Impl -{ -public: - typedef LLXMLRPCTransaction::Status Status; - - AICurlEasyRequestStateMachine* mCurlEasyRequestStateMachinePtr; - - Status mStatus; - CURLcode mCurlCode; - std::string mStatusMessage; - std::string mStatusURI; - LLCurl::TransferInfo mTransferInfo; - - std::string mURI; - - std::string mProxyAddress; - - std::string mResponseText; - XMLRPC_REQUEST mResponse; - - Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip); - Impl(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip); - ~Impl(); - - bool is_finished(void) const; - void curlEasyRequestCallback(bool success); - - void setStatus(Status code, - const std::string& message = "", const std::string& uri = ""); - void setCurlStatus(CURLcode); - -private: - void init(XMLRPC_REQUEST request, bool useGzip); - - static size_t curlDownloadCallback( - char* data, size_t size, size_t nmemb, void* user_data); -}; - -LLXMLRPCTransaction::Impl::Impl(const std::string& uri, - XMLRPC_REQUEST request, bool useGzip) - : mCurlEasyRequestStateMachinePtr(NULL), - mStatus(LLXMLRPCTransaction::StatusNotStarted), - mURI(uri), - mResponse(0) -{ - init(request, useGzip); -} - - -LLXMLRPCTransaction::Impl::Impl(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip) - : mCurlEasyRequestStateMachinePtr(NULL), - mStatus(LLXMLRPCTransaction::StatusNotStarted), - mURI(uri), - mResponse(0) -{ - XMLRPC_REQUEST request = XMLRPC_RequestNew(); - XMLRPC_RequestSetMethodName(request, method.c_str()); - XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); - XMLRPC_RequestSetData(request, params.getValue()); - - init(request, useGzip); -} - -// Store pointer to data allocated with XMLRPC_REQUEST_ToXML and call XMLRPC_Free to free it upon destruction. -class AIXMLRPCData : public AIPostField -{ - public: - AIXMLRPCData(char const* allocated_data) : AIPostField(allocated_data) { } - /*virtual*/ ~AIXMLRPCData() { XMLRPC_Free(const_cast(mData)); mData = NULL; } -}; - -void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) -{ - { - try - { - mCurlEasyRequestStateMachinePtr = new AICurlEasyRequestStateMachine(false); // AIFIXME: This is the only unbuffered AICurlEasyRequestStateMachine left. - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "Failed to initialize LLXMLRPCTransaction: " << error.what() << llendl; - setStatus(StatusOtherError, "No curl easy handle"); - return; - } - AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequestStateMachinePtr->mCurlEasyRequest); - - curlEasyRequest_w->setWriteCallback(&curlDownloadCallback, (void*)this); - BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); - curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); - curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); - - /* Setting the DNS cache timeout to -1 disables it completely. - This might help with bug #503 */ - curlEasyRequest_w->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1L); - - curlEasyRequest_w->addHeader("Content-Type: text/xml"); - - if (useGzip) - { - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, ""); - } - - int requestTextSize; - char* requestText = XMLRPC_REQUEST_ToXML(request, &requestTextSize); - if (requestText) - { - curlEasyRequest_w->setPost(new AIXMLRPCData(requestText), requestTextSize); - } - else - { - setStatus(StatusOtherError); - } - - curlEasyRequest_w->finalizeRequest(mURI, XMLRPCTransaction_timeout, mCurlEasyRequestStateMachinePtr); - } - if (mStatus == LLXMLRPCTransaction::StatusNotStarted) // It could be LLXMLRPCTransaction::StatusOtherError. - { - mCurlEasyRequestStateMachinePtr->run(boost::bind(&LLXMLRPCTransaction::Impl::curlEasyRequestCallback, this, _1)); - setStatus(LLXMLRPCTransaction::StatusStarted); - } - else - { - // This deletes the statemachine immediately. - mCurlEasyRequestStateMachinePtr->kill(); - mCurlEasyRequestStateMachinePtr = NULL; - } -} - -LLXMLRPCTransaction::Impl::~Impl() -{ - if (mCurlEasyRequestStateMachinePtr && mCurlEasyRequestStateMachinePtr->running()) - { - llwarns << "Calling LLXMLRPCTransaction::Impl::~Impl while mCurlEasyRequestStateMachinePtr is still running" << llendl; - mCurlEasyRequestStateMachinePtr->abort(); - } - - if (mResponse) - { - XMLRPC_RequestFree(mResponse, 1); - } -} - -bool LLXMLRPCTransaction::Impl::is_finished(void) const -{ - // Nothing to process anymore. Just wait till the statemachine finished. - return mStatus != LLXMLRPCTransaction::StatusNotStarted && - mStatus != LLXMLRPCTransaction::StatusStarted && - mStatus != LLXMLRPCTransaction::StatusDownloading; -} - -void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success) -{ - llassert(mStatus == LLXMLRPCTransaction::StatusStarted || mStatus == LLXMLRPCTransaction::StatusDownloading); - - AICurlEasyRequestStateMachine* state_machine = mCurlEasyRequestStateMachinePtr; - // We're done with the statemachine, one way or another. - // Set mCurlEasyRequestStateMachinePtr to NULL so we won't call mCurlEasyRequestStateMachinePtr->running() in the destructor. - // Note that the state machine auto-cleaning: it will be deleted by the main-thread after this function returns. - mCurlEasyRequestStateMachinePtr = NULL; - - if (!success) - { - // AICurlEasyRequestStateMachine did abort. - // This currently only happens when libcurl didn't finish before the timer expired, or when the viewer was quit. - if (LLApp::isRunning()) - { - std::ostringstream msg; - F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeout"); - msg << "Connection to " << mURI << " timed out (" << timeout_value << " s)!"; - if (timeout_value < 40) - { - msg << "\nTry increasing CurlRequestTimeout in Debug Settings."; - } - setStatus(LLXMLRPCTransaction::StatusOtherError, msg.str()); - } - return; - } - - AICurlEasyRequest_wat curlEasyRequest_w(*state_machine->mCurlEasyRequest); - CURLcode result; - curlEasyRequest_w->getResult(&result, &mTransferInfo); - - if (result != CURLE_OK) - { - setCurlStatus(result); - llwarns << "LLXMLRPCTransaction CURL error: " - << AICurlInterface::strerror(mCurlCode) << llendl; - llwarns << "LLXMLRPCTransaction request URI: " - << mURI << llendl; - - return; - } - - setStatus(LLXMLRPCTransaction::StatusComplete); - - 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); - - llwarns << "LLXMLRPCTransaction XMLRPC " - << (hasError ? "error " : "fault ") - << faultCode << ": " - << faultString << llendl; - llwarns << "LLXMLRPCTransaction request URI: " - << mURI << llendl; - } -} - -void LLXMLRPCTransaction::Impl::setStatus(Status status, - const std::string& message, const std::string& uri) -{ - mStatus = status; - mStatusMessage = message; - mStatusURI = uri; - - if (mStatusMessage.empty()) - { - switch (mStatus) - { - case StatusNotStarted: - mStatusMessage = "(not started)"; - break; - - case StatusStarted: - mStatusMessage = "(waiting for server response)"; - break; - - case StatusDownloading: - mStatusMessage = "(reading server response)"; - break; - - case StatusComplete: - mStatusMessage = "(done)"; - break; - - default: - // Usually this means that there's a problem with the login server, - // not with the client. Direct user to status page. - // NOTE: these should really be gHippoGridManager->getCurrentGrid()->getGridName() - // but apparently that's broken as of 1.3 b2 -- MC - mStatusMessage = - "Despite our best efforts, something unexpected has gone wrong. \n" - " \n" - "Please check " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s status \n" - "to see if there is a known problem with the service."; - - //mStatusURI = "http://secondlife.com/status/"; - } - } -} - -void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) -{ - std::string message; - std::string uri = gHippoGridManager->getCurrentGrid()->getSupportUrl(); - - switch (code) - { - case CURLE_COULDNT_RESOLVE_HOST: - message = - "DNS could not resolve the host name.\n" - "Please verify that you can connect to " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s\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 " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s 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" - "\n" - "If you continue to receive this error, please go\n" - "to the Support section of " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s 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; - -#ifdef CWDEBUG - void* lockobj = impl.mCurlEasyRequestStateMachinePtr ? impl.mCurlEasyRequestStateMachinePtr->mCurlEasyRequest.get_ptr().get() : NULL; - if (n < 80) - Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << - buf2str(data, n) << "\", " << size << ", " << nmemb << ", " << user_data << ") [" << lockobj << ']'); - else - Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" << - buf2str(data, 40) << "\"...\"" << buf2str(data + n - 40, 40) << "\", " << size << ", " << nmemb << ", " << user_data << ") [" << lockobj << ']'); -#endif - - impl.mResponseText.append(data, n); - - if (impl.mStatus == LLXMLRPCTransaction::StatusStarted) - { - impl.setStatus(LLXMLRPCTransaction::StatusDownloading); - } - - return n; -} - - -LLXMLRPCTransaction::LLXMLRPCTransaction( - const std::string& uri, XMLRPC_REQUEST request, bool useGzip) -: impl(* new Impl(uri, request, useGzip)) -{ } - - -LLXMLRPCTransaction::LLXMLRPCTransaction( - const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip) -: impl(* new Impl(uri, method, params, useGzip)) -{ } - -LLXMLRPCTransaction::~LLXMLRPCTransaction() -{ - delete &impl; -} - -bool LLXMLRPCTransaction::is_finished(void) const -{ - return impl.is_finished(); -} - -LLXMLRPCTransaction::Status LLXMLRPCTransaction::status(int* curlCode) -{ - if (curlCode) - { - *curlCode = - (impl.mStatus == StatusCURLError) - ? impl.mCurlCode - : CURLE_OK; - } - - return impl.mStatus; -} - -std::string LLXMLRPCTransaction::statusMessage() -{ - return impl.mStatusMessage; -} - -std::string LLXMLRPCTransaction::statusURI() -{ - return impl.mStatusURI; -} - -XMLRPC_REQUEST LLXMLRPCTransaction::response() -{ - return impl.mResponse; -} - -LLXMLRPCValue LLXMLRPCTransaction::responseValue() -{ - return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse)); -} - - -F64 LLXMLRPCTransaction::transferRate() -{ - if (impl.mStatus != StatusComplete) - { - return 0.0L; - } - - double rate_bits_per_sec = impl.mTransferInfo.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_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL; - - return rate_bits_per_sec; -} From b92de9beb5197b69b3bf608f22ffceb88f52bf8c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 22 Oct 2012 02:20:20 +0200 Subject: [PATCH 47/64] Done as part of AIHTTPTimeout --- indra/llmessage/llurlrequest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index d1ce88672..5d5d4d6b3 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -346,7 +346,6 @@ LLIOPipe::EStatus LLURLRequest::process_impl( if (!mDetail) return STATUS_ERROR; //Seems to happen on occasion. Need to hunt down why. - //AIFIXME: implement this again: // we're still waiting or processing, check how many // bytes we have accumulated. const S32 MIN_ACCUMULATION = 100000; From 768f1b57107440e92a5970f7e490fbe99f602d5f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 22 Oct 2012 18:54:23 +0200 Subject: [PATCH 48/64] Fixes blocking_request. Adds LegacyPolledResponder and BlockingResponder. XMLRPCResponder also uses the new LegacyPolledResponder now. Renamed http_result() -> http_status(). --- indra/aistatemachine/aicurl.cpp | 18 +-- indra/aistatemachine/aicurl.h | 35 ++++- indra/llmessage/llhttpclient.cpp | 194 +++++++++++++------------- indra/newview/llcurrencyuimanager.cpp | 2 +- indra/newview/llfloaterbuyland.cpp | 2 +- indra/newview/llxmlrpcresponder.cpp | 6 +- indra/newview/llxmlrpcresponder.h | 13 +- 7 files changed, 143 insertions(+), 127 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index c9f393ff5..65457cd80 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -456,14 +456,6 @@ AIHTTPTimeoutPolicy const& Responder::getHTTPTimeoutPolicy(void) const return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); } -// Called with HTML header. -// virtual -void Responder::completedHeaders(U32, std::string const&, AIHTTPReceivedHeaders const&) -{ - // This should not be called unless a derived class implemented it. - llerrs << "Unexpected call to completedHeaders()." << llendl; -} - // Called with HTML body. // virtual void Responder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer) @@ -529,6 +521,16 @@ void intrusive_ptr_release(Responder* responder) } } +// virtual +void LegacyPolledResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) +{ + mCode = code; + mStatus = status; + mReason = reason; + // Call base class implementation. + Responder::completed_headers(status, reason, code, info); +} + } // namespace AICurlInterface //================================================================================== diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index db1da9a10..767a6dabc 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -52,6 +52,7 @@ #include "stdtypes.h" // U16, S32, U32, F64 #include "llatomic.h" // LLAtomicU32 #include "aithreadsafe.h" +#include "llhttpstatuscodes.h" #include "aihttpheaders.h" extern bool gNoVerifySSLCert; @@ -244,11 +245,13 @@ class Responder : public AICurlResponderBufferEvents { } // Derived classes can override this to get the HTML headers that were received, when the message is completed. - // The default does nothing. - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers); + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + { + // The default does nothing. + } public: - // Derived classes that implement completedHeaders() should return true here. + // Derived classes that implement completed_headers()/completedHeaders() should return true here. virtual bool needsHeaders(void) const { return false; } // Timeout policy to use. @@ -299,6 +302,32 @@ class Responder : public AICurlResponderBufferEvents { // destruct when there are no pointers left pointing to it. typedef boost::intrusive_ptr ResponderPtr; +// Same as above except that this class stores the result, allowing old polling +// code to poll if the transaction finished by calling is_finished() (from the +// main the thread) and then access the results-- as opposed to immediately +// digesting the results when any of the virtual functions are called. +class LegacyPolledResponder : public Responder { + protected: + CURLcode mCode; + U32 mStatus; + std::string mReason; + bool mFinished; + + public: + LegacyPolledResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mFinished(false) { } + + // Accessors. + CURLcode result_code(void) const { return mCode; } + U32 http_status(void) const { return mStatus; } + bool is_finished(void) const { return mFinished; } + std::string const& reason(void) const { return mReason; } + + /*virtual*/ bool needsHeaders(void) const { return true; } + /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); + // This must be defined by the derived class and set mFinished = true at the end. + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; +}; + } // namespace AICurlInterface // Forward declaration (see aicurlprivate.h). diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 03e9e50e5..6f7db978d 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -230,39 +230,68 @@ void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr get4(uri.asString(), responder, headers); } -// A simple class for managing data returned from a curl http request. -class LLHTTPBuffer -{ -public: - LLHTTPBuffer() { } - - static size_t curl_write(char* ptr, size_t size, size_t nmemb, void* user_data) - { - LLHTTPBuffer* self = (LLHTTPBuffer*)user_data; - - size_t bytes = (size * nmemb); - self->mBuffer.append(ptr,bytes); - return nmemb; - } - - LLSD asLLSD() - { - LLSD content; - - if (mBuffer.empty()) return content; - - std::istringstream istr(mBuffer); - LLSDSerialize::fromXML(content, istr); - return content; - } - - std::string asString() - { - return mBuffer; - } - +class BlockingResponder : public AICurlInterface::LegacyPolledResponder { private: - std::string mBuffer; + LLCondition mSignal; + LLSD mResponse; + std::ostringstream mBody; + +public: + void wait(void); + LLSD const& response(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + std::string const& body(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus != HTTP_OK); return mBody.str(); } + + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); +}; + +void BlockingResponder::completedRaw(U32, std::string const&, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +{ + if (mCode == CURLE_OK) + { + LLBufferStream istr(channels, buffer.get()); + if (mStatus == HTTP_OK) + { + LLSDSerialize::fromXML(mResponse, istr); + } + else + { + mBody << istr; + } + } + mSignal.lock(); + mFinished = true; + mSignal.unlock(); + mSignal.signal(); +} + +void BlockingResponder::wait(void) +{ + if (AIThreadID::in_main_thread()) + { + // We're the main thread, so we have to give AIStateMachine CPU cycles. + while (!mFinished) + { + AIStateMachine::mainloop(); + ms_sleep(10); + } + } + else // Hopefully not the curl thread :p + { + mSignal.lock(); + while (!mFinished) + mSignal.wait(); + mSignal.unlock(); + } +} + +class BlockingPostResponder : public BlockingResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingPost_timeout; } +}; + +class BlockingGetResponder : public BlockingResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingGet_timeout; } }; // These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome. @@ -287,85 +316,54 @@ static LLSD blocking_request( std::string const& url, LLURLRequest::ERequestAction method, LLSD const& body, - AIHTTPHeaders& headers, - AIHTTPTimeoutPolicy const& timeout) + AIHTTPHeaders& headers) { lldebugs << "blockingRequest of " << url << llendl; - S32 http_status = 499; - LLSD response = LLSD::emptyMap(); - -#if 0 // AIFIXME: rewrite to use AICurlEasyRequestStateMachine - try + boost::intrusive_ptr responder; + if (method == LLURLRequest::HTTP_POST) { - AICurlEasyRequest easy_request(false); - AICurlEasyRequest_wat curlEasyRequest_w(*easy_request); + responder = new BlockingPostResponder; + LLHTTPClient::post4(url, body, responder, headers); + } + else + { + llassert(method == LLURLRequest::HTTP_GET); + responder = new BlockingGetResponder; + LLHTTPClient::get4(url, responder, headers); + } - LLHTTPBuffer http_buffer; - - // * Set curl handle options - curlEasyRequest_w->setopt(CURLOPT_TIMEOUT, (long)timeout); // seconds, see warning at top of function. - curlEasyRequest_w->setWriteCallback(&LLHTTPBuffer::curl_write, &http_buffer); + responder->wait(); - // * Setup headers. - 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() ; - lldebugs << "header = " << header.str() << llendl; - curlEasyRequest_w->addHeader(header.str().c_str()); - } - } - - // Needs to stay alive until after the call to perform(). - std::ostringstream ostr; + S32 http_status = HTTP_INTERNAL_ERROR; + LLSD response = LLSD::emptyMap(); + CURLcode result = responder->result_code(); - // * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy) - if (method == LLURLRequest::HTTP_GET) + if (result == CURLE_OK && (http_status = responder->http_status()) == HTTP_OK) + { + response["body"] = responder->response(); + } + else if (result == CURLE_OK) + { + // We expect 404s, don't spam for them. + if (http_status != 404) { - curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1); - } - else if (method == LLURLRequest::HTTP_POST) - { - //copied from PHP libs, correct? - curlEasyRequest_w->addHeader("Content-Type: application/llsd+xml"); - LLSDSerialize::toXML(body, ostr); - curlEasyRequest_w->setPost(ostr.str().c_str(), ostr.str().length()); - } - - // * Do the action using curl, handle results - curlEasyRequest_w->addHeader("Accept: application/llsd+xml"); - curlEasyRequest_w->finalizeRequest(url); - - S32 curl_success = curlEasyRequest_w->perform(); - curlEasyRequest_w->getinfo(CURLINFO_RESPONSE_CODE, &http_status); - // if we get a non-404 and it's not a 200 OR maybe it is but you have error bits, - if ( http_status != 404 && (http_status != 200 || curl_success != 0) ) - { - // We expect 404s, don't spam for them. llwarns << "CURL REQ URL: " << url << llendl; llwarns << "CURL REQ METHOD TYPE: " << LLURLRequest::actionAsVerb(method) << llendl; - llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl; - llwarns << "CURL REQ BODY: " << ostr.str() << llendl; + llwarns << "CURL REQ HEADERS: " << headers << llendl; + if (method == LLURLRequest::HTTP_POST) + { + llwarns << "CURL REQ BODY: " << body.asString() << llendl; + } llwarns << "CURL HTTP_STATUS: " << http_status << llendl; - llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl; - response["body"] = http_buffer.asString(); - } - else - { - response["body"] = http_buffer.asLLSD(); - lldebugs << "CURL response: " << http_buffer.asString() << llendl; + llwarns << "CURL ERROR BODY: " << responder->body() << llendl; } + response["body"] = responder->body(); } - catch(AICurlNoEasyHandle const& error) + else { - response["body"] = error.what(); + response["body"] = responder->reason(); } -#endif response["status"] = http_status; return response; @@ -374,13 +372,13 @@ static LLSD blocking_request( LLSD LLHTTPClient::blockingGet(const std::string& url) { AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers, blockingGet_timeout); + return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers); } LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers, blockingPost_timeout); + return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers); } void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index 5ba0c5980..80a70a152 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -265,7 +265,7 @@ bool LLCurrencyUIManager::Impl::checkTransaction() return false; } - if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400) + if (mResponder->result_code() != CURLE_OK || mResponder->http_status() < 200 || mResponder->http_status() >= 400) { setError(mResponder->reason(), mResponder->getURL()); } diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index a5a1b62a2..2c1631987 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -863,7 +863,7 @@ bool LLFloaterBuyLandUI::checkTransaction() return false; } - if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400) + if (mResponder->result_code() != CURLE_OK || mResponder->http_status() < 200 || mResponder->http_status() >= 400) { tellUserError(mResponder->reason(), mResponder->getURL()); } diff --git a/indra/newview/llxmlrpcresponder.cpp b/indra/newview/llxmlrpcresponder.cpp index ddf4afee9..a19bcdd9e 100644 --- a/indra/newview/llxmlrpcresponder.cpp +++ b/indra/newview/llxmlrpcresponder.cpp @@ -158,14 +158,12 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) { - mCode = code; if (info) { mTransferInfo = *info; } - mStatus = status; - mReason = reason; - // Note: 'status' and 'reason' are the same as what is passed to completedRaw. + // Call base class implementation. + LegacyPolledResponder::completed_headers(status, reason, code, info); } void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) diff --git a/indra/newview/llxmlrpcresponder.h b/indra/newview/llxmlrpcresponder.h index 23973b6db..ffb06f14d 100644 --- a/indra/newview/llxmlrpcresponder.h +++ b/indra/newview/llxmlrpcresponder.h @@ -91,31 +91,20 @@ private: XMLRPC_VALUE mV; }; -class XMLRPCResponder : public LLCurl::Responder { +class XMLRPCResponder : public AICurlInterface::LegacyPolledResponder { private: - CURLcode mCode; - U32 mStatus; AICurlInterface::TransferInfo mTransferInfo; S32 mBufferSize; bool mReceivedHTTPHeader; - bool mFinished; - std::string mReason; XMLRPC_REQUEST mResponse; public: - XMLRPCResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mReceivedHTTPHeader(false), mFinished(false) { } - // Accessors. - CURLcode result_code(void) const { return mCode; } - U32 http_result(void) const { return mStatus; } F64 transferRate(void) const; bool is_downloading(void) const { return mReceivedHTTPHeader; } - bool is_finished(void) const { return mFinished; } - std::string const& reason(void) const { return mReason; } XMLRPC_REQUEST response(void) const { return mResponse; } LLXMLRPCValue responseValue(void) const; - /*virtual*/ bool needsHeaders(void) const { return true; } /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::Responder::received_HTTP_header(); } /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); From daac25c3434717842f7e7be6389867583e34c0a6 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 22 Oct 2012 20:31:33 +0200 Subject: [PATCH 49/64] Bug fix, introduced in commit 0bee4a92 --- indra/llcommon/llthread.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 5c1a29f24..9b2537d98 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -118,7 +118,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // the critical area of the mSignal lock)]. lldebugs << "LLThread::staticRun() Exiting: " << name << llendl; - --sRunning; // Would be better to do this after joining with the thread, but we don't join :/ return NULL; } From 243db9a3a8727b0da6ac8b32805e815fdab22c47 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 22 Oct 2012 22:52:18 +0200 Subject: [PATCH 50/64] Moved mFinished/is_finished() from LegacyPolledResponder to Responder. Slightly more robust, adds one boolean to all responders, 99% of which don't need that though, and an extra call redirection, but well... We might need it this way when I add the possibility to abort a transfer. --- indra/aistatemachine/aicurl.cpp | 4 +-- indra/aistatemachine/aicurl.h | 45 +++++++++++++++++---------- indra/aistatemachine/aicurlthread.cpp | 2 +- indra/llmessage/llhttpclient.cpp | 2 ++ indra/newview/llxmlrpcresponder.cpp | 1 - 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 65457cd80..537d12e2f 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -433,7 +433,7 @@ std::string strerror(CURLcode errorcode) // class Responder // -Responder::Responder(void) : mReferenceCount(0) +Responder::Responder(void) : mReferenceCount(0), mFinished(false) { DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); } @@ -1340,7 +1340,7 @@ CurlResponderBuffer::~CurlResponderBuffer() void CurlResponderBuffer::timed_out(void) { - mResponder->completedRaw(HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); + mResponder->finished(HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); mResponder = NULL; } diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 767a6dabc..53f7af394 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -215,6 +215,9 @@ class Responder : public AICurlResponderBufferEvents { // Headers received from the server. AIHTTPReceivedHeaders mReceivedHeaders; + // Set when the transaction finished (with or without errors). + bool mFinished; + public: // Called to set the URL of the current request for this Responder, // used only when printing debug output regarding activity of the Responder. @@ -223,6 +226,20 @@ class Responder : public AICurlResponderBufferEvents { // Accessor. std::string const& getURL(void) const { return mURL; } + // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. + void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + completedRaw(status, reason, channels, buffer); + mFinished = true; + } + + // Return true if the curl thread is done with this transaction. + // If this returns true then it is guaranteed that none of the + // virtual functions will be called anymore: the curl thread + // will not access this object anymore. + // Note that normally you don't need to call this function. + bool is_finished(void) const { return mFinished; } + protected: // Called when the "HTTP/1.x " header is received. /*virtual*/ void received_HTTP_header(void) @@ -244,12 +261,6 @@ class Responder : public AICurlResponderBufferEvents { completedHeaders(status, reason, mReceivedHeaders); } - // Derived classes can override this to get the HTML headers that were received, when the message is completed. - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) - { - // The default does nothing. - } - public: // Derived classes that implement completed_headers()/completedHeaders() should return true here. virtual bool needsHeaders(void) const { return false; } @@ -257,15 +268,21 @@ class Responder : public AICurlResponderBufferEvents { // Timeout policy to use. virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; - // Derived classes can override this to get the raw data of the body of the HTML message that was received. - // The default is to interpret the content as LLSD and call completed(). - virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); - // A derived class should return true if curl should follow redirections. // The default is not to follow redirections. virtual bool followRedir(void) { return false; } protected: + // Derived classes can override this to get the HTML headers that were received, when the message is completed. + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + { + // The default does nothing. + } + + // Derived classes can override this to get the raw data of the body of the HTML message that was received. + // The default is to interpret the content as LLSD and call completed(). + virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // ... or, derived classes can override this to get the LLSD content when the message is completed. // The default is to call result() (or errorWithContent() in case of a HTML status indicating an error). virtual void completed(U32 status, std::string const& reason, LLSD const& content); @@ -278,7 +295,7 @@ class Responder : public AICurlResponderBufferEvents { // The default calls error(). virtual void errorWithContent(U32 status, std::string const& reason, LLSD const& content); - // ... or, derived classes can override this to get informed when a bad HTML statis code is received. + // ... or, derived classes can override this to get informed when a bad HTML status code is received. // The default prints the error to llinfos. virtual void error(U32 status, std::string const& reason); @@ -311,21 +328,17 @@ class LegacyPolledResponder : public Responder { CURLcode mCode; U32 mStatus; std::string mReason; - bool mFinished; public: - LegacyPolledResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mFinished(false) { } + LegacyPolledResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR) { } // Accessors. CURLcode result_code(void) const { return mCode; } U32 http_status(void) const { return mStatus; } - bool is_finished(void) const { return mFinished; } std::string const& reason(void) const { return mReason; } /*virtual*/ bool needsHeaders(void) const { return true; } /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); - // This must be defined by the derived class and set mFinished = true at the end. - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; }; } // namespace AICurlInterface diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index e03d92e7f..61a1a1961 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -2109,7 +2109,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request // the body and provide completed/result/error calls. mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); } - mResponder->completedRaw(responseCode, responseReason, sChannels, mOutput); + mResponder->finished(responseCode, responseReason, sChannels, mOutput); mResponder = NULL; } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 6f7db978d..26c7b39e0 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -258,6 +258,8 @@ void BlockingResponder::completedRaw(U32, std::string const&, LLChannelDescripto mBody << istr; } } + // Normally mFinished is set immediately after returning from this function, + // but we do it here, because we need to set it before calling mSignal.signal(). mSignal.lock(); mFinished = true; mSignal.unlock(); diff --git a/indra/newview/llxmlrpcresponder.cpp b/indra/newview/llxmlrpcresponder.cpp index a19bcdd9e..a66b0a1f7 100644 --- a/indra/newview/llxmlrpcresponder.cpp +++ b/indra/newview/llxmlrpcresponder.cpp @@ -205,7 +205,6 @@ void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChan } } } - mFinished = true; } LLXMLRPCValue XMLRPCResponder::responseValue(void) const From 33809f56c53a937c3faa9cfc8ca02b24efc6fef0 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 25 Oct 2012 02:17:40 +0200 Subject: [PATCH 51/64] Comment out unused code. --- indra/newview/llinventorymodel.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index ab88171ef..b4aa322a6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -567,14 +567,15 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { //Let's use the new capability. - LLSD request, body; +// LLSD request; + LLSD body; body["folder_id"] = id; body["parent_id"] = parent_id; body["type"] = (LLSD::Integer) preferred_type; body["name"] = name; - request["message"] = "CreateInventoryCategory"; - request["payload"] = body; +// request["message"] = "CreateInventoryCategory"; +// request["payload"] = body; // viewer_region->getCapAPI().post(request); LLHTTPClient::post4( From 2a88f7d7c47de9d2c85309b4a37a2efc29d956d8 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 26 Oct 2012 03:47:05 +0200 Subject: [PATCH 52/64] ResponderAdapter stuff Renamed AICurlInterface::Responder to AICurlInterface::ResponderBase, but without the virtual 'event' methods. Derived from that: Responder and ReponderWithCompleted, where the first defines result = 0, ErrorWithContent and error, and the latter completedRaw and completed. Added HttpClient::IgnoreBody, derived from Responder and implementing 'result' doing nothing; HttpClient::Ignore is now derived from IgnoreBody and defines the still pure virtual getHTTPTimeoutPolicy. Added ResponderBase::decode_body, which is now the sole place where the code makes the decision wether some response data might be LLSD or not based on the http status result. Before it just tried to decode everything as LLSD, which seems a bit nonsense. ResponderWithCompleted::completed no longer does anything, since classes derived from ResponderWithCompleted are expected to override it, or never call it by overriding completedRaw. Entry point is now ResponderBase::finished = 0, instead of completedRaw, where ResponderWithCompleted implements finished by called completedRaw, but Responder doesn't: that directly calls result/errorWithContent/error. Or, for the hack ResponderAdapter, the entry points are pubResult/pubErrorWithContent. Those are now the ONLY public methods, so more confusion. mFinished is now set in all cases. As a result of all that, it is no longer possible to accidently pass a responder to ResponderAdapter that would break because it expects completed() and completedRaw() to be called. Added LLBufferArray::writeChannelTo. Fixed bug for BlockingResponder::body (returned reference to temporary). LLSDMessage::ResponderAdapter now allows a "timeoutpolicy" name to be passed (not doing so results in the default timings), so that the timeout policy of the used responder is retained. Fixed llfasttimerview.cpp to test LLSDSerialize::fromXML() to return a positive value instead of non-zero, because it may return -1 when the parsing fails (three places). Removed LLHTTPClient::Responder as base class from LLFloaterRegionDebugConsole completely: it isn't a responder! Several other responder classes were simplified a bit in order to compile again with the above changes. --- indra/aistatemachine/aicurl.cpp | 81 ++++++++++++++----- indra/aistatemachine/aicurl.h | 76 ++++++++++++----- indra/llmessage/aihttptimeoutpolicy.cpp | 21 ++++- indra/llmessage/aihttptimeoutpolicy.h | 4 + indra/llmessage/llbuffer.cpp | 14 ++++ indra/llmessage/llbuffer.h | 6 ++ indra/llmessage/llcurlrequest.h | 4 +- indra/llmessage/llhttpclient.cpp | 23 ++---- indra/llmessage/llhttpclient.h | 4 +- indra/llmessage/llsdmessage.cpp | 49 +++++++---- indra/llmessage/llsdmessage.h | 18 ++--- indra/newview/lggdicdownload.cpp | 2 +- indra/newview/llagent.cpp | 1 + indra/newview/llcapabilitylistener.cpp | 19 ++--- indra/newview/lleventpoll.cpp | 26 +----- indra/newview/llfasttimerview.cpp | 6 +- indra/newview/llfloateractivespeakers.cpp | 6 +- indra/newview/llfloaterregiondebugconsole.cpp | 2 +- indra/newview/llfloaterregiondebugconsole.h | 4 +- indra/newview/llfloaterurlentry.cpp | 2 +- indra/newview/llimpanel.cpp | 4 +- indra/newview/llmeshrepository.cpp | 10 +-- indra/newview/llpanellogin.cpp | 19 ++--- indra/newview/lltexturefetch.cpp | 2 +- indra/newview/llviewerdisplayname.cpp | 2 +- indra/newview/llviewermedia.cpp | 6 +- indra/newview/llxmlrpcresponder.h | 2 +- 27 files changed, 244 insertions(+), 169 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 537d12e2f..c45c6f214 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -430,50 +430,92 @@ std::string strerror(CURLcode errorcode) } //----------------------------------------------------------------------------- -// class Responder +// class ResponderBase // -Responder::Responder(void) : mReferenceCount(0), mFinished(false) +ResponderBase::ResponderBase(void) : mReferenceCount(0), mFinished(false) { DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); } -Responder::~Responder() +ResponderBase::~ResponderBase() { - DoutEntering(dc::curl, "AICurlInterface::Responder::~Responder() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount); + DoutEntering(dc::curl, "AICurlInterface::ResponderBase::~ResponderBase() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount); llassert(mReferenceCount == 0); } -void Responder::setURL(std::string const& url) +void ResponderBase::setURL(std::string const& url) { // setURL is called from llhttpclient.cpp (request()), before calling any of the below (of course). // We don't need locking here therefore; it's a case of initializing before use. mURL = url; } -AIHTTPTimeoutPolicy const& Responder::getHTTPTimeoutPolicy(void) const +AIHTTPTimeoutPolicy const& ResponderBase::getHTTPTimeoutPolicy(void) const { return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); } +void ResponderBase::decode_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) +{ + // If the status indicates success (and we get here) then we expect the body to be LLSD. + bool const should_be_llsd = (200 <= status && status < 300); + if (should_be_llsd) + { + LLBufferStream istr(channels, buffer.get()); + if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE) + { + // Unfortunately we can't show the body of the message... I think this is a pretty serious error + // though, so if this ever happens it has to be investigated by making a copy of the buffer + // before serializing it, as is done below. + llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; + } + // LLSDSerialize::fromXML destructed buffer, we can't initialize content now. + return; + } + // Put the body in content as-is. + std::stringstream ss; + buffer->writeChannelTo(ss, channels.in()); + content = ss.str(); +#ifdef SHOW_ASSERT + if (!should_be_llsd) + { + // Make sure that the server indeed never returns LLSD as body when the http status is an error. + LLSD dummy; + bool server_sent_llsd_with_http_error = LLSDSerialize::fromXML(dummy, ss) > 0; + if (server_sent_llsd_with_http_error) + { + llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl; + } + llassert(!server_sent_llsd_with_http_error); + } +#endif +} + // Called with HTML body. // virtual -void Responder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer) +void ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { LLSD content; - LLBufferStream istr(channels, buffer.get()); - if (!LLSDSerialize::fromXML(content, istr)) - { - llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; - } + decode_body(status, reason, channels, buffer, content); // Allow derived class to override at this point. completed(status, reason, content); } // virtual -void Responder::completed(U32 status, std::string const& reason, LLSD const& content) +void ResponderWithCompleted::completed(U32 status, std::string const& reason, LLSD const& content) { + // Either completedRaw() or this method must be overridden by the derived class. Hence, we should never get here. + llassert_always(false); +} + +// virtual +void Responder::finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +{ + LLSD content; + decode_body(status, reason, channels, buffer, content); + // HTML status good? if (200 <= status && status < 300) { @@ -485,6 +527,7 @@ void Responder::completed(U32 status, std::string const& reason, LLSD const& con // Allow derived class to override at this point. errorWithContent(status, reason, content); } + mFinished = true; } // virtual @@ -500,20 +543,14 @@ void Responder::error(U32 status, std::string const& reason) llinfos << mURL << " [" << status << "]: " << reason << llendl; } -// virtual -void Responder::result(LLSD const&) -{ - // Nothing. -} - // Friend functions. -void intrusive_ptr_add_ref(Responder* responder) +void intrusive_ptr_add_ref(ResponderBase* responder) { responder->mReferenceCount++; } -void intrusive_ptr_release(Responder* responder) +void intrusive_ptr_release(ResponderBase* responder) { if (--responder->mReferenceCount == 0) { @@ -528,7 +565,7 @@ void LegacyPolledResponder::completed_headers(U32 status, std::string const& rea mStatus = status; mReason = reason; // Call base class implementation. - Responder::completed_headers(status, reason, code, info); + ResponderBase::completed_headers(status, reason, code, info); } } // namespace AICurlInterface diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 53f7af394..7a679d6f6 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -200,13 +200,16 @@ void setCAPath(std::string const& file); // destructed. Also, if any of those are destructed then the Responder is automatically // destructed too. // -class Responder : public AICurlResponderBufferEvents { +class ResponderBase : public AICurlResponderBufferEvents { public: typedef boost::shared_ptr buffer_ptr_t; protected: - Responder(void); - virtual ~Responder(); + ResponderBase(void); + virtual ~ResponderBase(); + + // Read body from buffer and put it into content. If status indicates success, interpret it as LLSD, otherwise copy it as-is. + void decode_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); protected: // Associated URL, used for debug output. @@ -227,11 +230,7 @@ class Responder : public AICurlResponderBufferEvents { std::string const& getURL(void) const { return mURL; } // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. - void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - completedRaw(status, reason, channels, buffer); - mFinished = true; - } + virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; // Return true if the curl thread is done with this transaction. // If this returns true then it is guaranteed that none of the @@ -279,6 +278,25 @@ class Responder : public AICurlResponderBufferEvents { // The default does nothing. } + private: + // Used by ResponderPtr. Object is deleted when reference count reaches zero. + LLAtomicU32 mReferenceCount; + + friend void intrusive_ptr_add_ref(ResponderBase* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. + friend void intrusive_ptr_release(ResponderBase* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. + // This function must delete the ResponderBase object when the reference count reaches zero. +}; + +class ResponderWithCompleted : public ResponderBase { + protected: + virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + // Allow classes derived from ResponderBase to override completedRaw + // (if not they should override completed or be derived from Responder instead). + completedRaw(status, reason, channels, buffer); + mFinished = true; + } + // Derived classes can override this to get the raw data of the body of the HTML message that was received. // The default is to interpret the content as LLSD and call completed(). virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); @@ -287,9 +305,25 @@ class Responder : public AICurlResponderBufferEvents { // The default is to call result() (or errorWithContent() in case of a HTML status indicating an error). virtual void completed(U32 status, std::string const& reason, LLSD const& content); +#ifdef SHOW_ASSERT + // Responders derived from this class must override either completedRaw or completed. + // They may not attempt to override any of the virual functions defined by Responder. + // Define those functions here with different parameter in order to cause a compile + // warning when a class accidently tries to override them. + enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; + virtual void result(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void errorWithContent(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void error(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } +#endif +}; + +class Responder : public ResponderBase { + protected: + virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // ... or, derived classes can override this to received the content of a body upon success. // The default does nothing. - virtual void result(LLSD const& content); + virtual void result(LLSD const& content) = 0; // Derived classes can override this to get informed when a bad HTML status code is received. // The default calls error(). @@ -303,27 +337,29 @@ class Responder : public AICurlResponderBufferEvents { // Called from LLSDMessage::ResponderAdapter::listener. // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that these functions need to be public. - void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); } - void pubResult(LLSD const& content) { result(content); } + void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); mFinished = true; } + void pubResult(LLSD const& content) { result(content); mFinished = true; } - private: - // Used by ResponderPtr. Object is deleted when reference count reaches zero. - LLAtomicU32 mReferenceCount; - - friend void intrusive_ptr_add_ref(Responder* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. - friend void intrusive_ptr_release(Responder* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. - // This function must delete the Responder object when the reference count reaches zero. +#ifdef SHOW_ASSERT + // Responders derived from this class must override result, and either errorWithContent or error. + // They may not attempt to override any of the virual functions defined by ResponderWithCompleted. + // Define those functions here with different parameter in order to cause a compile + // warning when a class accidently tries to override them. + enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; + virtual void completedRaw(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void completed(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } +#endif }; // A Responder is passed around as ResponderPtr, which causes it to automatically // destruct when there are no pointers left pointing to it. -typedef boost::intrusive_ptr ResponderPtr; +typedef boost::intrusive_ptr ResponderPtr; // Same as above except that this class stores the result, allowing old polling // code to poll if the transaction finished by calling is_finished() (from the // main the thread) and then access the results-- as opposed to immediately // digesting the results when any of the virtual functions are called. -class LegacyPolledResponder : public Responder { +class LegacyPolledResponder : public ResponderWithCompleted { protected: CURLcode mCode; U32 mStatus; diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 1a601db07..7db472f96 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -186,6 +186,7 @@ AIHTTPTimeoutPolicy::AIHTTPTimeoutPolicy(char const* name, AIHTTPTimeoutPolicyBa mMaximumCurlTransaction(mBase->mMaximumCurlTransaction), mMaximumTotalDelay(mBase->mMaximumTotalDelay) { + sNameMap.insert(namemap_t::value_type(name, this)); // Register for changes to the base policy. mBase->derived(this); } @@ -645,6 +646,24 @@ AIHTTPTimeoutPolicyBase connect_40s(AIHTTPTimeoutPolicyBase::getDebugSettingsCur // End of policy definitions. //======================================================================================================= +//static +AIHTTPTimeoutPolicy::namemap_t AIHTTPTimeoutPolicy::sNameMap; + +//static +AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::string const& name) +{ + namemap_t::iterator iter = sNameMap.find(name); + if (iter == sNameMap.end()) + { + if (!name.empty()) + { + llwarns << "Cannot find AIHTTPTimeoutPolicy with name \"" << name << "\"." << llendl; + } + return &sDebugSettingsCurlTimeout; + } + return iter->second; +} + //======================================================================================================= // Start of Responder timeout policy list. @@ -674,9 +693,7 @@ P(environmentApplyResponder); P(environmentRequestResponder); P(estateChangeInfoResponder); P(eventPollResponder); -P(eventResponder); P(fetchInventoryResponder); -P(floaterRegionDebugConsole); P(fnPtrResponder); P2(groupProposalBallotResponder, transfer_300s); P(homeLocationResponder); diff --git a/indra/llmessage/aihttptimeoutpolicy.h b/indra/llmessage/aihttptimeoutpolicy.h index bb11b033a..bf333b105 100644 --- a/indra/llmessage/aihttptimeoutpolicy.h +++ b/indra/llmessage/aihttptimeoutpolicy.h @@ -33,6 +33,7 @@ #include "stdtypes.h" #include +#include class AIHTTPTimeoutPolicyBase; @@ -52,6 +53,8 @@ class AIHTTPTimeoutPolicy { char const* const mName; // The name of this policy, for debugging purposes. AIHTTPTimeoutPolicyBase* const mBase; // Policy this policy was based on. static AIHTTPTimeoutPolicyBase sDebugSettingsCurlTimeout; // CurlTimeout* debug settings. + typedef std::map namemap_t; // Type of sNameMap. + static namemap_t sNameMap; // Map of name of timeout policies (as returned by name()) to AIHTTPTimeoutPolicy* (this). private: U16 mDNSLookupGrace; // Extra connect timeout the first time we connect to a host (this is to allow for DNS lookups). @@ -97,6 +100,7 @@ class AIHTTPTimeoutPolicy { U16 getCurlTransaction(void) const { return mMaximumCurlTransaction; } U16 getTotalDelay(void) const { return mMaximumTotalDelay; } static AIHTTPTimeoutPolicy const& getDebugSettingsCurlTimeout(void); + static AIHTTPTimeoutPolicy const* getTimeoutPolicyByName(std::string const& name); // Called once at start up of viewer to set a different default timeout policy than HTTPTimeoutPolicy_default. static void setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& defaultCurlTimeout); diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 0f31f7065..b9ca7ceb6 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -650,6 +650,20 @@ U8* LLBufferArray::readAfter( return rv; } +void LLBufferArray::writeChannelTo(std::ostream& ostr, S32 channel) const +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + LLMutexLock lock(mMutexp) ; + const_segment_iterator_t const end = mSegments.end(); + for (const_segment_iterator_t it = mSegments.begin(); it != end; ++it) + { + if (it->isOnChannel(channel)) + { + ostr.write((char*)it->data(), it->size()); + } + } +} + U8* LLBufferArray::seek( S32 channel, U8* start, diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index 4940da2fe..c7624bde3 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -592,6 +592,12 @@ public: void setThreaded(bool threaded); //@} + /** + * @brief Read channel channel of LLBufferArray and write it to ostr. + * This is a Singularity extension. + */ + void writeChannelTo(std::ostream& ostr, S32 channel) const; + protected: /** * @brief Optimally put data in buffers, and reutrn segments. diff --git a/indra/llmessage/llcurlrequest.h b/indra/llmessage/llcurlrequest.h index d30418abd..4fe172b46 100644 --- a/indra/llmessage/llcurlrequest.h +++ b/indra/llmessage/llcurlrequest.h @@ -41,8 +41,8 @@ class AIHTTPHeaders; namespace AICurlInterface { // Forward declaration. -class Responder; -typedef boost::intrusive_ptr ResponderPtr; +class ResponderBase; +typedef boost::intrusive_ptr ResponderPtr; class Request { public: diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 26c7b39e0..96a38ea10 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -234,30 +234,17 @@ class BlockingResponder : public AICurlInterface::LegacyPolledResponder { private: LLCondition mSignal; LLSD mResponse; - std::ostringstream mBody; public: void wait(void); LLSD const& response(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } - std::string const& body(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus != HTTP_OK); return mBody.str(); } /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); }; -void BlockingResponder::completedRaw(U32, std::string const&, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +void BlockingResponder::completedRaw(U32, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - if (mCode == CURLE_OK) - { - LLBufferStream istr(channels, buffer.get()); - if (mStatus == HTTP_OK) - { - LLSDSerialize::fromXML(mResponse, istr); - } - else - { - mBody << istr; - } - } + decode_body(mCode, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. // Normally mFinished is set immediately after returning from this function, // but we do it here, because we need to set it before calling mSignal.signal(). mSignal.lock(); @@ -341,7 +328,7 @@ static LLSD blocking_request( LLSD response = LLSD::emptyMap(); CURLcode result = responder->result_code(); - if (result == CURLE_OK && (http_status = responder->http_status()) == HTTP_OK) + if (result == CURLE_OK && (http_status = responder->http_status()) >= 200 && http_status < 300) { response["body"] = responder->response(); } @@ -358,9 +345,9 @@ static LLSD blocking_request( llwarns << "CURL REQ BODY: " << body.asString() << llendl; } llwarns << "CURL HTTP_STATUS: " << http_status << llendl; - llwarns << "CURL ERROR BODY: " << responder->body() << llendl; + llwarns << "CURL ERROR BODY: " << responder->response().asString() << llendl; } - response["body"] = responder->body(); + response["body"] = responder->response().asString(); } else { diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index d6ffad888..c78917a82 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -53,8 +53,8 @@ public: typedef LLCurl::Responder Responder; typedef LLCurl::ResponderPtr ResponderPtr; - // The default actually already ignores responses. - class ResponderIgnore : public Responder { virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} }; + class ResponderIgnoreBody : public Responder { void result(LLSD const&) { } }; + class ResponderIgnore : public ResponderIgnoreBody { virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} }; /** @name non-blocking API */ //@{ diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 441355b3b..be968c5db 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -45,6 +45,7 @@ #include "llhost.h" #include "message.h" #include "llsdutil.h" +#include "aihttptimeoutpolicy.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. @@ -62,13 +63,15 @@ LLSDMessage::LLSDMessage(): bool LLSDMessage::httpListener(const LLSD& request) { + llassert(false); // This function is never called. --Aleric + // 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"]); + LLSD::String timeoutpolicy(request["timeoutpolicy"]); // If the LLSD doesn't even have a "url" key, we doubt it was intended for // this listener. if (url.empty()) @@ -77,21 +80,25 @@ bool LLSDMessage::httpListener(const LLSD& request) out << "request event without 'url' key to '" << mEventPump.getName() << "'"; throw ArgError(out.str()); } -#if 0 // AIFIXME: ignore this for now - // Establish default timeout. This test relies on LLSD::asReal() returning - // exactly 0.0 for an undef value. - if (! timeout) - { - timeout = HTTP_REQUEST_EXPIRY_SECS; - } -#endif - LLHTTPClient::post4(url, payload, - new LLSDMessage::EventResponder(LLEventPumps::instance(), - request, - url, "POST", reply, error)); + LLSDMessage::EventResponder* responder = + new LLSDMessage::EventResponder(LLEventPumps::instance(), request, url, "POST", reply, error); + responder->setTimeoutPolicy(timeoutpolicy); + LLHTTPClient::post4(url, payload, responder); return false; } +LLSDMessage::EventResponder::EventResponder(LLEventPumps& pumps, LLSD const& request, std::string const& target, + std::string const& message, std::string const& replyPump, std::string const& errorPump) : + mPumps(pumps), mReqID(request), mTarget(target), mMessage(message), mReplyPump(replyPump), mErrorPump(errorPump), + mHTTPTimeoutPolicy(AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::string())) +{ +} + +void LLSDMessage::EventResponder::setTimeoutPolicy(std::string const& name) +{ + mHTTPTimeoutPolicy = AIHTTPTimeoutPolicy::getTimeoutPolicyByName(name); +} + void LLSDMessage::EventResponder::result(const LLSD& data) { // If our caller passed an empty replyPump name, they're not @@ -137,7 +144,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string } } -LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderPtr responder, +LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::Responder* responder, const std::string& name): mResponder(responder), mReplyPump(name + ".reply", true), // tweak name for uniqueness @@ -147,15 +154,25 @@ LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderPtr respo mErrorPump.listen("self", boost::bind(&ResponderAdapter::listener, this, _1, false)); } +std::string LLSDMessage::ResponderAdapter::getTimeoutPolicyName(void) const +{ + return mResponder->getHTTPTimeoutPolicy().name(); +} + bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) { + AICurlInterface::Responder* responder = dynamic_cast(mResponder.get()); + // If this assertion fails then ResponderAdapter has been used for a ResponderWithCompleted derived class, + // which is not allowed because ResponderAdapter can only work for classes derived from Responder that + // implement result() and errorWithContent (or just error). + llassert_always(responder); if (success) { - mResponder->pubResult(payload); + responder->pubResult(payload); } else { - mResponder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); + responder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); } /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 3d1ae814c..b839cbc74 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -90,13 +90,15 @@ public: * interesting if you suspect some usage will lead to an exception or * log message. */ - ResponderAdapter(LLHTTPClient::ResponderPtr responder, + ResponderAdapter(LLHTTPClient::Responder* 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(); } + /// Name of timeout policy to use. + std::string getTimeoutPolicyName() const; private: // We have two different LLEventStreams, though we route them both to @@ -126,7 +128,7 @@ private: class EventResponder: public LLHTTPClient::Responder { public: - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventResponder_timeout; } + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return *mHTTPTimeoutPolicy; } /** * LLHTTPClient::Responder that dispatches via named LLEventPump instances. @@ -144,14 +146,9 @@ private: 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) - {} + const std::string& replyPump, const std::string& errorPump); + + void setTimeoutPolicy(std::string const& name); virtual void result(const LLSD& data); virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); @@ -160,6 +157,7 @@ private: LLEventPumps& mPumps; LLReqID mReqID; const std::string mTarget, mMessage, mReplyPump, mErrorPump; + AIHTTPTimeoutPolicy const* mHTTPTimeoutPolicy; }; private: diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index 7bcaaac49..154d29063 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -52,7 +52,7 @@ class lggDicDownloadFloater; class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy emeraldDicDownloader_timeout; -class EmeraldDicDownloader : public LLHTTPClient::Responder +class EmeraldDicDownloader : public AICurlInterface::ResponderWithCompleted { public: EmeraldDicDownloader(lggDicDownloadFloater* spanel, std::string sname); diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3a3c38c20..b2e1c2181 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2188,6 +2188,7 @@ void LLAgent::setStartPosition( U32 location_id ) request["payload"] = body; request["reply"] = adapter->getReplyName(); request["error"] = adapter->getErrorName(); + request["timeoutpolicy"] = adapter->getTimeoutPolicyName(); gAgent.getRegion()->getCapAPI().post(request); diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp index 75934c156..2ebaffd4f 100644 --- a/indra/newview/llcapabilitylistener.cpp +++ b/indra/newview/llcapabilitylistener.cpp @@ -84,7 +84,7 @@ bool LLCapabilityListener::capListener(const LLSD& request) LLSD payload(request["payload"]); LLSD::String reply(request["reply"]); LLSD::String error(request["error"]); - LLSD::Real timeout(request["timeout"]); + LLSD::String timeoutpolicy(request["timeoutpolicy"]); // If the LLSD doesn't even have a "message" key, we doubt it was intended // for this listener. if (cap.empty()) @@ -95,24 +95,15 @@ bool LLCapabilityListener::capListener(const LLSD& request) << LL_ENDL; return false; // in case fatal-error function isn't } -#if 0 // AIFIXME: ignore this for now - // Establish default timeout. This test relies on LLSD::asReal() returning - // exactly 0.0 for an undef value. - if (! timeout) - { - timeout = HTTP_REQUEST_EXPIRY_SECS; - } -#endif // Look up the url for the requested capability name. std::string url = mProvider.getCapability(cap); if (! url.empty()) { + LLSDMessage::EventResponder* responder = + new LLSDMessage::EventResponder(LLEventPumps::instance(), request, mProvider.getDescription(), cap, reply, error); + responder->setTimeoutPolicy(timeoutpolicy); // This capability is supported by the region to which we're talking. - LLHTTPClient::post4(url, payload, - new LLSDMessage::EventResponder(LLEventPumps::instance(), - request, - mProvider.getDescription(), - cap, reply, error)); + LLHTTPClient::post4(url, payload, responder); } else { diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index e7442483f..be7ede224 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -73,14 +73,10 @@ namespace void handleMessage(const LLSD& content); - virtual void error(U32 status, const std::string& reason); + virtual void error(U32 status, const std::string& reason); virtual void result(const LLSD& content); virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventPollResponder_timeout; } - virtual void completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer); private: bool mDone; @@ -160,24 +156,6 @@ namespace << mPollURL << llendl; } - // virtual - void LLEventPollResponder::completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) - { - if (status == HTTP_BAD_GATEWAY) - { - // These errors are not parsable as LLSD, - // which LLHTTPClient::Responder::completedRaw will try to do. - completed(status, reason, LLSD()); - } - else - { - LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer); - } - } - void LLEventPollResponder::makeRequest() { LLSD request; @@ -295,7 +273,7 @@ LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender) LLEventPoll::~LLEventPoll() { - LLHTTPClient::Responder* responderp = mImpl.get(); + AICurlInterface::ResponderBase* responderp = mImpl.get(); LLEventPollResponder* event_poll_responder = dynamic_cast(responderp); if (event_poll_responder) event_poll_responder->stop(); } diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index eeb53a98d..9f1cbca6c 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1146,7 +1146,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t { //read base log into memory S32 i = 0; std::ifstream is(base.c_str()); - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + while (!is.eof() && LLSDSerialize::fromXML(cur, is) > 0) { base_data[i++] = cur; } @@ -1159,7 +1159,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t { //read current log into memory S32 i = 0; std::ifstream is(target.c_str()); - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + while (!is.eof() && LLSDSerialize::fromXML(cur, is) > 0) { cur_data[i++] = cur; @@ -1450,7 +1450,7 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is) stats_map_t time_stats; stats_map_t sample_stats; - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + while (!is.eof() && LLSDSerialize::fromXML(cur, is) > 0) { for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) { diff --git a/indra/newview/llfloateractivespeakers.cpp b/indra/newview/llfloateractivespeakers.cpp index 3b8bde610..968228fb2 100644 --- a/indra/newview/llfloateractivespeakers.cpp +++ b/indra/newview/llfloateractivespeakers.cpp @@ -849,7 +849,7 @@ void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data // ctrl value represents ability to type, so invert data["params"]["mute_info"]["voice"] = !ctrl->getValue(); - class MuteVoiceResponder : public LLHTTPClient::Responder + class MuteVoiceResponder : public LLHTTPClient::ResponderIgnoreBody { public: MuteVoiceResponder(const LLUUID& session_id) @@ -916,7 +916,7 @@ void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data) // ctrl value represents ability to type, so invert data["params"]["mute_info"]["text"] = !ctrl->getValue(); - class MuteTextResponder : public LLHTTPClient::Responder + class MuteTextResponder : public LLHTTPClient::ResponderIgnoreBody { public: MuteTextResponder(const LLUUID& session_id) @@ -990,7 +990,7 @@ void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_da data["params"]["update_info"]["moderated_mode"]["voice"] = true; } - struct ModerationModeResponder : public LLHTTPClient::Responder + struct ModerationModeResponder : public LLHTTPClient::ResponderIgnoreBody { virtual void error(U32 status, const std::string& reason) { diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index ad3e873eb..e0720d2b0 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -77,7 +77,7 @@ namespace // we assume that the simulator has received our request. Error will be // called if this request times out. // - class AsyncConsoleResponder : public LLHTTPClient::Responder + class AsyncConsoleResponder : public LLHTTPClient::ResponderIgnoreBody { public: /* virtual */ diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h index 2636b6426..fdf975c48 100644 --- a/indra/newview/llfloaterregiondebugconsole.h +++ b/indra/newview/llfloaterregiondebugconsole.h @@ -40,14 +40,12 @@ extern AIHTTPTimeoutPolicy floaterRegionDebugConsole_timeout; typedef boost::signals2::signal< void (const std::string& output)> console_reply_signal_t; -class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Responder, public LLSingleton +class LLFloaterRegionDebugConsole : public LLFloater, public LLSingleton { public: LLFloaterRegionDebugConsole(); virtual ~LLFloaterRegionDebugConsole(); - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return floaterRegionDebugConsole_timeout; } - // virtual BOOL postBuild(); void onClose(bool app_quitting); diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index f43619553..416458617 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -53,7 +53,7 @@ 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 +class LLMediaTypeResponder : public LLHTTPClient::ResponderIgnoreBody { public: LLMediaTypeResponder( const LLHandle parent ) : diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 2d5ee2293..fe1bab58a 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -184,7 +184,7 @@ void start_deprecated_conference_chat( delete[] bucket; } -class LLStartConferenceChatResponder : public LLHTTPClient::Responder +class LLStartConferenceChatResponder : public LLHTTPClient::ResponderIgnoreBody { public: LLStartConferenceChatResponder( @@ -1558,7 +1558,7 @@ void LLFloaterIMPanel::draw() LLFloater::draw(); } -class LLSessionInviteResponder : public LLHTTPClient::Responder +class LLSessionInviteResponder : public LLHTTPClient::ResponderIgnoreBody { public: LLSessionInviteResponder(const LLUUID& session_id) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index cc2b7306f..cd406e3c5 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -210,7 +210,7 @@ S32 LLMeshRepoThread::sActiveHeaderRequests = 0; S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; -class LLMeshHeaderResponder : public LLCurl::Responder +class LLMeshHeaderResponder : public LLCurl::ResponderWithCompleted { public: LLVolumeParams mMeshParams; @@ -233,7 +233,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshHeaderResponder_timeout; } }; -class LLMeshLODResponder : public LLCurl::Responder +class LLMeshLODResponder : public LLCurl::ResponderWithCompleted { public: LLVolumeParams mMeshParams; @@ -259,7 +259,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshLODResponder_timeout; } }; -class LLMeshSkinInfoResponder : public LLCurl::Responder +class LLMeshSkinInfoResponder : public LLCurl::ResponderWithCompleted { public: LLUUID mMeshID; @@ -278,7 +278,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshSkinInfoResponder_timeout; } }; -class LLMeshDecompositionResponder : public LLCurl::Responder +class LLMeshDecompositionResponder : public LLCurl::ResponderWithCompleted { public: LLUUID mMeshID; @@ -297,7 +297,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshDecompositionResponder_timeout; } }; -class LLMeshPhysicsShapeResponder : public LLCurl::Responder +class LLMeshPhysicsShapeResponder : public LLCurl::ResponderWithCompleted { public: LLUUID mMeshID; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index a10e9f0cb..1bfbcc702 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -168,7 +168,7 @@ std::string gFullName; // 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 LLIamHereLogin : public LLHTTPClient::Responder +class LLIamHereLogin : public AICurlInterface::ResponderWithCompleted { private: LLIamHereLogin( LLPanelLogin* parent ) : @@ -193,20 +193,11 @@ class LLIamHereLogin : public LLHTTPClient::Responder const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - completed(status, reason, LLSD()); // will call result() or error() + if (mParent) + { + mParent->setSiteIsAlive(200 <= status && status < 300); + } } - - virtual void result( const LLSD& content ) - { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; - - virtual void error( U32 status, const std::string& reason ) - { - if ( mParent ) - mParent->setSiteIsAlive( false ); - }; virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereLogin_timeout; } }; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 159110fc0..561c19129 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -292,7 +292,7 @@ private: }; ////////////////////////////////////////////////////////////////////////////// -class HTTPGetResponder : public LLCurl::Responder +class HTTPGetResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(HTTPGetResponder); public: diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index e5590de87..d4a89d3a4 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -58,7 +58,7 @@ namespace LLViewerDisplayName } -class LLSetDisplayNameResponder : public LLHTTPClient::Responder +class LLSetDisplayNameResponder : public LLHTTPClient::ResponderIgnoreBody { public: // only care about errors diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 25acb0b83..b818ae50c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -71,7 +71,7 @@ const int RIGHT_BUTTON = 1; /////////////////////////////////////////////////////////////////////////////// // 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 +class LLMimeDiscoveryResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(LLMimeDiscoveryResponder); public: @@ -111,7 +111,7 @@ public: bool mInitialized; }; -class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +class LLViewerMediaOpenIDResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(LLViewerMediaOpenIDResponder); public: @@ -150,7 +150,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaOpenIDResponder_timeout; } }; -class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder +class LLViewerMediaWebProfileResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(LLViewerMediaWebProfileResponder); public: diff --git a/indra/newview/llxmlrpcresponder.h b/indra/newview/llxmlrpcresponder.h index ffb06f14d..c52756f03 100644 --- a/indra/newview/llxmlrpcresponder.h +++ b/indra/newview/llxmlrpcresponder.h @@ -105,7 +105,7 @@ public: XMLRPC_REQUEST response(void) const { return mResponse; } LLXMLRPCValue responseValue(void) const; - /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::Responder::received_HTTP_header(); } + /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::ResponderBase::received_HTTP_header(); } /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return XMLRPCResponder_timeout; } From 65e012c54098b054131faef4ebfc86b79a4b2079 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 28 Oct 2012 17:38:25 +0100 Subject: [PATCH 53/64] More curl fixes and changes. * Moved LegacyPolledResponder::mCode to ResponderBase::mCode. * Added a parameter to ResponderBase::finished (and pubError*) to set mCode. * Renamed ResponderBase::decode_body to decode_llsd_body and added ResponderBase::decode_raw_body. * Use LegacyPolledResponder::finished instead of LegacyPolledResponder::completed_headers to set remaining cached values. * Fixed assertion in case of -DCWDEBUG and upload finish detection failure in case of HEAD method (mDebugIsGetMethod -> mDebugIsHeadOrGetMethod). * Add XmlTreeInjector : support for LLXmlTree. * Split BlockingResponder into BlockingLLSDResponder and BlockingRawResponder. * Final blocking responders are now: BlockingLLSDPostResponder, BlockingLLSDGetResponder and BlockingRawGetResponder. * Added LLHTTPClient::blockingGetRaw * Got rid of hipporestrequest.* -- and fixed hippogridmanager.cpp to use LLHTTPClient::blockingGetRaw instead, and fixed llviewermessage.cpp to use AICurlInterface::ResponderWithCompleted and decode_raw_body instead of HippoRestHandlerRaw and LLHTTPClient::get4 instead of HippoRestRequest::get5. --- indra/aistatemachine/aicurl.cpp | 46 +++--- indra/aistatemachine/aicurl.h | 79 +++++++--- indra/aistatemachine/aicurlprivate.h | 4 +- indra/aistatemachine/aicurlthread.cpp | 38 +++-- indra/llmessage/CMakeLists.txt | 5 +- indra/llmessage/aihttptimeoutpolicy.cpp | 6 +- indra/llmessage/llhttpclient.cpp | 194 ++++++++++++++++++------ indra/llmessage/llhttpclient.h | 11 +- indra/llmessage/llsdmessage.cpp | 3 +- indra/newview/CMakeLists.txt | 2 - indra/newview/hippogridmanager.cpp | 4 +- indra/newview/llmeshrepository.cpp | 4 +- indra/newview/llviewermedia.cpp | 2 +- indra/newview/llviewermessage.cpp | 23 ++- 14 files changed, 290 insertions(+), 131 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index c45c6f214..d4353226f 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -433,7 +433,7 @@ std::string strerror(CURLcode errorcode) // class ResponderBase // -ResponderBase::ResponderBase(void) : mReferenceCount(0), mFinished(false) +ResponderBase::ResponderBase(void) : mReferenceCount(0), mCode(CURLE_FAILED_INIT), mFinished(false) { DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); } @@ -456,7 +456,7 @@ AIHTTPTimeoutPolicy const& ResponderBase::getHTTPTimeoutPolicy(void) const return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); } -void ResponderBase::decode_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) +void ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) { // If the status indicates success (and we get here) then we expect the body to be LLSD. bool const should_be_llsd = (200 <= status && status < 300); @@ -492,12 +492,25 @@ void ResponderBase::decode_body(U32 status, std::string const& reason, LLChannel #endif } +void ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) +{ + LLMutexLock lock(buffer->getMutex()); + LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); + for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter) + { + if (iter->isOnChannel(channels.in())) + { + content.append((char*)iter->data(), iter->size()); + } + } +} + // Called with HTML body. // virtual void ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { LLSD content; - decode_body(status, reason, channels, buffer, content); + decode_llsd_body(status, reason, channels, buffer, content); // Allow derived class to override at this point. completed(status, reason, content); @@ -511,13 +524,15 @@ void ResponderWithCompleted::completed(U32 status, std::string const& reason, LL } // virtual -void Responder::finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +void Responder::finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - LLSD content; - decode_body(status, reason, channels, buffer, content); + mCode = code; - // HTML status good? - if (200 <= status && status < 300) + LLSD content; + decode_llsd_body(http_status, reason, channels, buffer, content); + + // HTTP status good? + if (200 <= http_status && http_status < 300) { // Allow derived class to override at this point. result(content); @@ -525,8 +540,9 @@ void Responder::finished(U32 status, std::string const& reason, LLChannelDescrip else { // Allow derived class to override at this point. - errorWithContent(status, reason, content); + errorWithContent(http_status, reason, content); } + mFinished = true; } @@ -558,16 +574,6 @@ void intrusive_ptr_release(ResponderBase* responder) } } -// virtual -void LegacyPolledResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) -{ - mCode = code; - mStatus = status; - mReason = reason; - // Call base class implementation. - ResponderBase::completed_headers(status, reason, code, info); -} - } // namespace AICurlInterface //================================================================================== @@ -1377,7 +1383,7 @@ CurlResponderBuffer::~CurlResponderBuffer() void CurlResponderBuffer::timed_out(void) { - mResponder->finished(HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); + mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); mResponder = NULL; } diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 7a679d6f6..5174b0cd6 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -180,7 +180,7 @@ void setCAPath(std::string const& file); //----------------------------------------------------------------------------- // Global classes. -// Responder - base class for Request::get* and Request::post API. +// ResponderBase - base class for all Responders. // // The life cycle of classes derived from this class is as follows: // They are allocated with new on the line where get(), getByteRange() or post() is called, @@ -209,7 +209,10 @@ class ResponderBase : public AICurlResponderBufferEvents { virtual ~ResponderBase(); // Read body from buffer and put it into content. If status indicates success, interpret it as LLSD, otherwise copy it as-is. - void decode_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); + void decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); + + // Read body from buffer and put it into content. Always copy it as-is. + void decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content); protected: // Associated URL, used for debug output. @@ -218,6 +221,9 @@ class ResponderBase : public AICurlResponderBufferEvents { // Headers received from the server. AIHTTPReceivedHeaders mReceivedHeaders; + // The curl result code. + CURLcode mCode; + // Set when the transaction finished (with or without errors). bool mFinished; @@ -226,11 +232,12 @@ class ResponderBase : public AICurlResponderBufferEvents { // used only when printing debug output regarding activity of the Responder. void setURL(std::string const& url); - // Accessor. + // Accessors. std::string const& getURL(void) const { return mURL; } + CURLcode result_code(void) const { return mCode; } // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. - virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; + virtual void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; // Return true if the curl thread is done with this transaction. // If this returns true then it is guaranteed that none of the @@ -240,6 +247,8 @@ class ResponderBase : public AICurlResponderBufferEvents { bool is_finished(void) const { return mFinished; } protected: + // AICurlResponderBufferEvents + // Called when the "HTTP/1.x " header is received. /*virtual*/ void received_HTTP_header(void) { @@ -264,13 +273,13 @@ class ResponderBase : public AICurlResponderBufferEvents { // Derived classes that implement completed_headers()/completedHeaders() should return true here. virtual bool needsHeaders(void) const { return false; } - // Timeout policy to use. - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; - // A derived class should return true if curl should follow redirections. // The default is not to follow redirections. virtual bool followRedir(void) { return false; } + // Timeout policy to use. + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; + protected: // Derived classes can override this to get the HTML headers that were received, when the message is completed. virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) @@ -287,28 +296,37 @@ class ResponderBase : public AICurlResponderBufferEvents { // This function must delete the ResponderBase object when the reference count reaches zero. }; +// ResponderWithCompleted - base class for Responders that implement completed, or completedRaw if the response is not LLSD. class ResponderWithCompleted : public ResponderBase { protected: - virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + // ResponderBase event + + // The responder finished. Do not override this function in derived classes; override completedRaw instead. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { + mCode = code; // Allow classes derived from ResponderBase to override completedRaw // (if not they should override completed or be derived from Responder instead). - completedRaw(status, reason, channels, buffer); + completedRaw(http_status, reason, channels, buffer); mFinished = true; } + protected: + // Events generated by this class. + // Derived classes can override this to get the raw data of the body of the HTML message that was received. // The default is to interpret the content as LLSD and call completed(). virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); - // ... or, derived classes can override this to get the LLSD content when the message is completed. - // The default is to call result() (or errorWithContent() in case of a HTML status indicating an error). + // ... or, derived classes can override this to get LLSD content when the message is completed. + // The default aborts, as it should never be called (can't make it pure virtual though, so + // classes that override completedRaw don't need to implement this function, too). virtual void completed(U32 status, std::string const& reason, LLSD const& content); #ifdef SHOW_ASSERT // Responders derived from this class must override either completedRaw or completed. - // They may not attempt to override any of the virual functions defined by Responder. - // Define those functions here with different parameter in order to cause a compile + // They may not attempt to override any of the virual functions defined by ResponderBase. + // Define those functions here with different parameters in order to cause a compile // warning when a class accidently tries to override them. enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; virtual void result(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } @@ -317,12 +335,18 @@ class ResponderWithCompleted : public ResponderBase { #endif }; +// Responder - base class for reponders that expect LLSD in the body of the reply. +// +// Classes derived from Responder must implement result, and either errorWithContent or error. class Responder : public ResponderBase { protected: - virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // The responder finished. Do not override this function in derived classes; use ResponderWithCompleted instead. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); - // ... or, derived classes can override this to received the content of a body upon success. - // The default does nothing. + protected: + // Events generated by this class. + + // Derived classes must override this to receive the content of a body upon success. virtual void result(LLSD const& content) = 0; // Derived classes can override this to get informed when a bad HTML status code is received. @@ -335,10 +359,10 @@ class Responder : public ResponderBase { public: // Called from LLSDMessage::ResponderAdapter::listener. - // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that these functions need to be public. + // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that it needs these functions. - void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); mFinished = true; } - void pubResult(LLSD const& content) { result(content); mFinished = true; } + void pubErrorWithContent(CURLcode code, U32 status, std::string const& reason, LLSD const& content) { mCode = code; errorWithContent(status, reason, content); mFinished = true; } + void pubResult(LLSD const& content) { mCode = CURLE_OK; result(content); mFinished = true; } #ifdef SHOW_ASSERT // Responders derived from this class must override result, and either errorWithContent or error. @@ -361,20 +385,25 @@ typedef boost::intrusive_ptr ResponderPtr; // digesting the results when any of the virtual functions are called. class LegacyPolledResponder : public ResponderWithCompleted { protected: - CURLcode mCode; U32 mStatus; std::string mReason; + protected: + // The responder finished. Do not override this function in derived classes. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + mStatus = http_status; + mReason = reason; + // Call base class implementation. + ResponderWithCompleted::finished(code, http_status, reason, channels, buffer); + } + public: - LegacyPolledResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR) { } + LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR) { } // Accessors. - CURLcode result_code(void) const { return mCode; } U32 http_status(void) const { return mStatus; } std::string const& reason(void) const { return mReason; } - - /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); }; } // namespace AICurlInterface diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index fbf70fcce..1dfd500d6 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -377,7 +377,7 @@ class CurlEasyRequest : public CurlEasyHandle { bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo. #if defined(CWDEBUG) || defined(DEBUG_CURLIO) public: - bool mDebugIsGetMethod; + bool mDebugIsHeadOrGetMethod; #endif public: @@ -398,7 +398,7 @@ class CurlEasyRequest : public CurlEasyHandle { // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : mHeaders(NULL), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) - , mDebugIsGetMethod(false) + , mDebugIsHeadOrGetMethod(false) #endif { applyDefaultOptions(); } public: diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 61a1a1961..ce80c4b4b 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1789,9 +1789,9 @@ bool HTTPTimeout::data_received(size_t n) { // mUploadFinished not being set this point should only happen for GET requests (in fact, then it is normal), // because in that case it is impossible to detect the difference between connecting and waiting for a reply without - // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsGetMethod is only valid when the debug channel 'curlio' is on, + // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsHeadOrGetMethod is only valid when the debug channel 'curlio' is on, // because it is set in the debug callback function. - Debug(llassert(AICurlEasyRequest_wat(*mLockObj)->mDebugIsGetMethod || !dc::curlio.is_on())); + Debug(llassert(AICurlEasyRequest_wat(*mLockObj)->mDebugIsHeadOrGetMethod || !dc::curlio.is_on())); // 'Upload finished' detection failed, generate it now. upload_finished(); } @@ -2094,24 +2094,20 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); } - llassert(mResponder); // AIFIXME: We always have a responder now, no? - if (mResponder) - { - if (code != CURLE_OK) - { - curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); - } - if (mEventsTarget) - { - // Only the responder registers for these events. - llassert(mEventsTarget == mResponder.get()); - // Allow clients to parse result codes and headers before we attempt to parse - // the body and provide completed/result/error calls. - mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); - } - mResponder->finished(responseCode, responseReason, sChannels, mOutput); - mResponder = NULL; + if (code != CURLE_OK) + { + curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); } + if (mEventsTarget) + { + // Only the responder registers for these events. + llassert(mEventsTarget == mResponder.get()); + // Allow clients to parse result codes and headers before we attempt to parse + // the body and provide completed/result/error calls. + mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); + } + mResponder->finished(code, responseCode, responseReason, sChannels, mOutput); + mResponder = NULL; resetState(curl_easy_request_w); } @@ -2297,8 +2293,8 @@ int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* break; case CURLINFO_HEADER_OUT: LibcwDoutStream << "H< "; - if (size >= 4 && strncmp(buf, "GET ", 4) == 0) - request->mDebugIsGetMethod = true; + if (size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0)) + request->mDebugIsHeadOrGetMethod = true; break; case CURLINFO_DATA_IN: LibcwDoutStream << "D> "; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index ec697c4a3..046e77b0e 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -8,6 +8,7 @@ include(AIStateMachine) include(LLMath) include(LLMessage) include(LLVFS) +include(LLXML) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) @@ -17,6 +18,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} ) set(llmessage_SOURCE_FILES @@ -244,7 +246,8 @@ if (LL_TESTS) ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} - ${GOOGLEMOCK_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} + ${LLXML_LIBRARIES} ) LL_ADD_INTEGRATION_TEST( diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 7db472f96..2292b93f2 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -679,10 +679,12 @@ P(accountingCostResponder); P(agentStateResponder); P(assetUploadResponder); P(asyncConsoleResponder); +P(authHandler); P(avatarNameResponder); P2(baseCapabilitiesComplete, transfer_18s); -P(blockingGet); -P(blockingPost); +P(blockingLLSDPost); +P(blockingLLSDGet); +P(blockingRawGet); P(charactersResponder); P(classifiedStatsResponder); P(consoleResponder); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 96a38ea10..33edb311a 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -34,10 +34,12 @@ #include "llsdserialize.h" #include "llvfile.h" #include "llurlrequest.h" +#include "llxmltree.h" class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy blockingGet_timeout; -extern AIHTTPTimeoutPolicy blockingPost_timeout; +extern AIHTTPTimeoutPolicy blockingLLSDPost_timeout; +extern AIHTTPTimeoutPolicy blockingLLSDGet_timeout; +extern AIHTTPTimeoutPolicy blockingRawGet_timeout; //////////////////////////////////////////////////////////////////////////// @@ -64,6 +66,27 @@ private: char const* mRequestText; }; +class XmlTreeInjector : public Injector +{ + public: + XmlTreeInjector(LLXmlTree const* tree) : mTree(tree) { } + ~XmlTreeInjector() { delete const_cast(mTree); } + + /*virtual*/ char const* contentType(void) const { return "application/xml"; } + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) + { + std::string data; + mTree->write(data); + LLBufferStream ostream(channels, buffer.get()); + ostream.write(data.data(), data.size()); + ostream << std::flush; // Always flush a LLBufferStream when done writing to it. + return data.size(); + } + + private: + LLXmlTree const* mTree; +}; + class LLSDInjector : public Injector { public: @@ -230,28 +253,27 @@ void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr get4(uri.asString(), responder, headers); } +//============================================================================= +// Blocking Responders. +// + class BlockingResponder : public AICurlInterface::LegacyPolledResponder { private: - LLCondition mSignal; - LLSD mResponse; + LLCondition mSignal; // Wait condition to wait till mFinished is true. + static LLSD LLSD_dummy; + static std::string Raw_dummy; public: - void wait(void); - LLSD const& response(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + void wait(void); // Blocks until mFinished is true. + virtual LLSD const& getLLSD(void) const { llassert(false); return LLSD_dummy; } + virtual std::string const& getRaw(void) const { llassert(false); return Raw_dummy; } - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); +protected: + void wakeup(void); // Call this at the end of completedRaw. }; -void BlockingResponder::completedRaw(U32, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) -{ - decode_body(mCode, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. - // Normally mFinished is set immediately after returning from this function, - // but we do it here, because we need to set it before calling mSignal.signal(). - mSignal.lock(); - mFinished = true; - mSignal.unlock(); - mSignal.signal(); -} +LLSD BlockingResponder::LLSD_dummy; +std::string BlockingResponder::Raw_dummy; void BlockingResponder::wait(void) { @@ -273,18 +295,68 @@ void BlockingResponder::wait(void) } } -class BlockingPostResponder : public BlockingResponder { -public: - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingPost_timeout; } +void BlockingResponder::wakeup(void) +{ + // Normally mFinished is set immediately after returning from this function, + // but we do it here, because we need to set it before calling mSignal.signal(). + mSignal.lock(); + mFinished = true; + mSignal.unlock(); + mSignal.signal(); +} + +class BlockingLLSDResponder : public BlockingResponder { +private: + LLSD mResponse; + +protected: + /*virtual*/ LLSD const& getLLSD(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + decode_llsd_body(mCode, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. + wakeup(); + } }; -class BlockingGetResponder : public BlockingResponder { -public: - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingGet_timeout; } +class BlockingRawResponder : public BlockingResponder { +private: + std::string mResponse; + +protected: + /*virtual*/ std::string const& getRaw(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + decode_raw_body(mCode, reason, channels, buffer, mResponse); + wakeup(); + } }; +class BlockingLLSDPostResponder : public BlockingLLSDResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingLLSDPost_timeout; } +}; + +class BlockingLLSDGetResponder : public BlockingLLSDResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingLLSDGet_timeout; } +}; + +class BlockingRawGetResponder : public BlockingRawResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingRawGet_timeout; } +}; + +// End blocking responders. +//============================================================================= + // These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome. +enum EBlockingRequestAction { + HTTP_LLSD_POST, + HTTP_LLSD_GET, + HTTP_RAW_GET +}; + /** @brief does a blocking request on the url, returning the data or bad status. @@ -303,22 +375,26 @@ public: */ static LLSD blocking_request( std::string const& url, - LLURLRequest::ERequestAction method, - LLSD const& body, - AIHTTPHeaders& headers) + EBlockingRequestAction method, + LLSD const& body) // Only used for HTTP_LLSD_POST { lldebugs << "blockingRequest of " << url << llendl; + AIHTTPHeaders headers; boost::intrusive_ptr responder; - if (method == LLURLRequest::HTTP_POST) + if (method == HTTP_LLSD_POST) { - responder = new BlockingPostResponder; + responder = new BlockingLLSDPostResponder; LLHTTPClient::post4(url, body, responder, headers); } - else + else if (method == HTTP_LLSD_GET) { - llassert(method == LLURLRequest::HTTP_GET); - responder = new BlockingGetResponder; + responder = new BlockingLLSDGetResponder; + LLHTTPClient::get4(url, responder, headers); + } + else // method == HTTP_RAW_GET + { + responder = new BlockingRawGetResponder; LLHTTPClient::get4(url, responder, headers); } @@ -328,9 +404,18 @@ static LLSD blocking_request( LLSD response = LLSD::emptyMap(); CURLcode result = responder->result_code(); - if (result == CURLE_OK && (http_status = responder->http_status()) >= 200 && http_status < 300) + http_status = responder->http_status(); + bool http_success = http_status >= 200 && http_status < 300; + if (result == CURLE_OK && http_success) { - response["body"] = responder->response(); + if (method == HTTP_RAW_GET) + { + response["body"] = responder->getRaw(); + } + else + { + response["body"] = responder->getLLSD(); + } } else if (result == CURLE_OK) { @@ -338,16 +423,30 @@ static LLSD blocking_request( if (http_status != 404) { llwarns << "CURL REQ URL: " << url << llendl; - llwarns << "CURL REQ METHOD TYPE: " << LLURLRequest::actionAsVerb(method) << llendl; + llwarns << "CURL REQ METHOD TYPE: " << method << llendl; llwarns << "CURL REQ HEADERS: " << headers << llendl; - if (method == LLURLRequest::HTTP_POST) + if (method == HTTP_LLSD_POST) { llwarns << "CURL REQ BODY: " << body.asString() << llendl; } llwarns << "CURL HTTP_STATUS: " << http_status << llendl; - llwarns << "CURL ERROR BODY: " << responder->response().asString() << llendl; + if (method == HTTP_RAW_GET) + { + llwarns << "CURL ERROR BODY: " << responder->getRaw() << llendl; + } + else + { + llwarns << "CURL ERROR BODY: " << responder->getLLSD().asString() << llendl; + } + } + if (method == HTTP_RAW_GET) + { + response["body"] = responder->getRaw(); + } + else + { + response["body"] = responder->getLLSD().asString(); } - response["body"] = responder->response().asString(); } else { @@ -358,16 +457,21 @@ static LLSD blocking_request( return response; } -LLSD LLHTTPClient::blockingGet(const std::string& url) -{ - AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers); -} - LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { - AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers); + return blocking_request(url, HTTP_LLSD_POST, body); +} + +LLSD LLHTTPClient::blockingGet(const std::string& url) +{ + return blocking_request(url, HTTP_LLSD_GET, LLSD()); +} + +U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body) +{ + LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD()); + body = result["body"].asString(); + return result["status"].asInteger(); } void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index c78917a82..6c8718344 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -130,13 +130,22 @@ public: //@} /** - * @brief Blocking HTTP get that returns an LLSD map of status and body. + * @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(std::string const& url); + /** + * @brief Blocking HTTP GET that returns the raw body. + * + * @param url the complete serialized (and escaped) url to get + * @param result the target string to write the body to + * @return HTTP status + */ + static U32 blockingGetRaw(const std::string& url, std::string& result); + /** * @brief Blocking HTTP POST that returns an LLSD map of status and body. * diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index be968c5db..e833abee5 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -128,6 +128,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string LLSD info(mReqID.makeResponse()); info["target"] = mTarget; info["message"] = mMessage; + info["code"] = mCode; info["status"] = LLSD::Integer(status); info["reason"] = reason; info["content"] = content; @@ -172,7 +173,7 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) } else { - responder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); + responder->pubErrorWithContent((CURLcode)payload["code"].asInteger(), payload["status"].asInteger(), payload["reason"], payload["content"]); } /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8d7f6c323..058df371f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -91,7 +91,6 @@ set(viewer_SOURCE_FILES hippogridmanager.cpp hippolimits.cpp hippopanelgrids.cpp - hipporestrequest.cpp importtracker.cpp jcfloaterareasearch.cpp lggdicdownload.cpp @@ -591,7 +590,6 @@ set(viewer_HEADER_FILES hippogridmanager.h hippolimits.h hippopanelgrids.h - hipporestrequest.h importtracker.h jcfloaterareasearch.h lggdicdownload.h diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index fac276e7a..c0ceef71d 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -17,8 +17,6 @@ #include "llviewercontrol.h" #include "llweb.h" -#include "hipporestrequest.h" - // ******************************************************************** // Global Variables @@ -491,7 +489,7 @@ bool HippoGridInfo::retrieveGridInfo() uri += '/'; } std::string reply; - int result = HippoRestRequest::getBlocking(uri + "get_grid_info", &reply); + int result = LLHTTPClient::blockingGetRaw(uri + "get_grid_info", reply); if (result != 200) return false; llinfos << "Received: " << reply << llendl; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index cd406e3c5..d90a9483d 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -366,7 +366,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s } } -class LLWholeModelFeeResponder: public LLCurl::Responder +class LLWholeModelFeeResponder: public LLCurl::ResponderWithCompleted { LLMeshUploadThread* mThread; LLSD mModelData; @@ -420,7 +420,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return wholeModelFeeResponder_timeout; } }; -class LLWholeModelUploadResponder: public LLCurl::Responder +class LLWholeModelUploadResponder: public LLCurl::ResponderWithCompleted { LLMeshUploadThread* mThread; LLSD mModelData; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index b818ae50c..74526a61d 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -71,7 +71,7 @@ const int RIGHT_BUTTON = 1; /////////////////////////////////////////////////////////////////////////////// // 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 AICurlInterface::ResponderWithCompleted +class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderIgnoreBody { LOG_CLASS(LLMimeDiscoveryResponder); public: diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3084f61f9..57c65caea 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -165,7 +165,6 @@ #include "hippogridmanager.h" #include "hippolimits.h" -#include "hipporestrequest.h" #include "hippofloaterxml.h" #include "sgversion.h" #include "m7wlinterface.h" @@ -188,6 +187,8 @@ static const boost::regex NEWLINES("\\n{1}"); // NaCl End +extern AIHTTPTimeoutPolicy authHandler_timeout; + // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) #include "llfloateravatarinfo.h" extern LLMap< const LLUUID, LLFloaterAvatarInfo* > gAvatarInfoInstances; // Only defined in llfloateravatarinfo.cpp @@ -3349,12 +3350,24 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist // defined in llchatbar.cpp, but not declared in any header void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); -class AuthHandler : public HippoRestHandlerRaw +class AuthHandler : public AICurlInterface::ResponderWithCompleted { - void result(const std::string &content) +protected: + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + std::string content; + decode_raw_body(status, reason, channels, buffer, content); + if (status == HTTP_OK) + { + send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + } + else + { + llwarns << "Hippo AuthHandler: non-OK HTTP status " << status << " for URL " << mURL << " (" << reason << "). Error body: \"" << content << "\"." << llendl; + } } + + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return authHandler_timeout; } }; void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) @@ -3612,7 +3625,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string authUrl = mesg.substr(8); authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; authUrl += gAuthString; - HippoRestRequest::get5(authUrl, new AuthHandler()); + LLHTTPClient::get4(authUrl, new AuthHandler); return; } } From 3e78b7c26263782ff2c85f91c047ce56aa0e671f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 30 Oct 2012 07:16:01 +0100 Subject: [PATCH 54/64] Allow people with last name "Resident" to login using Hippogrid manager. --- indra/newview/llpanellogin.cpp | 21 ++++++++++----------- indra/newview/llpanellogin.h | 4 ++-- indra/newview/llsavedlogins.cpp | 16 ++++++++++++++++ indra/newview/llsavedlogins.h | 4 +++- indra/newview/llstartup.cpp | 10 ++++++---- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 1bfbcc702..f229497a4 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -114,7 +114,7 @@ static bool nameSplit(const std::string& full, std::string& first, std::string& if (fragments.size() == 1) { if (gHippoGridManager->getConnectedGrid()->isSecondLife()) - last = "resident"; + last = "Resident"; else last = ""; } @@ -123,8 +123,8 @@ static bool nameSplit(const std::string& full, std::string& first, std::string& return (fragments.size() <= 2); } -static std::string nameJoin(const std::string& first,const std::string& last) { - if (last.empty() || boost::algorithm::iequals(last, "resident")) +static std::string nameJoin(const std::string& first,const std::string& last, bool strip_resident) { + if (last.empty() || (strip_resident && boost::algorithm::iequals(last, "Resident"))) return first; else { if(std::islower(last[0])) @@ -134,15 +134,15 @@ static std::string nameJoin(const std::string& first,const std::string& last) { } } -static std::string getDisplayString(const std::string& first, const std::string& last, const std::string& grid) { +static std::string getDisplayString(const std::string& first, const std::string& last, const std::string& grid, bool is_secondlife) { if(grid == gHippoGridManager->getDefaultGridNick()) - return nameJoin(first, last); + return nameJoin(first, last, is_secondlife); else - return nameJoin(first, last) + " (" + grid + ")"; + return nameJoin(first, last, is_secondlife) + " (" + grid + ")"; } static std::string getDisplayString(const LLSavedLoginEntry& entry) { - return getDisplayString(entry.getFirstName(), entry.getLastName(), entry.getGrid()); + return getDisplayString(entry.getFirstName(), entry.getLastName(), entry.getGrid(), entry.isSecondLife()); } class LLLoginRefreshHandler : public LLCommandHandler @@ -661,8 +661,7 @@ void LLPanelLogin::show(const LLRect &rect, // static void LLPanelLogin::setFields(const std::string& firstname, const std::string& lastname, - const std::string& password, - const LLSavedLogins& login_history) + const std::string& password) { if (!sInstance) { @@ -673,7 +672,7 @@ void LLPanelLogin::setFields(const std::string& firstname, LLComboBox* login_combo = sInstance->getChild("name_combo"); llassert_always(firstname.find(' ') == std::string::npos); - login_combo->setLabel(nameJoin(firstname, lastname)); + login_combo->setLabel(nameJoin(firstname, lastname, false)); // Max "actual" password length is 16 characters. // Hex digests are always 32 characters. @@ -710,7 +709,7 @@ void LLPanelLogin::setFields(const LLSavedLoginEntry& entry, bool takeFocus) } LLCheckBoxCtrl* remember_pass_check = sInstance->getChild("remember_check"); - std::string fullname = nameJoin(entry.getFirstName(), entry.getLastName()); + std::string fullname = nameJoin(entry.getFirstName(), entry.getLastName(), entry.isSecondLife()); LLComboBox* login_combo = sInstance->getChild("name_combo"); login_combo->setTextEntry(fullname); login_combo->resetTextDirty(); diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 3fd697b34..53eb9b52d 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -71,10 +71,10 @@ public: * @param firstname First name value. * @param lastname Last name value. * @param password Password, as plaintext or munged. - * @param login_history Login history object. An empty one can be provided if no history is available. + * @param is_secondlife True if First/Last refer to a SecondLife(tm) account. */ static void setFields(const std::string& firstname, const std::string& lastname, - const std::string& password, const LLSavedLogins& login_history = LLSavedLogins()); + const std::string& password); /** * @brief Set the values of the displayed fields from a populated history entry. diff --git a/indra/newview/llsavedlogins.cpp b/indra/newview/llsavedlogins.cpp index 819091fc5..991f1aacf 100644 --- a/indra/newview/llsavedlogins.cpp +++ b/indra/newview/llsavedlogins.cpp @@ -145,6 +145,22 @@ const LLSD LLSavedLoginEntry::encryptPassword(const std::string& password) return pwdata; } +bool LLSavedLoginEntry::isSecondLife() const +{ + if (!mEntry.has("grid")) + { + return false; + } + std::string name = mEntry.get("grid").asString(); + HippoGridInfo* grid_info = gHippoGridManager->getGrid(name); + llassert(grid_info); + if (!grid_info) + { + return name.substr(0, 11) == "Second Life"; + } + return grid_info->isSecondLife(); +} + //--------------------------------------------------------------------------- // LLSavedLogins methods //--------------------------------------------------------------------------- diff --git a/indra/newview/llsavedlogins.h b/indra/newview/llsavedlogins.h index 592fedff6..5461bae8e 100644 --- a/indra/newview/llsavedlogins.h +++ b/indra/newview/llsavedlogins.h @@ -119,7 +119,9 @@ public: void setGrid(const std::string& value){ mEntry.insert("grid", LLSD(value)); } - + + bool isSecondLife() const; + LLSD asLLSD() const; static const size_t PASSWORD_HASH_LENGTH = 32; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d0a5a6364..91abb8dc5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -32,6 +32,7 @@ #include "llviewerprecompiledheaders.h" +#include #include "llstartup.h" #if LL_WINDOWS @@ -893,7 +894,7 @@ bool idle_startup() } else { - LLPanelLogin::setFields(firstname, lastname, password, login_history); + LLPanelLogin::setFields(firstname, lastname, password); // gFullName = utf8str_tolower(firstname + " " + lastname); // @@ -1591,10 +1592,11 @@ bool idle_startup() if(process_login_success_response(password)) { std::string name = firstname; - std::string last_name = lastname; - LLStringUtil::toLower(last_name); - if(last_name != "resident") + if (!gHippoGridManager->getCurrentGrid()->isSecondLife() || + !boost::algorithm::iequals(lastname, "Resident")) + { name += " " + lastname; + } gViewerWindow->getWindow()->setTitle(LLAppViewer::instance()->getWindowTitle() + "- " + name); // Pass the user information to the voice chat server interface. gVoiceClient->userAuthorized(firstname, lastname, gAgentID); From 9996cf6157b411ad96b6d56c80a44928e83b684e Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 30 Oct 2012 21:17:25 +0100 Subject: [PATCH 55/64] Bug fix --- indra/llmessage/llhttpclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 33edb311a..b94a17ee4 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -313,7 +313,7 @@ protected: /*virtual*/ LLSD const& getLLSD(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - decode_llsd_body(mCode, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. + decode_llsd_body(status, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. wakeup(); } }; From 3708d55ef935d0b2ce0cfaf832cd190aadbe16e5 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 30 Oct 2012 21:18:15 +0100 Subject: [PATCH 56/64] Allow changing CurlTimeout Debug Settings on the fly. Same for NoVerifySSLCert and CurlConcurrentConnections. --- indra/aistatemachine/aicurl.h | 5 + indra/aistatemachine/aicurlthread.cpp | 15 +++ indra/llmessage/aihttptimeoutpolicy.cpp | 128 +++++++++++++++++++++++- indra/llmessage/aihttptimeoutpolicy.h | 20 ++++ indra/newview/app_settings/settings.xml | 18 ++-- indra/newview/llviewercontrol.cpp | 21 ++++ 6 files changed, 196 insertions(+), 11 deletions(-) diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 5174b0cd6..bafa2c31b 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -55,6 +55,7 @@ #include "llhttpstatuscodes.h" #include "aihttpheaders.h" +// Debug Settings. extern bool gNoVerifySSLCert; class LLSD; @@ -148,6 +149,10 @@ struct TransferInfo { //----------------------------------------------------------------------------- // Global functions. +// Called to handle changes in Debug Settings. +bool handleCurlConcurrentConnections(LLSD const& newvalue); +bool handleNoVerifySSLCert(LLSD const& newvalue); + // Called once at start of application (from newview/llappviewer.cpp by main thread (before threads are created)), // with main purpose to initialize curl. void initCurl(void (*)(void) = NULL); diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index ce80c4b4b..b1b518c20 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -2493,5 +2493,20 @@ void startCurlThread(U32 CurlConcurrentConnections, bool NoVerifySSLCert) AICurlThread::sInstance->start(); } +bool handleCurlConcurrentConnections(LLSD const& newvalue) +{ + using namespace AICurlPrivate::curlthread; + + curl_concurrent_connections = newvalue.asInteger(); + llinfos << "CurlConcurrentConnections set to " << curl_concurrent_connections << llendl; + return true; +} + +bool handleNoVerifySSLCert(LLSD const& newvalue) +{ + gNoVerifySSLCert = newvalue.asBoolean(); + return true; +} + } // namespace AICurlInterface diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 2292b93f2..db4acaf65 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -602,8 +602,6 @@ void AIHTTPTimeoutPolicy::sanity_checks(void) const //======================================================================================================= // Start of policy definitions. -// AIFIXME: update all policies whenever a CurlTimeout* settings is changed. - // Policy with hardcoded default values. AIHTTPTimeoutPolicyBase HTTPTimeoutPolicy_default( AITP_default_DNS_lookup_grace, @@ -646,6 +644,132 @@ AIHTTPTimeoutPolicyBase connect_40s(AIHTTPTimeoutPolicyBase::getDebugSettingsCur // End of policy definitions. //======================================================================================================= +bool validateCurlTimeoutDNSLookup(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::DNS op(new_value); + op.perform(&timeout); + return timeout.getDNSLookup() == new_value; +} + +bool handleCurlTimeoutDNSLookup(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::DNS op(newvalue.asInteger()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + +bool validateCurlTimeoutConnect(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Connect op(new_value); + op.perform(&timeout); + return timeout.getConnect() == new_value; +} + +bool handleCurlTimeoutConnect(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Connect op(newvalue.asInteger()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + +bool validateCurlTimeoutReplyDelay(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Reply op(new_value); + op.perform(&timeout); + return timeout.getReplyDelay() == new_value; +} + +bool handleCurlTimeoutReplyDelay(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Reply op(newvalue.asInteger()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + +bool validateCurlTimeoutLowSpeedLimit(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Speed op(timeout.getLowSpeedTime(), new_value); + op.perform(&timeout); + return timeout.getLowSpeedLimit() == new_value; +} + +bool handleCurlTimeoutLowSpeedLimit(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Speed op(timeout.getLowSpeedTime(), newvalue.asInteger()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + +bool validateCurlTimeoutLowSpeedTime(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Speed op(new_value, timeout.getLowSpeedLimit()); + op.perform(&timeout); + return timeout.getLowSpeedTime() == new_value; +} + +bool handleCurlTimeoutLowSpeedTime(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Speed op(newvalue.asInteger(), timeout.getLowSpeedLimit()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + +bool validateCurlTimeoutMaxTransaction(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Transaction op(new_value); + op.perform(&timeout); + return timeout.getCurlTransaction() == new_value; +} + +bool handleCurlTimeoutMaxTransaction(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Transaction op(newvalue.asInteger()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + +bool validateCurlTimeoutMaxTotalDelay(LLSD const& newvalue) +{ + U32 new_value = newvalue.asInteger(); + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Total op(new_value); + op.perform(&timeout); + return timeout.getTotalDelay() == new_value; +} + +bool handleCurlTimeoutMaxTotalDelay(LLSD const& newvalue) +{ + AIHTTPTimeoutPolicyBase timeout = AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(); + AIHTTPTimeoutPolicyOperators::Total op(newvalue.asInteger()); + op.perform(&timeout); + AIHTTPTimeoutPolicy::setDefaultCurlTimeout(timeout); + return true; +} + //static AIHTTPTimeoutPolicy::namemap_t AIHTTPTimeoutPolicy::sNameMap; diff --git a/indra/llmessage/aihttptimeoutpolicy.h b/indra/llmessage/aihttptimeoutpolicy.h index bf333b105..9d77ffd5c 100644 --- a/indra/llmessage/aihttptimeoutpolicy.h +++ b/indra/llmessage/aihttptimeoutpolicy.h @@ -94,6 +94,8 @@ class AIHTTPTimeoutPolicy { // Accessors. char const* name(void) const { return mName; } U16 getConnectTimeout(std::string const& hostname) const; + U16 getDNSLookup(void) const { return mDNSLookupGrace; } + U16 getConnect(void) const { return mMaximumConnectTime; } U16 getReplyDelay(void) const { return mMaximumReplyDelay; } U16 getLowSpeedTime(void) const { return mLowSpeedTime; } U32 getLowSpeedLimit(void) const { return mLowSpeedLimit; } @@ -115,4 +117,22 @@ class AIHTTPTimeoutPolicy { AIHTTPTimeoutPolicy& operator=(AIHTTPTimeoutPolicy const&); }; +class LLSD; + +// Handlers for Debug Setting changes. +bool validateCurlTimeoutDNSLookup(LLSD const& newvalue); +bool handleCurlTimeoutDNSLookup(LLSD const& newvalue); +bool validateCurlTimeoutConnect(LLSD const& newvalue); +bool handleCurlTimeoutConnect(LLSD const& newvalue); +bool validateCurlTimeoutReplyDelay(LLSD const& newvalue); +bool handleCurlTimeoutReplyDelay(LLSD const& newvalue); +bool validateCurlTimeoutLowSpeedLimit(LLSD const& newvalue); +bool handleCurlTimeoutLowSpeedLimit(LLSD const& newvalue); +bool validateCurlTimeoutLowSpeedTime(LLSD const& newvalue); +bool handleCurlTimeoutLowSpeedTime(LLSD const& newvalue); +bool validateCurlTimeoutMaxTransaction(LLSD const& newvalue); +bool handleCurlTimeoutMaxTransaction(LLSD const& newvalue); +bool validateCurlTimeoutMaxTotalDelay(LLSD const& newvalue); +bool handleCurlTimeoutMaxTotalDelay(LLSD const& newvalue); + #endif // AIHTTPTIMEOUTPOLICY_H diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ef6ad1679..35313721e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4208,7 +4208,7 @@ CurlConcurrentConnections Comment - Maximum number of simultaneous curl connections (requires restart) + Maximum number of simultaneous curl connections Persist 1 Type @@ -4230,7 +4230,7 @@ CurlTimeoutDNSLookup Comment - Extra time in seconds added to CurlTimeoutConnect for the initial connect to a host (requires restart) + Extra time in seconds added to CurlTimeoutConnect for the initial connect to a host Persist 1 Type @@ -4241,7 +4241,7 @@ CurlTimeoutConnect Comment - Maximum time allowed until a connection is established (after adding the easy handle) until the server is considered unreachable and the connection is terminated (requires restart) + Maximum time allowed until a connection is established (after adding the easy handle) until the server is considered unreachable and the connection is terminated Persist 1 Type @@ -4252,7 +4252,7 @@ CurlTimeoutReplyDelay Comment - Maximum time the viewer will wait between sending data to the server and receiving (a partial) reply (requires restart) + Maximum time the viewer will wait between sending data to the server and receiving (a partial) reply Persist 1 Type @@ -4263,7 +4263,7 @@ CurlTimeoutLowSpeedLimit Comment - If a transfer speed drops below this value (in bytes/s) during CurlTimeoutLowSpeedTime seconds, the transfer is considered too slow and is terminated (requires restart) + If a transfer speed drops below this value (in bytes/s) during CurlTimeoutLowSpeedTime seconds, the transfer is considered too slow and is terminated Persist 1 Type @@ -4274,7 +4274,7 @@ CurlTimeoutLowSpeedTime Comment - If a transfer speed drops below CurlTimeoutLowSpeedLimit (in bytes/s) during this amount of seconds, the transfer is considered too slow and is terminated (requires restart) + If a transfer speed drops below CurlTimeoutLowSpeedLimit (in bytes/s) during this amount of seconds, the transfer is considered too slow and is terminated Persist 1 Type @@ -4285,7 +4285,7 @@ CurlTimeoutMaxTransaction Comment - Maximum total time of a curl transaction, from when the easy handle is added till the transaction has completed. This INCLUDES DNS lookups (CurlTimeoutConnect), connect time (CurlTimeoutConnect) and waiting for the first server reply (CurlTimeoutReply) as well as the actually time needed for data transfer (requires restart) + Maximum total time of a curl transaction, from when the easy handle is added till the transaction has completed. This INCLUDES DNS lookups (CurlTimeoutDNSLookup), connect time (CurlTimeoutConnect) and waiting for the first server reply (CurlTimeoutReply) as well as the actually time needed for data transfer Persist 1 Type @@ -4296,7 +4296,7 @@ CurlTimeoutMaxTotalDelay Comment - Maximum total time of a curl request, from when it is requested till the transaction has completed. This includes queuing due to connection throttling on top of the events covered by CurlTimeoutMaxTransaction (requires restart) + Maximum total time of a curl request, from when it is requested till the transaction has completed. This includes queuing due to connection throttling on top of the events covered by CurlTimeoutMaxTransaction Persist 1 Type @@ -9059,7 +9059,7 @@ NoVerifySSLCert Comment - Do not verify SSL peers (requires restart) + Do not verify SSL peers Persist 1 Type diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index bc51d808f..7feab1d86 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -82,6 +82,8 @@ #include "aithreadsafe.h" #include "lldrawpoolbump.h" #include "emeraldboobutils.h" +#include "aicurl.h" +#include "aihttptimeoutpolicy.h" #include "NACLantispam.h" // for NaCl Antispam Registry @@ -625,6 +627,7 @@ static bool handleAllowLargeSounds(const LLSD& newvalue) gAudiop->setAllowLargeSounds(newvalue.asBoolean()); return true; } + //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() { @@ -793,6 +796,24 @@ void settings_setup_listeners() gSavedSettings.getControl("AscentAvatarYModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); gSavedSettings.getControl("AscentAvatarZModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); + gSavedSettings.getControl("CurlConcurrentConnections")->getSignal()->connect(boost::bind(&AICurlInterface::handleCurlConcurrentConnections, _2)); + gSavedSettings.getControl("NoVerifySSLCert")->getSignal()->connect(boost::bind(&AICurlInterface::handleNoVerifySSLCert, _2)); + + gSavedSettings.getControl("CurlTimeoutDNSLookup")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutDNSLookup, _2)); + gSavedSettings.getControl("CurlTimeoutDNSLookup")->getSignal()->connect(boost::bind(&handleCurlTimeoutDNSLookup, _2)); + gSavedSettings.getControl("CurlTimeoutConnect")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutConnect, _2)); + gSavedSettings.getControl("CurlTimeoutConnect")->getSignal()->connect(boost::bind(&handleCurlTimeoutConnect, _2)); + gSavedSettings.getControl("CurlTimeoutReplyDelay")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutReplyDelay, _2)); + gSavedSettings.getControl("CurlTimeoutReplyDelay")->getSignal()->connect(boost::bind(&handleCurlTimeoutReplyDelay, _2)); + gSavedSettings.getControl("CurlTimeoutLowSpeedLimit")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutLowSpeedLimit, _2)); + gSavedSettings.getControl("CurlTimeoutLowSpeedLimit")->getSignal()->connect(boost::bind(&handleCurlTimeoutLowSpeedLimit, _2)); + gSavedSettings.getControl("CurlTimeoutLowSpeedTime")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutLowSpeedTime, _2)); + gSavedSettings.getControl("CurlTimeoutLowSpeedTime")->getSignal()->connect(boost::bind(&handleCurlTimeoutLowSpeedTime, _2)); + gSavedSettings.getControl("CurlTimeoutMaxTransaction")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutMaxTransaction, _2)); + gSavedSettings.getControl("CurlTimeoutMaxTransaction")->getSignal()->connect(boost::bind(&handleCurlTimeoutMaxTransaction, _2)); + gSavedSettings.getControl("CurlTimeoutMaxTotalDelay")->getValidateSignal()->connect(boost::bind(&validateCurlTimeoutMaxTotalDelay, _2)); + gSavedSettings.getControl("CurlTimeoutMaxTotalDelay")->getSignal()->connect(boost::bind(&handleCurlTimeoutMaxTotalDelay, _2)); + // [Ansariel: Display name support] gSavedSettings.getControl("PhoenixNameSystem")->getSignal()->connect(boost::bind(&handlePhoenixNameSystemChanged, _2)); // [/Ansariel: Display name support] From 6033a768706fa3e7b9fc9b96c8532c99d6e407ac Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 30 Oct 2012 21:37:49 +0100 Subject: [PATCH 57/64] Print more debug output. Remove last AIFIXME --- indra/llmessage/aihttptimeoutpolicy.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index db4acaf65..a8099cea4 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -69,8 +69,8 @@ U16 const ABS_max_reply_delay = 120; // If the server needs more than 2 minu U16 const ABS_min_low_speed_time = 4; // Intuitively, I think it makes no sense to average a download speed over less than 4 seconds. U16 const ABS_max_low_speed_time = 120; // Averaging it over a time considerably larger than the normal timeout periods makes no sense either. -U32 const ABS_min_low_speed_limit = 1000; // AIFIXME: this should be 1 byte/s, set at 1000 now for debugging purposes. -U32 const ABS_max_low_speed_limit = 1000000; // This limit almost certainly higher than what the maximum speed you get from the server! +U32 const ABS_min_low_speed_limit = 1; // In case you don't want to timeout when there is any data received at all. +U32 const ABS_max_low_speed_limit = 1000000; // This limit is almost certainly higher than the maximum speed you get from the server. U16 const ABS_min_transaction = 60; // This is an absurd low value for experimentation. In reality, you should control // termination of really slow connections through the low_speed settings. @@ -195,6 +195,14 @@ AIHTTPTimeoutPolicy::AIHTTPTimeoutPolicy(char const* name, AIHTTPTimeoutPolicyBa void AIHTTPTimeoutPolicy::setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& timeout) { sDebugSettingsCurlTimeout = timeout; + llinfos << "CurlTimeout Debug Settings now" + ": DNSLookup: " << sDebugSettingsCurlTimeout.mDNSLookupGrace << + "; Connect: " << sDebugSettingsCurlTimeout.mMaximumConnectTime << + "; ReplyDelay: " << sDebugSettingsCurlTimeout.mMaximumReplyDelay << + "; LowSpeedTime: " << sDebugSettingsCurlTimeout.mLowSpeedTime << + "; LowSpeedLimit: " << sDebugSettingsCurlTimeout.mLowSpeedLimit << + "; MaxTransaction: " << sDebugSettingsCurlTimeout.mMaximumCurlTransaction << + "; MaxTotalDelay: " << sDebugSettingsCurlTimeout.mMaximumTotalDelay << llendl; if (sDebugSettingsCurlTimeout.mDNSLookupGrace < AITP_default_DNS_lookup_grace) { llwarns << "CurlTimeoutDNSLookup (" << sDebugSettingsCurlTimeout.mDNSLookupGrace << ") is lower than the built-in default value (" << AITP_default_DNS_lookup_grace << ")." << llendl; From 0b265320a95cafcc22f70cdae965430d1015392f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 31 Oct 2012 05:01:24 +0100 Subject: [PATCH 58/64] Code clean up. * Removed LLCurlRequest and replaced it's last usage with LLHTTPClient API calls. * Deleted dead code. * Renamed all the get4/post4/put4/getByteRange4 etc, back to their original name without the '4'. --- indra/llcrashlogger/llcrashlogger.cpp | 2 +- indra/llmessage/CMakeLists.txt | 2 - indra/llmessage/llavatarnamecache.cpp | 4 +- indra/llmessage/llcurlrequest.cpp | 149 ------ indra/llmessage/llcurlrequest.h | 57 --- indra/llmessage/llhttpclient.cpp | 32 +- indra/llmessage/llhttpclient.h | 72 +-- indra/llmessage/llhttpclientadapter.cpp | 6 +- indra/llmessage/llhttpsender.cpp | 2 +- indra/llmessage/llsdmessage.cpp | 2 +- indra/llmessage/llurlrequest.cpp | 479 ------------------ indra/llmessage/llurlrequest.h | 290 ----------- indra/newview/floatervoicelicense.cpp | 2 +- indra/newview/hgfloatertexteditor.cpp | 2 +- indra/newview/hipporestrequest.cpp | 345 ------------- indra/newview/hipporestrequest.h | 95 ---- indra/newview/lggdicdownload.cpp | 4 +- indra/newview/llaccountingcostmanager.cpp | 2 +- indra/newview/llagent.cpp | 2 +- indra/newview/llagentlanguage.cpp | 2 +- indra/newview/llassetuploadqueue.cpp | 4 +- indra/newview/llassetuploadresponders.cpp | 8 +- indra/newview/llcapabilitylistener.cpp | 2 +- indra/newview/llcaphttpsender.cpp | 2 +- indra/newview/lleventpoll.cpp | 2 +- indra/newview/llfloateractivespeakers.cpp | 6 +- indra/newview/llfloatermodeluploadbase.cpp | 2 +- indra/newview/llfloaterpostcard.cpp | 2 +- indra/newview/llfloaterregiondebugconsole.cpp | 4 +- indra/newview/llfloaterregioninfo.cpp | 4 +- indra/newview/llfloaterreporter.cpp | 4 +- indra/newview/llfloaterteleport.cpp | 2 +- indra/newview/llfloatertos.cpp | 2 +- indra/newview/llfloaterurlentry.cpp | 2 +- indra/newview/llimpanel.cpp | 6 +- indra/newview/llimview.cpp | 6 +- indra/newview/llinventorymodel.cpp | 2 +- .../llinventorymodelbackgroundfetch.cpp | 8 +- indra/newview/llinventoryobserver.cpp | 2 +- indra/newview/llmeshrepository.cpp | 68 +-- indra/newview/llmeshrepository.h | 5 - indra/newview/llpanelclassified.cpp | 4 +- indra/newview/llpanelgroupvoting.cpp | 4 +- indra/newview/llpanellogin.cpp | 2 +- indra/newview/llpanelplace.cpp | 2 +- indra/newview/llpathfindingmanager.cpp | 18 +- indra/newview/llpreviewgesture.cpp | 4 +- indra/newview/llpreviewnotecard.cpp | 4 +- indra/newview/llpreviewscript.cpp | 4 +- indra/newview/llproductinforequest.cpp | 2 +- indra/newview/lltexlayer.cpp | 2 +- indra/newview/lltexturefetch.cpp | 33 +- indra/newview/lltexturefetch.h | 6 - indra/newview/lltexturestatsuploader.cpp | 2 +- indra/newview/lltranslate.cpp | 2 +- indra/newview/lluserauth.h | 1 - indra/newview/llviewerdisplayname.cpp | 2 +- indra/newview/llviewerinventory.cpp | 2 +- indra/newview/llviewermedia.cpp | 6 +- indra/newview/llviewermenufile.cpp | 4 +- indra/newview/llviewermessage.cpp | 2 +- indra/newview/llviewerobjectbackup.cpp | 2 +- indra/newview/llviewerobjectlist.cpp | 4 +- indra/newview/llviewerparcelmedia.cpp | 2 +- indra/newview/llviewerparcelmgr.cpp | 2 +- indra/newview/llviewerregion.cpp | 8 +- indra/newview/llviewerstats.cpp | 2 +- indra/newview/llvoiceclient.cpp | 4 +- indra/newview/llwaterparammanager.cpp | 2 +- indra/newview/llwlhandlers.cpp | 4 +- indra/newview/llwlparammanager.cpp | 2 +- indra/newview/llworldmap.cpp | 2 +- 72 files changed, 172 insertions(+), 1662 deletions(-) delete mode 100644 indra/llmessage/llcurlrequest.cpp delete mode 100644 indra/llmessage/llcurlrequest.h delete mode 100644 indra/newview/hipporestrequest.cpp delete mode 100644 indra/newview/hipporestrequest.h diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index f5e9a1932..9195aafe0 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -320,7 +320,7 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg for(int i = 0; i < retries; ++i) { status_message = llformat("%s, try %d...", msg.c_str(), i+1); - LLHTTPClient::post4(host, data, new LLCrashLoggerResponder); + LLHTTPClient::post(host, data, new LLCrashLoggerResponder); while(!gBreak) { updateApplication(status_message); diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 046e77b0e..de096ba31 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -36,7 +36,6 @@ set(llmessage_SOURCE_FILES llchainio.cpp llcircuit.cpp llclassifiedflags.cpp - llcurlrequest.cpp lldatapacker.cpp lldispatcher.cpp llfiltersd2xmlrpc.cpp @@ -123,7 +122,6 @@ set(llmessage_HEADER_FILES llcircuit.h llclassifiedflags.h llcurl.h - llcurlrequest.h lldatapacker.h lldbstrings.h lldispatcher.h diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 57affabfe..36518df4b 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -385,7 +385,7 @@ void LLAvatarNameCache::requestNamesViaCapability() LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first " << ids << " ids" << LL_ENDL; - LLHTTPClient::get4(url, new LLAvatarNameResponder(agent_ids)); + LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } @@ -396,7 +396,7 @@ void LLAvatarNameCache::requestNamesViaCapability() LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all " << ids << " ids" << LL_ENDL; - LLHTTPClient::get4(url, new LLAvatarNameResponder(agent_ids)); + LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); url.clear(); agent_ids.clear(); } diff --git a/indra/llmessage/llcurlrequest.cpp b/indra/llmessage/llcurlrequest.cpp deleted file mode 100644 index 72de85774..000000000 --- a/indra/llmessage/llcurlrequest.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/** - * @file llcurlrequest.cpp - * @brief Implementation of Request. - * - * Copyright (c) 2012, Aleric Inglewood. - * Copyright (C) 2010, Linden Research, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution. - * - * CHANGELOG - * and additional copyright holders. - * - * 17/03/2012 - * Initial version, written by Aleric Inglewood @ SL - * - * 20/03/2012 - * Added copyright notice for Linden Lab for those parts that were - * copied or derived from llcurl.cpp. The code of those parts are - * already in their own llcurl.cpp, so they do not ever need to - * even look at this file; the reason I added the copyright notice - * is to make clear that I am not the author of 100% of this code - * and hence I cannot change the license of it. - */ - -#include "linden_common.h" - -#include "llsdserialize.h" -#include "llcurlrequest.h" -#include "llbufferstream.h" -#include "aicurleasyrequeststatemachine.h" -#include "aihttpheaders.h" - -//----------------------------------------------------------------------------- -// class Request -// - -namespace AICurlInterface { - -bool Request::get2(std::string const& url, ResponderPtr responder) -{ - AIHTTPHeaders empty_headers; - return getByteRange2(url, empty_headers, 0, -1, responder); -} - -bool Request::getByteRange2(std::string const& url, AIHTTPHeaders const& headers, S32 offset, S32 length, ResponderPtr responder) -{ - DoutEntering(dc::curl, "Request::getByteRange(" << url << ", ...)"); - - // This might throw AICurlNoEasyHandle. - AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true); - - { - AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); - - AICurlResponderBuffer_wat(*buffered_easy_request->mCurlEasyRequest)->prepRequest(buffered_easy_request_w, headers, responder); - - buffered_easy_request_w->setopt(CURLOPT_HTTPGET, 1); - if (length > 0) - { - std::string range = llformat("Range: bytes=%d-%d", offset, offset + length - 1); - buffered_easy_request_w->addHeader(range.c_str()); - } - - buffered_easy_request_w->finalizeRequest(url, responder->getHTTPTimeoutPolicy(), buffered_easy_request); - } - - buffered_easy_request->run(); - - return true; // We throw in case of problems. -} - -bool Request::post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder) -{ - DoutEntering(dc::curl, "Request::post(" << url << ", ...)"); - - // This might throw AICurlNoEasyHandle. - AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true); - - { - AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); - AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest); - - buffer_w->prepRequest(buffered_easy_request_w, headers, responder); - - U32 bytes = data.size(); - bool success = buffer_w->getInput()->append(buffer_w->sChannels.out(), (U8 const*)data.data(), bytes); - if (!success) - { - buffered_easy_request->kill(); - throw AICurlNoBody("LLBufferArray::copyIntoBuffers() returned false"); - } - buffered_easy_request_w->setPost(bytes); - buffered_easy_request_w->addHeader("Content-Type: application/octet-stream"); - buffered_easy_request_w->finalizeRequest(url, responder->getHTTPTimeoutPolicy(), buffered_easy_request); - } - - buffered_easy_request->run(); - - return true; // We throw in case of problems. -} - -bool Request::post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder) -{ - DoutEntering(dc::curl, "Request::post(" << url << ", ...)"); - - // This might throw AICurlNoEasyHandle. - AICurlEasyRequestStateMachine* buffered_easy_request = new AICurlEasyRequestStateMachine(true); - - { - AICurlEasyRequest_wat buffered_easy_request_w(*buffered_easy_request->mCurlEasyRequest); - AICurlResponderBuffer_wat buffer_w(*buffered_easy_request->mCurlEasyRequest); - - buffer_w->prepRequest(buffered_easy_request_w, headers, responder); - - LLBufferStream buffer_stream(buffer_w->sChannels, buffer_w->getInput().get()); - LLSDSerialize::toXML(data, buffer_stream); - // Need to flush the LLBufferStream or countAfter() returns more than the written data. - buffer_stream << std::flush; - S32 bytes = buffer_w->getInput()->countAfter(buffer_w->sChannels.out(), NULL); - buffered_easy_request_w->setPost(bytes); - buffered_easy_request_w->addHeader("Content-Type: application/llsd+xml"); - buffered_easy_request_w->finalizeRequest(url, responder->getHTTPTimeoutPolicy(), buffered_easy_request); - - lldebugs << "POSTING: " << bytes << " bytes." << llendl; - } - - buffered_easy_request->run(); - - return true; // We throw in case of problems. -} - -} // namespace AICurlInterface -//================================================================================== - diff --git a/indra/llmessage/llcurlrequest.h b/indra/llmessage/llcurlrequest.h deleted file mode 100644 index 4fe172b46..000000000 --- a/indra/llmessage/llcurlrequest.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file llcurlrequest.h - * @brief Declaration of class Request - * - * Copyright (c) 2012, Aleric Inglewood. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution. - * - * CHANGELOG - * and additional copyright holders. - * - * 17/03/2012 - * Initial version, written by Aleric Inglewood @ SL - */ - -#ifndef AICURLREQUEST_H -#define AICURLREQUEST_H - -#include -#include -#include - -class AIHTTPHeaders; - -// Things defined in this namespace are called from elsewhere in the viewer code. -namespace AICurlInterface { - -// Forward declaration. -class ResponderBase; -typedef boost::intrusive_ptr ResponderPtr; - -class Request { - public: - bool get2(std::string const& url, ResponderPtr responder); - bool getByteRange2(std::string const& url, AIHTTPHeaders const& headers, S32 offset, S32 length, ResponderPtr responder); - bool post2(std::string const& url, AIHTTPHeaders const& headers, std::string const& data, ResponderPtr responder); - bool post3(std::string const& url, AIHTTPHeaders const& headers, LLSD const& data, ResponderPtr responder); -}; - -} // namespace AICurlInterface - -#endif diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index b94a17ee4..259b671d4 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -221,7 +221,7 @@ static void request( req->run(); } -void LLHTTPClient::getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers) { if(offset > 0 || bytes > 0) { @@ -230,27 +230,27 @@ void LLHTTPClient::getByteRange4(std::string const& url, S32 offset, S32 bytes, request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); } -void LLHTTPClient::head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::head(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); } -void LLHTTPClient::get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_GET, NULL, responder, headers); } -void LLHTTPClient::getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers); } -void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers) { LLURI uri; uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query); - get4(uri.asString(), responder, headers); + get(uri.asString(), responder, headers); } //============================================================================= @@ -385,17 +385,17 @@ static LLSD blocking_request( if (method == HTTP_LLSD_POST) { responder = new BlockingLLSDPostResponder; - LLHTTPClient::post4(url, body, responder, headers); + LLHTTPClient::post(url, body, responder, headers); } else if (method == HTTP_LLSD_GET) { responder = new BlockingLLSDGetResponder; - LLHTTPClient::get4(url, responder, headers); + LLHTTPClient::get(url, responder, headers); } else // method == HTTP_RAW_GET { responder = new BlockingRawGetResponder; - LLHTTPClient::get4(url, responder, headers); + LLHTTPClient::get(url, responder, headers); } responder->wait(); @@ -474,12 +474,12 @@ U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body) return result["status"].asInteger(); } -void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers); } -void LLHTTPClient::post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers); } @@ -500,29 +500,29 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression. } -void LLHTTPClient::postRaw4(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers); } -void LLHTTPClient::postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers); } -void LLHTTPClient::postFile4(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers); } // static -void LLHTTPClient::del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers) { request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers); } // static -void LLHTTPClient::move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers) { headers.addHeader("Destination", destination); request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers); diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 6c8718344..5234ec736 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -58,33 +58,33 @@ public: /** @name non-blocking API */ //@{ - static void head4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); - static void head4(std::string const& url, ResponderPtr responder) - { AIHTTPHeaders headers; head4(url, responder, headers); } + static void head(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void head(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; head(url, responder, headers); } - static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers); - static void getByteRange4(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder) - { AIHTTPHeaders headers; getByteRange4(url, offset, bytes, responder, headers); } + static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers); + static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder) + { AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers); } - static void get4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); - static void get4(std::string const& url, ResponderPtr responder) - { AIHTTPHeaders headers; get4(url, responder, headers); } + static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void get(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; get(url, responder, headers); } - static void get4(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers); - static void get4(std::string const& url, LLSD const& query, ResponderPtr responder) - { AIHTTPHeaders headers; get4(url, query, responder, headers); } + static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers); + static void get(std::string const& url, LLSD const& query, ResponderPtr responder) + { AIHTTPHeaders headers; get(url, query, responder, headers); } - static void put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); - static void put4(std::string const& url, LLSD const& body, ResponderPtr responder) - { AIHTTPHeaders headers; put4(url, body, responder, headers); } + static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); + static void put(std::string const& url, LLSD const& body, ResponderPtr responder) + { AIHTTPHeaders headers; put(url, body, responder, headers); } - static void getHeaderOnly4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); - static void getHeaderOnly4(std::string const& url, ResponderPtr responder) - { AIHTTPHeaders headers; getHeaderOnly4(url, responder, headers); } + static void getHeaderOnly(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void getHeaderOnly(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); } - static void post4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); - static void post4(std::string const& url, LLSD const& body, ResponderPtr responder) - { AIHTTPHeaders headers; post4(url, body, responder, headers); } + static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); + static void post(std::string const& url, LLSD const& body, ResponderPtr responder) + { AIHTTPHeaders headers; post(url, body, responder, headers); } /** Takes ownership of request and deletes it when sent */ static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers); @@ -96,21 +96,21 @@ public: { AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); } /** Takes ownership of data and deletes it when sent */ - static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers); - static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder) - { AIHTTPHeaders headers; postRaw4(url, data, size, responder, headers); } + static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers); + static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder) + { AIHTTPHeaders headers; postRaw(url, data, size, responder, headers); } - static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers); - static void postFile4(std::string const& url, std::string const& filename, ResponderPtr responder) - { AIHTTPHeaders headers; postFile4(url, filename, responder, headers); } + static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers); + static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder) + { AIHTTPHeaders headers; postFile(url, filename, responder, headers); } - static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers); - static void postFile4(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder) - { AIHTTPHeaders headers; postFile4(url, uuid, asset_type, responder, headers); } + static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers); + static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder) + { AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers); } - static void del4(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); - static void del4(std::string const& url, ResponderPtr responder) - { AIHTTPHeaders headers; del4(url, responder, headers); } + static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); + static void del(std::string const& url, ResponderPtr responder) + { AIHTTPHeaders headers; del(url, responder, headers); } ///< sends a DELETE method, but we can't call it delete in c++ @@ -123,9 +123,9 @@ public: * @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 move4(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers); - static void move4(std::string const& url, std::string const& destination, ResponderPtr responder) - { AIHTTPHeaders headers; move4(url, destination, responder, headers); } + static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers); + static void move(std::string const& url, std::string const& destination, ResponderPtr responder) + { AIHTTPHeaders headers; move(url, destination, responder, headers); } //@} diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index d1c42a665..3c064d61b 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -36,18 +36,18 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo // Pragma is required to stop curl adding "no-cache" // Space is required to stop llurlrequest from turnning off proxying AIHTTPHeaders empty_pragma_header("Pragma", " "); - LLHTTPClient::get4(url, responder, empty_pragma_header); + LLHTTPClient::get(url, responder, empty_pragma_header); } void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) { // as above AIHTTPHeaders empty_pragma_header("Pragma", " "); - LLHTTPClient::get4(url, responder, empty_pragma_header); + LLHTTPClient::get(url, responder, empty_pragma_header); } void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) { - LLHTTPClient::put4(url, body, responder); + LLHTTPClient::put(url, body, responder); } diff --git a/indra/llmessage/llhttpsender.cpp b/indra/llmessage/llhttpsender.cpp index 195548abe..c48cbc42a 100644 --- a/indra/llmessage/llhttpsender.cpp +++ b/indra/llmessage/llhttpsender.cpp @@ -55,7 +55,7 @@ void LLHTTPSender::send(const LLHost& host, const std::string& name, std::ostringstream stream; stream << "http://" << host << "/trusted-message/" << name; llinfos << "LLHTTPSender::send: POST to " << stream.str() << llendl; - LLHTTPClient::post4(stream.str(), body, response); + LLHTTPClient::post(stream.str(), body, response); } //static diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index e833abee5..52869f3ef 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -83,7 +83,7 @@ bool LLSDMessage::httpListener(const LLSD& request) LLSDMessage::EventResponder* responder = new LLSDMessage::EventResponder(LLEventPumps::instance(), request, url, "POST", reply, error); responder->setTimeoutPolicy(timeoutpolicy); - LLHTTPClient::post4(url, payload, responder); + LLHTTPClient::post(url, payload, responder); return false; } diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 5d5d4d6b3..8dea0c9b2 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -54,43 +54,6 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499; */ const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); - -//static size_t headerCallback(char* data, size_t size, size_t nmemb, void* user); - -#if 0 -/** - * class LLURLRequestDetail - */ -class LLURLRequestDetail -{ -public: - LLURLRequestDetail(); - ~LLURLRequestDetail(); - std::string mURL; - AICurlEasyRequestStateMachine* mStateMachine; - LLIOPipe::buffer_ptr_t mResponseBuffer; - LLChannelDescriptors mChannels; - U8* mLastRead; - U32 mBodyLimit; - S32 mByteAccumulator; - bool mIsBodyLimitSet; -}; - -LLURLRequestDetail::LLURLRequestDetail() : - mStateMachine(new AICurlEasyRequestStateMachine(false)), - mLastRead(NULL), - mBodyLimit(0), - mByteAccumulator(0), - mIsBodyLimitSet(false) -{ -} - -LLURLRequestDetail::~LLURLRequestDetail() -{ - mLastRead = NULL; -} -#endif - /** * class LLURLRequest */ @@ -186,39 +149,12 @@ void LLURLRequest::initialize_impl(void) } } -#if 0 -void LLURLRequest::setURL2(const std::string& url) -{ - mDetail->mURL = url; -} - -std::string LLURLRequest::getURL2() const -{ - return mDetail->mURL; -} -#endif - void LLURLRequest::addHeader(const char* header) { AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); curlEasyRequest_w->addHeader(header); } -#ifdef AI_UNUSED -void LLURLRequest::setBodyLimit(U32 size) -{ - mDetail->mBodyLimit = size; - mDetail->mIsBodyLimitSet = true; -} - -void LLURLRequest::setCallback(LLURLRequestComplete* callback) -{ - mCompletionCallback = callback; - AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); - curlEasyRequest_w->setHeaderCallback(&headerCallback, (void*)callback); -} -#endif - // 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 @@ -270,226 +206,6 @@ void LLURLRequest::allowCookies() curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, ""); } -#ifdef AI_UNUSED // no longer derived from LLIOPipe -//virtual -bool LLURLRequest::hasExpiration(void) const -{ - // Currently, this ALWAYS returns false -- because only AICurlEasyRequestStateMachine uses buffered - // AICurlEasyRequest objects, and LLURLRequest uses (unbuffered) AICurlEasyRequest directly, which - // have no expiration facility. - return mDetail->mStateMachine->isBuffered(); -} - -//virtual -bool LLURLRequest::hasNotExpired(void) const -{ - if (!mDetail->mStateMachine->isBuffered()) - return true; - AICurlEasyRequest_wat buffered_easy_request_w(*mCurlEasyRequest); - AICurlResponderBuffer_wat buffer_w(*mCurlEasyRequest); - return buffer_w->isValid(); -} - -// virtual -LLIOPipe::EStatus LLURLRequest::handleError( - LLIOPipe::EStatus status, - LLPumpIO* pump) -{ - DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ") [" << (void*)mCurlEasyRequest.get_ptr().get() << "]"); - - if (LL_LIKELY(!mDetail->mStateMachine->isBuffered())) // Currently always true. - { - // The last reference will be deleted when the pump that this chain belongs to - // is removed from the running chains vector, upon returning from this function. - // This keeps the CurlEasyRequest object alive until the curl thread cleanly removed it. - Dout(dc::curl, "Calling mDetail->mStateMachine->removeRequest() [" << (void*)mCurlEasyRequest.get_ptr().get() << "]"); - mDetail->mStateMachine->removeRequest(); - } - else if (!hasNotExpired()) - { - // The buffered version has it's own time out handling, and that already expired, - // so we can ignore the expiration of this timer (currently never happens). - // I left it here because it's what LL did (in the form if (!isValid() ...), - // and it would be relevant if this characteristic of mDetail->mStateMachine - // would change. --Aleric - return STATUS_EXPIRED ; - } - - if(mCompletionCallback && pump) - { - LLURLRequestComplete* complete = NULL; - complete = (LLURLRequestComplete*)mCompletionCallback.get(); - complete->httpStatus( - HTTP_STATUS_PIPE_ERROR, - LLIOPipe::lookupStatusString(status)); - complete->responseStatus(status); - pump->respond(complete); - mCompletionCallback = NULL; - } - return status; -} - -static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request"); - -// virtual -LLIOPipe::EStatus LLURLRequest::process_impl( - const LLChannelDescriptors& channels, - buffer_ptr_t& buffer, - bool& eos, - LLSD& context, - LLPumpIO* pump) -{ - LLFastTimer t(FTM_PROCESS_URL_REQUEST); - PUMP_DEBUG; - //llinfos << "LLURLRequest::process_impl()" << llendl; - if (!buffer) return STATUS_ERROR; - - if (!mDetail) return STATUS_ERROR; //Seems to happen on occasion. Need to hunt down why. - - // we're still waiting or processing, check how many - // bytes we have accumulated. - const S32 MIN_ACCUMULATION = 100000; - if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) - { - static LLFastTimer::DeclareTimer FTM_URL_ADJUST_TIMEOUT("Adjust Timeout"); - LLFastTimer t(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); - lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl; - if (mState == STATE_INITIALIZED) - { - llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl; - } - } - - 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; - } - mRemoved = false; - mState = STATE_WAITING_FOR_RESPONSE; - mDetail->mStateMachine->addRequest(); // Add easy handle to multi handle. - - return STATUS_BREAK; - } - case STATE_WAITING_FOR_RESPONSE: - case STATE_PROCESSING_RESPONSE: - { - if (!mRemoved) // Not removed from multi handle yet? - { - // Easy handle is still being processed. - return STATUS_BREAK; - } - // Curl thread finished with this easy handle. - mState = STATE_CURL_FINISHED; - } - case STATE_CURL_FINISHED: - { - PUMP_DEBUG; - LLIOPipe::EStatus status = STATUS_NO_CONNECTION; // Catch-all failure code. - - // Left braces in order not to change indentation. - { - CURLcode result; - - static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); - - AICurlEasyRequest_wat(*mCurlEasyRequest)->getResult(&result); - - mState = STATE_HAVE_RESPONSE; - context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; - context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; - lldebugs << this << "Setting context to " << context << llendl; - 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); - static LLFastTimer::DeclareTimer FTM_PROCESS_URL_PUMP_RESPOND("Pump Respond"); - { - LLFastTimer t(FTM_PROCESS_URL_PUMP_RESPOND); - pump->respond(chain, buffer, context); - } - mCompletionCallback = NULL; - } - status = STATUS_BREAK; // This is what the old code returned. Does it make sense? - break; - case CURLE_FAILED_INIT: - case CURLE_COULDNT_CONNECT: - status = STATUS_NO_CONNECTION; - break; - default: - llwarns << "URLRequest Error: " << result - << ", " - << LLCurl::strerror(result) - << ", " - << (mDetail->mURL.empty() ? "" : mDetail->mURL) - << llendl; - status = STATUS_ERROR; - 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; - lldebugs << this << "Setting context to " << context << llendl; - return STATUS_DONE; - - default: - PUMP_DEBUG; - context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; - context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; - lldebugs << this << "Setting context to " << context << llendl; - return STATUS_ERROR; - } -} -#endif // AI_UNUSED - bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) { bool rv = false; @@ -559,198 +275,3 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) } return rv; } - -#if 0 -// 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(char* header_line, size_t size, size_t nmemb, void* user) -{ - 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((U32)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()) - { - llwarns << "Unable to parse header: " << header << llendl; - } - } - - return header_len; -} -#endif - -#ifdef AI_UNUSED -/** - * 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) -{ - llwarns << "LLURLRequestComplete::response default implementation called" - << llendl; -} - -//virtual -void LLURLRequestComplete::noResponse() -{ - llwarns << "LLURLRequestComplete::noResponse default implementation called" - << llendl; -} - -void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status) -{ - mRequestStatus = status; -} - -static LLFastTimer::DeclareTimer 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) -{ - LLFastTimer t(FTM_PROCESS_URL_COMPLETE); - PUMP_DEBUG; - complete(channels, buffer); - return STATUS_OK; -} -#endif diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 3244f0035..a356ed786 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -126,294 +126,4 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { /*virtual*/ void initialize_impl(void); }; -#if 0 -extern const std::string CONTEXT_REQUEST; -extern const std::string CONTEXT_RESPONSE; -extern const std::string CONTEXT_TRANSFERED_BYTES; - -class LLURLRequestDetail; - -class LLURLRequestComplete; - -struct x509_store_ctx_st; -typedef struct x509_store_ctx_st X509_STORE_CTX; - -/** - * @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 This enumeration is for specifying the type of request. - */ - enum ERequestAction - { - INVALID, - HTTP_HEAD, - HTTP_GET, - HTTP_PUT, - HTTP_POST, - HTTP_DELETE, - HTTP_MOVE, // Caller will need to set 'Destination' header - REQUEST_ACTION_COUNT - }; - - /** - * @brief Turn the requst action into an http verb. - */ - static std::string actionAsVerb(ERequestAction action); - - /** - * @brief Constructor. - * - * @param action One of the ERequestAction enumerations. - */ - LLURLRequest(ERequestAction action); - - /** - * @brief Constructor. - * - * @param action One of the ERequestAction enumerations. - * @param url The url of the request. It should already be encoded. - */ - LLURLRequest(ERequestAction action, const std::string& url); - - /** - * @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); - std::string getURL() const; - /** - * @brief Add a header to the http post. - * - * The header must be correctly formatted for HTTP requests. This - * provides a raw interface if you know what kind of request you - * will be making during construction of this instance. All - * required headers will be automatically constructed, so this is - * usually useful for encoding parameters. - */ - void addHeader(const char* header); - - /** - * @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); - //@} - - /** - * @ 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(); - - /* @name LLIOPipe virtual implementations - */ - - /*virtual*/ bool hasExpiration(void) const; - /*virtual*/ bool hasNotExpired(void) const; - -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_CURL_FINISHED, - STATE_HAVE_RESPONSE, - }; - EState mState; - ERequestAction mAction; - LLURLRequestDetail* mDetail; - LLIOPipe::ptr_t mCompletionCallback; - S32 mRequestTransferedBytes; - S32 mResponseTransferedBytes; - - bool mRemoved; - -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 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(U32 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 useage from the LLURLRequest instance. - EStatus mRequestStatus; -}; -#endif - #endif // LL_LLURLREQUEST_H diff --git a/indra/newview/floatervoicelicense.cpp b/indra/newview/floatervoicelicense.cpp index 8badf0e30..ca887663b 100644 --- a/indra/newview/floatervoicelicense.cpp +++ b/indra/newview/floatervoicelicense.cpp @@ -133,7 +133,7 @@ BOOL FloaterVoiceLicense::postBuild() std::string url = getString( "real_url" ); if(url.substr(0,4) == "http") { gResponsePtr = LLIamHereVoice::build( this ); - LLHTTPClient::get4( url, gResponsePtr ); + LLHTTPClient::get( url, gResponsePtr ); } else { setSiteIsAlive(false); } diff --git a/indra/newview/hgfloatertexteditor.cpp b/indra/newview/hgfloatertexteditor.cpp index 61ea390bf..12342b4ba 100644 --- a/indra/newview/hgfloatertexteditor.cpp +++ b/indra/newview/hgfloatertexteditor.cpp @@ -364,7 +364,7 @@ void HGFloaterTextEditor::onClickSave(void* user_data) if(caps) { - LLHTTPClient::post4(url, body, + LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, fake_asset_id, item->getType())); } } diff --git a/indra/newview/hipporestrequest.cpp b/indra/newview/hipporestrequest.cpp deleted file mode 100644 index 107310759..000000000 --- a/indra/newview/hipporestrequest.cpp +++ /dev/null @@ -1,345 +0,0 @@ - -#include "llviewerprecompiledheaders.h" - -#include "hipporestrequest.h" - -#ifndef CURL_STATICLIB -#define CURL_STATICLIB 1 -#endif - -#include -#include "llbufferstream.h" -#include "llerror.h" -#include "llhttpclient.h" -#include "llurlrequest.h" -#include "llxmltree.h" - -#include -#ifdef DEBUG_CURLIO -#include "debug_libcurl.h" -#endif - -// ******************************************************************** - - -class HippoRestComplete /* AIFIXME: public LLURLRequestComplete*/ -{ - public: - HippoRestComplete(HippoRestHandler *handler) : - mHandler(handler), - mStatus(499), - mReason("Request completed w/o status") - { - } - - ~HippoRestComplete() - { - delete mHandler; - } - - // Called once for each header received, prior to httpStatus - void header(const std::string& header, const std::string& value) - { - mHandler->addHeader(header, value); - } - -#if 0 // AIFIXME: doesn't compile - // Always called on request completion, prior to complete - void httpStatus(U32 status, const std::string& reason) - { - LLURLRequestComplete::httpStatus(status, reason); - mStatus = status; - mReason = reason; - } - - void complete(const LLChannelDescriptors &channels, const buffer_ptr_t &buffer) - { - mHandler->handle(mStatus, mReason, channels, buffer); - } -#endif - - private: - HippoRestHandler *mHandler; - int mStatus; - std::string mReason; -}; - - -// ******************************************************************** - - -static std::string gEmptyString; - -void HippoRestHandler::addHeader(const std::string &header, const std::string &content) -{ - mHeaders[header] = content; -} - -bool HippoRestHandler::hasHeader(const std::string &header) const -{ - return (mHeaders.find(header) != mHeaders.end()); -} - -const std::string &HippoRestHandler::getHeader(const std::string &header) const -{ - std::map::const_iterator it; - it = mHeaders.find(header); - if (it != mHeaders.end()) { - return it->second; - } else { - return gEmptyString; - } -} - - -// ******************************************************************** - - -void HippoRestHandlerRaw::handle(int status, const std::string &reason, - const LLChannelDescriptors &channels, - const boost::shared_ptr &body) -{ - if (status == 200) { - std::string data; - LLBufferArray *buffer = body.get(); - LLBufferArray::segment_iterator_t it, end = buffer->endSegment(); - for (it=buffer->beginSegment(); it!=end; ++it) - if (it->isOnChannel(channels.in())) - data.append((char*)it->data(), it->size()); - result(data); - } else { - llwarns << "Rest request error " << status << ": " << reason << llendl; - } -} - -void HippoRestHandlerXml::handle(int status, const std::string &reason, - const LLChannelDescriptors &channels, - const boost::shared_ptr &body) -{ - if (status == 200) { - LLXmlTree *tree = new LLXmlTree(); - bool success = tree->parseBufferStart(); - LLBufferArray *buffer = body.get(); - LLBufferArray::segment_iterator_t it, end = buffer->endSegment(); - for (it=buffer->beginSegment(); success && (it!=end); ++it) - if (it->isOnChannel(channels.in())) - success = success && tree->parseBuffer((char*)it->data(), it->size()); - success = success && tree->parseBufferFinalize(); - if (success) result(tree); - delete tree; - } else { - llwarns << "Rest request error " << status << ": " << reason << llendl; - } -} - - -// ******************************************************************** - -class BodyDataRaw : public Injector -{ - public: - explicit BodyDataRaw(const std::string &data) : mData(data) { } - - /*virtual*/ char const* contentType(void) const { return "application/octet-stream"; } - - /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) - { - LLBufferStream ostream(channels, buffer.get()); - ostream.write(mData.data(), mData.size()); - ostream << std::flush; - return mData.size(); - } - - private: - std::string mData; -}; - -class BodyDataXml : public Injector -{ - public: - explicit BodyDataXml(const LLXmlTree *tree) : - mTree(tree) - { - } - - virtual ~BodyDataXml() - { - if (mTree) delete mTree; - } - - /*virtual*/ char const* contentType(void) const { return "application/xml"; } - - /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) - { - std::string data; - mTree->write(data); - LLBufferStream ostream(channels, buffer.get()); - ostream.write(data.data(), data.size()); - ostream << std::flush; - return data.size(); - } - - private: - const LLXmlTree *mTree; -}; - - -// ******************************************************************** - - -static void request(const std::string &url, - LLURLRequest::ERequestAction method, - Injector *body, - HippoRestHandler *handler, float timeout); - - -// static -void HippoRestRequest::get5(const std::string &url, - HippoRestHandler *handler, float timeout) -{ - request(url, LLURLRequest::HTTP_GET, 0, handler, timeout); -} - -// static -void HippoRestRequest::put5(const std::string &url, const std::string &body, - HippoRestHandler *handler, float timeout) -{ - request(url, LLURLRequest::HTTP_PUT, new BodyDataRaw(body), handler, timeout); -} - -// static -void HippoRestRequest::put5(const std::string &url, const LLXmlTree *body, - HippoRestHandler *handler, float timeout) -{ - request(url, LLURLRequest::HTTP_PUT, new BodyDataXml(body), handler, timeout); -} - -// static -void HippoRestRequest::post5(const std::string &url, const std::string &body, - HippoRestHandler *handler, float timeout) -{ - request(url, LLURLRequest::HTTP_POST, new BodyDataRaw(body), handler, timeout); -} - -// static -void HippoRestRequest::post5(const std::string &url, const LLXmlTree *body, - HippoRestHandler *handler, float timeout) -{ - request(url, LLURLRequest::HTTP_POST, new BodyDataXml(body), handler, timeout); -} - - -// ******************************************************************** - - -static void request(const std::string &url, - LLURLRequest::ERequestAction method, - Injector *body, - HippoRestHandler *handler, float timeout) -{ - LLURLRequest *req; - try - { - AIHTTPHeaders empty_headers; - //AIFIXME (doesn't compile): req = new LLURLRequest(method, url, body, handler, empty_headers); - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "Failed to create LLURLRequest: " << error.what() << llendl; - return; - } - // Already done by default. req->checkRootCertificate(true); - - /* - // Insert custom headers if the caller sent any - if (headers.isMap()) - { - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator end = headers.endMap(); - - for (; iter != end; ++iter) - { - std::ostringstream header; - //if the header is "Pragma" with no value - //the caller intends to force libcurl to drop - //the Pragma header it so gratuitously inserts - //Before inserting the header, force libcurl - //to not use the proxy (read: llurlrequest.cpp) - static const std::string PRAGMA("Pragma"); - if ((iter->first == PRAGMA) && (iter->second.asString().empty())) - { - req->useProxy(false); - } - header << iter->first << ": " << iter->second.asString() ; - lldebugs << "header = " << header.str() << llendl; - req->addHeader(header.str().c_str()); - } - } - */ - - if ((method != LLURLRequest::HTTP_PUT) && (method != LLURLRequest::HTTP_POST)) { - std::string accept = "Accept: "; - accept += handler->getAcceptMimeType(); - //AIFIXME req is not defined: req->addHeader(accept.c_str()); - } - - //AIFIXME: req->setCallback(new HippoRestComplete(handler)); - - if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) { - std::string content = "Content-Type: "; - content += body->contentType(); - //AIFIXME req is not defined: req->addHeader(content.c_str()); - //AIFIXME: chain.push_back(LLIOPipe::ptr_t(body)); - } - - //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req)); - //LLHTTPClient::getPump().addChain(chain, timeout); -} - - -// ******************************************************************** - - -static size_t curlWrite(void *ptr, size_t size, size_t nmemb, void *userData) -{ - std::string *result = (std::string*)userData; - size_t bytes = (size * nmemb); - result->append((char*)ptr, bytes); - return nmemb; -} - - -// static -int HippoRestRequest::getBlocking(const std::string &url, std::string *result) -{ - llinfos << "Requesting: " << url << llendl; - - char curlErrorBuffer[CURL_ERROR_SIZE]; - CURL* curlp = curl_easy_init(); - llassert_always(curlp); - - curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts - curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 30); // seconds (including DNS lookups) - curl_easy_setopt(curlp, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str()); - - curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, curlWrite); - curl_easy_setopt(curlp, CURLOPT_WRITEDATA, result); - curl_easy_setopt(curlp, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curlErrorBuffer); - curl_easy_setopt(curlp, CURLOPT_FAILONERROR, 1); - - *result = ""; - S32 curlSuccess = curl_easy_perform(curlp); - long httpStatus = 499L; // curl_easy_getinfo demands pointer to long. - curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &httpStatus); - - if (curlSuccess != 0) { - llwarns << "CURL ERROR (HTTP Status " << httpStatus << "): " << curlErrorBuffer << llendl; - } else if (httpStatus != 200) { - llwarns << "HTTP Error " << httpStatus << ", but no Curl error." << llendl; - } - - curl_easy_cleanup(curlp); - return httpStatus; -} - diff --git a/indra/newview/hipporestrequest.h b/indra/newview/hipporestrequest.h deleted file mode 100644 index 99f85929c..000000000 --- a/indra/newview/hipporestrequest.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef __HIPPO_REST_REQUEST_H__ -#define __HIPPO_REST_REQUEST_H__ - -#include -#include - -#include - -class LLBufferArray; -class LLChannelDescriptors; -class LLXmlTree; - -#define HIPPO_REST_TIMEOUT 60.f - -// ******************************************************************** - -class HippoRestHandler -{ - public: - virtual ~HippoRestHandler() { } - - virtual const char *getAcceptMimeType() const = 0; - - bool hasHeader(const std::string &header) const; - const std::string &getHeader(const std::string &header) const; - - private: - // These functions are called by the request engine - void addHeader(const std::string &header, const std::string &content); - virtual void handle(int status, const std::string &reason, - const LLChannelDescriptors &channels, - const boost::shared_ptr &body) = 0; - - std::map mHeaders; - - friend class HippoRestComplete; -}; - -class HippoRestHandlerRaw : public HippoRestHandler -{ - public: - virtual ~HippoRestHandlerRaw() { } - - const char *getAcceptMimeType() const { return "application/octet-stream"; } - - private: - // This function must be implemented to receive the content - // it is executed on (status == 200) only - virtual void result(const std::string &content) = 0; - - // This function is called by the request engine - void handle(int status, const std::string &reason, - const LLChannelDescriptors &channels, - const boost::shared_ptr &body); -}; - -class HippoRestHandlerXml : public HippoRestHandler -{ - public: - virtual ~HippoRestHandlerXml() { } - - const char *getAcceptMimeType() const { return "application/xml"; } - - private: - // This function must be implemented to receive the content - virtual void result(LLXmlTree *content) = 0; - - // This function is called by the request engine - void handle(int status, const std::string &reason, - const LLChannelDescriptors &channels, - const boost::shared_ptr &body); -}; - -// ******************************************************************** - -class HippoRestRequest -{ - public: - // asynchronous interface - static void get5(const std::string &url, - HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void put5(const std::string &url, const std::string &body, - HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void put5(const std::string &url, const LLXmlTree *body, - HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void post5(const std::string &url, const std::string &body, - HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - static void post5(const std::string &url, const LLXmlTree *body, - HippoRestHandler *handler, float timeout=HIPPO_REST_TIMEOUT); - - // synchronous interface - static int getBlocking(const std::string &url, std::string *result); -}; - -#endif diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index 154d29063..27f9dff7d 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -134,8 +134,8 @@ void lggDicDownloadFloater::onClickDownload(void* data) if (!comboBox->getSelectedItemLabel().empty()) { std::string newDict(self->sNames[comboBox->getCurrentIndex()]); - LLHTTPClient::get4(gSavedSettings.getString("SpellDownloadURL")+newDict+".aff", new EmeraldDicDownloader(self,newDict+".aff")); - LLHTTPClient::get4(gSavedSettings.getString("SpellDownloadURL")+newDict+".dic", new EmeraldDicDownloader(NULL,newDict+".dic")); + LLHTTPClient::get(gSavedSettings.getString("SpellDownloadURL")+newDict+".aff", new EmeraldDicDownloader(self,newDict+".aff")); + LLHTTPClient::get(gSavedSettings.getString("SpellDownloadURL")+newDict+".dic", new EmeraldDicDownloader(NULL,newDict+".dic")); LLButton* button = self->getChild("Emerald_dic_download"); if (button) diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index d35a80f8b..998262c15 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -142,7 +142,7 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, const st LLSD dataToPost = LLSD::emptyMap(); dataToPost[keystr.c_str()] = objectList; - LLHTTPClient::post4( url, dataToPost, new LLAccountingCostResponder( objectList )); + LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList )); } } else diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index b2e1c2181..43eceade5 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2402,7 +2402,7 @@ bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity) body["access_prefs"] = access_prefs; llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: " << url << llendl; - LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); // Ignore response + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); // Ignore response return true; } return false; diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp index dbcd7e5a0..4dbc7eb70 100644 --- a/indra/newview/llagentlanguage.cpp +++ b/indra/newview/llagentlanguage.cpp @@ -61,7 +61,7 @@ bool LLAgentLanguage::update() body["language"] = language; body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); - LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } return true; } diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index e7af36b6a..bb022bafa 100644 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -110,7 +110,7 @@ public: llinfos << "Compiling " << llendl; // postRaw takes ownership of mData and will delete it. - LLHTTPClient::postRaw4(uploader, mData, mDataSize, this); + LLHTTPClient::postRaw(uploader, mData, mDataSize, this); mData = NULL; mDataSize = 0; } @@ -174,7 +174,7 @@ void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier) if (object) { url = object->getRegion()->getCapability("UpdateScriptTask"); - LLHTTPClient::post4(url, body, + LLHTTPClient::post(url, body, new LLAssetUploadChainResponder( body, data.mFilename, data.mQueueId, data.mData, data.mDataSize, data.mScriptName, *supplier)); diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index c50557354..173666a12 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -281,11 +281,11 @@ void LLAssetUploadResponder::uploadUpload(const LLSD& content) std::string uploader = content["uploader"]; if (mFileName.empty()) { - LLHTTPClient::postFile4(uploader, mVFileID, mAssetType, this); + LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); } else { - LLHTTPClient::postFile4(uploader, mFileName, this); + LLHTTPClient::postFile(uploader, mFileName, this); } } @@ -944,7 +944,7 @@ public: if ( getFilename().empty() ) { // we have no filename, use virtual file ID instead - LLHTTPClient::postFile4( + LLHTTPClient::postFile( confirmation_url, getVFileID(), getAssetType(), @@ -952,7 +952,7 @@ public: } else { - LLHTTPClient::postFile4( + LLHTTPClient::postFile( confirmation_url, getFilename(), responder); diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp index 2ebaffd4f..3e2880199 100644 --- a/indra/newview/llcapabilitylistener.cpp +++ b/indra/newview/llcapabilitylistener.cpp @@ -103,7 +103,7 @@ bool LLCapabilityListener::capListener(const LLSD& request) new LLSDMessage::EventResponder(LLEventPumps::instance(), request, mProvider.getDescription(), cap, reply, error); responder->setTimeoutPolicy(timeoutpolicy); // This capability is supported by the region to which we're talking. - LLHTTPClient::post4(url, payload, responder); + LLHTTPClient::post(url, payload, responder); } else { diff --git a/indra/newview/llcaphttpsender.cpp b/indra/newview/llcaphttpsender.cpp index 952d72314..1127f4342 100644 --- a/indra/newview/llcaphttpsender.cpp +++ b/indra/newview/llcaphttpsender.cpp @@ -50,5 +50,5 @@ void LLCapHTTPSender::send(const LLHost& host, const std::string& message, LLSD llsd; llsd["message"] = message; llsd["body"] = body; - LLHTTPClient::post4(mCap, llsd, response); + LLHTTPClient::post(mCap, llsd, response); } diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index be7ede224..1499c8363 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -164,7 +164,7 @@ namespace lldebugs << "LLEventPollResponder::makeRequest <" << mCount << "> ack = " << LLSDXMLStreamer(mAcknowledge) << llendl; - LLHTTPClient::post4(mPollURL, request, this); + LLHTTPClient::post(mPollURL, request, this); } void LLEventPollResponder::handleMessage(const LLSD& content) diff --git a/indra/newview/llfloateractivespeakers.cpp b/indra/newview/llfloateractivespeakers.cpp index 968228fb2..9aa5a7adf 100644 --- a/indra/newview/llfloateractivespeakers.cpp +++ b/indra/newview/llfloateractivespeakers.cpp @@ -893,7 +893,7 @@ void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data LLUUID mSessionID; }; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new MuteVoiceResponder(self->mSpeakerMgr->getSessionID())); @@ -960,7 +960,7 @@ void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data) LLUUID mSessionID; }; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new MuteTextResponder(self->mSpeakerMgr->getSessionID())); @@ -999,7 +999,7 @@ void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_da virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationModeResponder_timeout; } }; - LLHTTPClient::post4(url, data, new ModerationModeResponder()); + LLHTTPClient::post(url, data, new ModerationModeResponder()); } // diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 07a183256..70466afd0 100644 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -53,7 +53,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() if (!url.empty()) { llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <getText()), new ConsoleResponder(mOutput)); @@ -226,7 +226,7 @@ void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param) else { // Using SimConsoleAsync - LLHTTPClient::post4( + LLHTTPClient::post( url, LLSD(input->getText()), new AsyncConsoleResponder); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index e7f6b805b..482a4af3c 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -765,7 +765,7 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate() body["allow_parcel_changes"] = childGetValue("allow_parcel_changes_check"); body["block_parcel_search"] = childGetValue("block_parcel_search_check"); - LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } else { @@ -2370,7 +2370,7 @@ bool LLPanelEstateInfo::commitEstateInfoCaps() body["owner_abuse_email"] = childGetValue("abuse_email_address").asString(); // we use a responder so that we can re-get the data after committing to the database - LLHTTPClient::post4(url, body, new LLEstateChangeInfoResponder((void*)this)); + LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder((void*)this)); return true; } diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index c11c95d18..ff8d32af5 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -881,14 +881,14 @@ void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url if(childGetValue("screen_check").asBoolean() && !sshot_url.empty()) { // try to upload screenshot - LLHTTPClient::post4(sshot_url, report, new LLUserReportScreenshotResponder(report, + LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report, mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType)); } else { // screenshot not wanted or we don't have screenshot cap - LLHTTPClient::post4(url, report, new LLUserReportResponder); + LLHTTPClient::post(url, report, new LLUserReportResponder); } } diff --git a/indra/newview/llfloaterteleport.cpp b/indra/newview/llfloaterteleport.cpp index adfa034b1..cf5a84ee0 100644 --- a/indra/newview/llfloaterteleport.cpp +++ b/indra/newview/llfloaterteleport.cpp @@ -303,7 +303,7 @@ void LLFloaterTeleport::onClickTeleport(void* userdata) args["public_region_seed_capability"] = text; args["position"] = ll_sd_from_vector3(LLVector3(128, 128, 50)); // default to middle of region above base terrain LL_INFOS("OGPX") << " args to placeavatar cap " << placeAvatarCap << " on teleport: " << LLSDOStreamer(args) << LL_ENDL; - LLHTTPClient::post4(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder()); + LLHTTPClient::post(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder()); gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["requesting"]); gViewerWindow->setShowProgress(TRUE); diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index a67d6aa43..fa010f282 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -171,7 +171,7 @@ BOOL LLFloaterTOS::postBuild() { web_browser->addObserver(this); gResponsePtr = LLIamHere::build( this ); - LLHTTPClient::get4( getString( "real_url" ), gResponsePtr ); + LLHTTPClient::get( getString( "real_url" ), gResponsePtr ); } return TRUE; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 416458617..d8d4f5e84 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -239,7 +239,7 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) // Discover the MIME type only for "http" scheme. if(scheme == "http" || scheme == "https") { - LLHTTPClient::getHeaderOnly4( media_url, + LLHTTPClient::getHeaderOnly( media_url, new LLMediaTypeResponder(self->getHandle())); } else diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index fe1bab58a..ff69483ca 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -279,7 +279,7 @@ bool send_start_session_messages( data["params"] = agents; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new LLStartConferenceChatResponder( @@ -724,7 +724,7 @@ void LLVoiceChannelGroup::getChannelInfo() LLSD data; data["method"] = "call"; data["session-id"] = mSessionID; - LLHTTPClient::post4(url, + LLHTTPClient::post(url, data, new LLVoiceCallCapResponder(mSessionID)); } @@ -1604,7 +1604,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) data["method"] = "invite"; data["session-id"] = mSessionUUID; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new LLSessionInviteResponder( diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index e8c221414..5aec41d50 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -310,7 +310,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLSD data; data["method"] = "accept invitation"; data["session-id"] = session_id; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new LLViewerChatterBoxInvitationAcceptResponder( @@ -348,7 +348,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLSD data; data["method"] = "decline invitation"; data["session-id"] = session_id; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, NULL); @@ -1627,7 +1627,7 @@ public: LLSD data; data["method"] = "accept invitation"; data["session-id"] = session_id; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new LLViewerChatterBoxInvitationAcceptResponder( diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index b4aa322a6..70173952a 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -578,7 +578,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, // request["payload"] = body; // viewer_region->getCapAPI().post(request); - LLHTTPClient::post4( + LLHTTPClient::post( url, body, new LLCreateInventoryCategoryResponder(this, callback, user_data) ); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 03ca87137..cb2be7419 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -705,14 +705,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch() if (folder_request_body["folders"].size()) { LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); - LLHTTPClient::post4(url, folder_request_body, fetcher); + LLHTTPClient::post(url, folder_request_body, fetcher); } if (folder_request_body_lib["folders"].size()) { std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); - LLHTTPClient::post4(url_lib, folder_request_body_lib, fetcher); + LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher); } } if (item_count) @@ -729,7 +729,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() body["agent_id"] = gAgent.getID(); body["items"] = item_request_body; - LLHTTPClient::post4(url, body, new LLInventoryModelFetchItemResponder(body)); + LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); } //else //{ @@ -756,7 +756,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch() body["agent_id"] = gAgent.getID(); body["items"] = item_request_body_lib; - LLHTTPClient::post4(url, body, new LLInventoryModelFetchItemResponder(body)); + LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); } } } diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 07427c396..887f0a474 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -235,7 +235,7 @@ void fetch_items_from_llsd(const LLSD& items_llsd) if (!url.empty()) { body[i]["agent_id"] = gAgent.getID(); - LLHTTPClient::post4(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); + LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i])); continue; } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index d90a9483d..738e327ac 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -35,7 +35,6 @@ #include "llappviewer.h" #include "llbufferstream.h" #include "llcallbacklist.h" -#include "llcurlrequest.h" #include "lldatapacker.h" #include "llfasttimer.h" #if MESH_IMPORT @@ -499,7 +498,6 @@ LLMeshRepoThread::~LLMeshRepoThread() void LLMeshRepoThread::run() { - mCurlRequest = new AICurlInterface::Request; #if MESH_IMPORT LLCDResult res = LLConvexDecomposition::initThread(); if (res != LLCD_OK) @@ -654,9 +652,6 @@ void LLMeshRepoThread::run() llwarns << "convex decomposition unable to be quit" << llendl; } #endif //MESH_IMPORT - - delete mCurlRequest; - mCurlRequest = NULL; } void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id) @@ -788,9 +783,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) { - // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange2(http_url, headers, offset, size, - new LLMeshSkinInfoResponder(mesh_id, offset, size)); + LLHTTPClient::getByteRange(http_url, offset, size, + new LLMeshSkinInfoResponder(mesh_id, offset, size), headers); LLMeshRepository::sHTTPRequestCount++; } } @@ -863,8 +857,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange2(http_url, headers, offset, size, - new LLMeshDecompositionResponder(mesh_id, offset, size)); + LLHTTPClient::getByteRange(http_url, offset, size, + new LLMeshDecompositionResponder(mesh_id, offset, size), headers); LLMeshRepository::sHTTPRequestCount++; } } @@ -937,8 +931,8 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange2(http_url, headers, offset, size, - new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + LLHTTPClient::getByteRange(http_url, offset, size, + new LLMeshPhysicsShapeResponder(mesh_id, offset, size), headers); LLMeshRepository::sHTTPRequestCount++; } } @@ -989,7 +983,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c //within the first 4KB //NOTE -- this will break of headers ever exceed 4KB // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange2(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + LLHTTPClient::getByteRange(http_url, 0, 4096, new LLMeshHeaderResponder(mesh_params), headers); LLMeshRepository::sHTTPRequestCount++; count++; } @@ -1050,8 +1044,8 @@ void LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, if (!http_url.empty()) { // This might throw AICurlNoEasyHandle. - mCurlRequest->getByteRange2(constructUrl(mesh_id), headers, offset, size, - new LLMeshLODResponder(mesh_params, lod, offset, size)); + LLHTTPClient::getByteRange(constructUrl(mesh_id), offset, size, + new LLMeshLODResponder(mesh_params, lod, offset, size), headers); LLMeshRepository::sHTTPRequestCount++; count++; } @@ -1287,9 +1281,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadSkin = upload_skin; mUploadJoints = upload_joints; mMutex = new LLMutex(); - mCurlRequest = NULL; mPendingUploads = 0; - mFinished = false; mOrigin = gAgent.getPositionAgent(); mHost = gAgent.getRegionHost(); @@ -1615,8 +1607,6 @@ void LLMeshUploadThread::generateHulls() void LLMeshUploadThread::doWholeModelUpload() { - mCurlRequest = new AICurlInterface::Request(); - if (mWholeModelUploadURL.empty()) { llinfos << "unable to upload, fee request failed" << llendl; @@ -1629,33 +1619,15 @@ void LLMeshUploadThread::doWholeModelUpload() wholeModelToLLSD(full_model_data, true); LLSD body = full_model_data["asset_resources"]; dump_llsd_to_file(body,make_dump_name("whole_model_body_",dump_num)); - AIHTTPHeaders headers; - // This might throw AICurlNoEasyHandle. - mCurlRequest->post2(mWholeModelUploadURL, headers, body, - new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle), mMeshUploadTimeOut); - do - { - mCurlRequest->process(); // FIXME: This function does not exist anymore. The post() gets CPU time from AICurlEasyRequestStateMachine. - // Therefore, if we do not want to continue here unless this upload is done... no wait, that would - // be blocking and we don't want blocking... - //sleep for 10ms to prevent eating a whole core - apr_sleep(10000); - } while (mCurlRequest->getQueued() > 0); + LLHTTPClient::post(mWholeModelUploadURL, body, + new LLWholeModelUploadResponder(this, full_model_data, mUploadObserverHandle)); } - - delete mCurlRequest; - mCurlRequest = NULL; - - // Currently a no-op. - mFinished = true; } void LLMeshUploadThread::requestWholeModelFee() { dump_num++; - mCurlRequest = new AICurlInterface::Request; - generateHulls(); LLSD model_data; @@ -1663,23 +1635,9 @@ void LLMeshUploadThread::requestWholeModelFee() dump_llsd_to_file(model_data,make_dump_name("whole_model_fee_request_",dump_num)); mPendingUploads++; - AIHTTPHeaders headers; // This might throw AICurlNoEasyHandle. - mCurlRequest->post2(mWholeModelFeeCapability, headers, model_data, - new LLWholeModelFeeResponder(this,model_data, mFeeObserverHandle), mMeshUploadTimeOut); - - do - { - mCurlRequest->process(); - //sleep for 10ms to prevent eating a whole core - apr_sleep(10000); - } while (mCurlRequest->getQueued() > 0); - - delete mCurlRequest; - mCurlRequest = NULL; - - // Currently a no-op. - mFinished = true; + LLHTTPClient::post(mWholeModelFeeCapability, model_data, + new LLWholeModelFeeResponder(this, model_data, mFeeObserverHandle)); } #endif //MESH_IMPORT diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 5d225cfe4..2047bf670 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -32,7 +32,6 @@ #include "lluuid.h" #include "llviewertexture.h" #include "llvolume.h" -#include "llcurlrequest.h" #if MESH_IMPORT #define LLCONVEXDECOMPINTER_STATIC 1 @@ -246,7 +245,6 @@ public: static S32 sActiveLODRequests; static U32 sMaxConcurrentRequests; - AICurlInterface::Request* mCurlRequest; LLMutex* mMutex; LLMutex* mHeaderMutex; LLCondition* mSignal; @@ -413,10 +411,8 @@ public: instance_map mInstance; LLMutex* mMutex; - LLCurlRequest* mCurlRequest; S32 mPendingUploads; LLVector3 mOrigin; - bool mFinished; bool mUploadTextures; bool mUploadSkin; bool mUploadJoints; @@ -431,7 +427,6 @@ public: LLHandle fee_observer= (LLHandle()), LLHandle upload_observer = (LLHandle())); ~LLMeshUploadThread(); - bool finished() { return mFinished; } virtual void run(); void preStart(); void discard() ; diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index f9227276f..1d3e50360 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -587,7 +587,7 @@ void LLPanelClassified::sendClassifiedInfoRequest() if (!url.empty()) { llinfos << "Classified stat request via capability" << llendl; - LLHTTPClient::post4(url, body, new LLClassifiedStatsResponder(((LLView*)this)->getHandle(), mClassifiedID)); + LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(((LLView*)this)->getHandle(), mClassifiedID)); } } } @@ -999,7 +999,7 @@ void LLPanelClassified::sendClassifiedClickMessage(const std::string& type) std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); llinfos << "LLPanelClassified::sendClassifiedClickMessage via capability" << llendl; - LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } //////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelgroupvoting.cpp b/indra/newview/llpanelgroupvoting.cpp index 978bddfda..68a8bc4be 100644 --- a/indra/newview/llpanelgroupvoting.cpp +++ b/indra/newview/llpanelgroupvoting.cpp @@ -790,7 +790,7 @@ void LLPanelGroupVoting::impl::sendStartGroupProposal() body["duration"] = duration_seconds; body["proposal-text"] = mProposalText->getText(); - LLHTTPClient::post4( + LLHTTPClient::post( url, body, new LLStartGroupVoteResponder(mGroupID)); @@ -836,7 +836,7 @@ void LLPanelGroupVoting::impl::sendGroupProposalBallot(const std::string& vote) body["group-id"] = mGroupID; body["vote"] = vote; - LLHTTPClient::post4( + LLHTTPClient::post( url, body, new LLGroupProposalBallotResponder(mGroupID)); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index f229497a4..27e3d1f4d 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -887,7 +887,7 @@ void LLPanelLogin::refreshLoginPage() std::string login_page = gHippoGridManager->getConnectedGrid()->getLoginPage(); if (!login_page.empty()) { - LLHTTPClient::head4(login_page, gResponsePtr); + LLHTTPClient::head(login_page, gResponsePtr); } else { sInstance->setSiteIsAlive(false); } diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp index 59ce810b3..4f687099f 100644 --- a/indra/newview/llpanelplace.cpp +++ b/indra/newview/llpanelplace.cpp @@ -391,7 +391,7 @@ void LLPanelPlace::displayParcelInfo(const LLVector3& pos_region, U64 region_handle = to_region_handle(pos_global); body["region_handle"] = ll_sd_from_U64(region_handle); } - LLHTTPClient::post4(url, body, new LLRemoteParcelRequestResponder(this->getHandle())); + LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(this->getHandle())); } else { diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index c56f1b618..a82478557 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -377,7 +377,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b llassert(!navMeshStatusURL.empty()); navMeshPtr->handleNavMeshCheckVersion(); LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); - LLHTTPClient::get4(navMeshStatusURL, navMeshStatusResponder); + LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); } } @@ -411,12 +411,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); - LLHTTPClient::get4(objectLinksetsURL, objectLinksetsResponder); + LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); if (doRequestTerrain) { LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); - LLHTTPClient::get4(terrainLinksetsURL, terrainLinksetsResponder); + LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); } } } @@ -460,13 +460,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP if (!objectPostData.isUndefined()) { LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); - LLHTTPClient::put4(objectLinksetsURL, objectPostData, objectLinksetsResponder); + LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); } if (!terrainPostData.isUndefined()) { LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); - LLHTTPClient::put4(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); + LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); } } } @@ -499,7 +499,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_ pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); - LLHTTPClient::get4(charactersURL, charactersResponder); + LLHTTPClient::get(charactersURL, charactersResponder); } } } @@ -532,7 +532,7 @@ void LLPathfindingManager::requestGetAgentState() std::string agentStateURL = getAgentStateURLForRegion(currentRegion); llassert(!agentStateURL.empty()); LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); - LLHTTPClient::get4(agentStateURL, responder); + LLHTTPClient::get(agentStateURL, responder); } } } @@ -556,7 +556,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak LLSD postData; postData["command"] = "rebuild"; LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); - LLHTTPClient::post4(navMeshStatusURL, postData, responder); + LLHTTPClient::post(navMeshStatusURL, postData, responder); } } @@ -580,7 +580,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); LLSD postData; - LLHTTPClient::post4(navMeshURL, postData, responder); + LLHTTPClient::post(navMeshURL, postData, responder); } } } diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 32da50942..ecb260704 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -1183,7 +1183,7 @@ void LLPreviewGesture::saveIfNeeded() // Saving into agent inventory LLSD body; body["item_id"] = mItemUUID; - LLHTTPClient::post4(agent_url, body, + LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); delayedUpload = TRUE; } @@ -1193,7 +1193,7 @@ void LLPreviewGesture::saveIfNeeded() LLSD body; body["task_id"] = mObjectUUID; body["item_id"] = mItemUUID; - LLHTTPClient::post4(task_url, body, + LLHTTPClient::post(task_url, body, new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); } else if (gAssetStorage) diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 5de155536..45de56e14 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -569,7 +569,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) body["item_id"] = mItemUUID; llinfos << "Saving notecard " << mItemUUID << " into agent inventory via " << agent_url << llendl; - LLHTTPClient::post4(agent_url, body, + LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else if (!mObjectUUID.isNull() && !task_url.empty()) @@ -582,7 +582,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) body["item_id"] = mItemUUID; llinfos << "Saving notecard " << mItemUUID << " into task " << mObjectUUID << " via " << task_url << llendl; - LLHTTPClient::post4(task_url, body, + LLHTTPClient::post(task_url, body, new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else if (gAssetStorage) diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index de49d1488..baf963d68 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1494,7 +1494,7 @@ void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, { body["target"] = "lsl2"; } - LLHTTPClient::post4(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); + LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, @@ -2393,7 +2393,7 @@ void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, body["item_id"] = item_id; body["is_script_running"] = is_running; body["target"] = monoChecked() ? "mono" : "lsl2"; - LLHTTPClient::post4(url, body, + LLHTTPClient::post(url, body, new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index 6a4b94a8d..b164a91fc 100644 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -70,7 +70,7 @@ void LLProductInfoRequestManager::initSingleton() std::string url = gAgent.getRegion()->getCapability("ProductInfoRequest"); if (!url.empty()) { - LLHTTPClient::get4(url, new LLProductInfoRequestResponder()); + LLHTTPClient::get(url, new LLProductInfoRequestResponder()); } } diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 5a825cb60..2b6195521 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -541,7 +541,7 @@ void LLTexLayerSetBuffer::doUpload() { LLSD body = LLSD::emptyMap(); // The responder will call LLTexLayerSetBuffer::onTextureUploadComplete() - LLHTTPClient::post4(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); + LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl; } else diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 561c19129..6b925da27 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1323,12 +1323,13 @@ bool LLTextureFetchWorker::doWork(S32 param) LLImageBase::TYPE_AVATAR_BAKE == mType); #endif - // Will call callbackHttpGet when curl request completes - AIHTTPHeaders headers("Accept", "image/x-j2c"); try { - res = mFetcher->mCurlGetRequest->getByteRange2(mUrl, headers, offset, mRequestedSize, - new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true)); + // Will call callbackHttpGet when curl request completes + AIHTTPHeaders headers("Accept", "image/x-j2c"); + LLHTTPClient::getByteRange(mUrl, offset, mRequestedSize, + new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true), headers); + res = true; } catch(AICurlNoEasyHandle const& error) { @@ -1994,8 +1995,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), mHTTPTextureBits(0), - mTotalHTTPRequests(0), - mCurlGetRequest(NULL) + mTotalHTTPRequests(0) #if HTTP_METRICS ,mQAMode(qa_mode) #endif @@ -2429,26 +2429,9 @@ void LLTextureFetch::shutDownImageDecodeThread() } } -// WORKER THREAD -void LLTextureFetch::startThread() -{ - // Construct mCurlGetRequest from Worker Thread - mCurlGetRequest = new AICurlInterface::Request; -} - -// WORKER THREAD -void LLTextureFetch::endThread() -{ - // Destroy mCurlGetRequest from Worker Thread - delete mCurlGetRequest; - mCurlGetRequest = NULL; -} - // WORKER THREAD void LLTextureFetch::threadedUpdate() { - llassert_always(mCurlGetRequest); - // Limit update frequency const F32 PROCESS_TIME = 0.05f; static LLFrameTimer process_timer; @@ -3118,9 +3101,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) if (! mCapsURL.empty()) { - LLCurlRequest::headers_t headers; - fetcher->getCurlRequest().post(mCapsURL, - headers, + LLHTTPClient::post(mCapsURL, merged_llsd, new lcl_responder(fetcher, report_sequence, diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 03073d906..b0caf2619 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -37,7 +37,6 @@ #include "llimage.h" #include "lluuid.h" #include "llworkerthread.h" -#include "llcurlrequest.h" #include "lltextureinfo.h" #include "llapr.h" @@ -107,8 +106,6 @@ public: LLViewerAssetStats * main_stats); void commandDataBreak(); - AICurlInterface::Request& getCurlRequest() { return *mCurlGetRequest; } - bool isQAMode() const { return mQAMode; } // Curl POST counter maintenance @@ -128,8 +125,6 @@ protected: private: void sendRequestListToSimulators(); - /*virtual*/ void startThread(void); - /*virtual*/ void endThread(void); /*virtual*/ void threadedUpdate(void); void commonUpdate(); @@ -178,7 +173,6 @@ private: LLTextureCache* mTextureCache; LLImageDecodeThread* mImageDecodeThread; - AICurlInterface::Request* mCurlGetRequest; // Map of all requests by UUID typedef std::map map_t; diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp index 722e31b65..7f14a4254 100644 --- a/indra/newview/lltexturestatsuploader.cpp +++ b/indra/newview/lltexturestatsuploader.cpp @@ -47,7 +47,7 @@ void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_ca { if ( texture_cap_url != "" ) { - LLHTTPClient::post4(texture_cap_url, texture_stats, NULL); + LLHTTPClient::post(texture_cap_url, texture_stats, NULL); } else { diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 7d0528d8c..833926afe 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -74,7 +74,7 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std m_Header.addHeader(m_AgentHeader, user_agent); } - LLHTTPClient::get4(url, result, m_Header, m_GoogleTimeout); + LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout); } //static diff --git a/indra/newview/lluserauth.h b/indra/newview/lluserauth.h index 12cf1f956..847b1e8b5 100644 --- a/indra/newview/lluserauth.h +++ b/indra/newview/lluserauth.h @@ -38,7 +38,6 @@ #include #include -class LLURLRequest; class XMLRPCResponder; // forward decl of types from xlrpc.h diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index d4a89d3a4..0c917ef4e 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -114,7 +114,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // communicates with the back-end. LLSD body; body["display_name"] = change_array; - LLHTTPClient::post4(cap_url, body, new LLSetDisplayNameResponder, headers); + LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); } class LLSetDisplayNameReply : public LLHTTPNode diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 436bb3e97..c932de258 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -256,7 +256,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const body["items"][0]["owner_id"] = mPermissions.getOwner(); body["items"][0]["item_id"] = mUUID; - LLHTTPClient::post4(url, body, new LLInventoryModel::fetchInventoryResponder(body)); + LLHTTPClient::post(url, body, new LLInventoryModel::fetchInventoryResponder(body)); } else { diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 74526a61d..1d77bd5e0 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -684,7 +684,7 @@ void LLViewerMedia::setOpenIDCookie() LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << llendl; LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << llendl; - LLHTTPClient::get4(profile_url, + LLHTTPClient::get(profile_url, new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), headers); } @@ -716,7 +716,7 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string char* data = new char[size]; memcpy(data, openid_token.data(), size); - LLHTTPClient::postRaw4( + LLHTTPClient::postRaw( openid_url, data, size, @@ -1307,7 +1307,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi { if(mime_type.empty()) { - LLHTTPClient::getHeaderOnly4( url, new LLMimeDiscoveryResponder(this)); + LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); } else if(initializeMedia(mime_type) && (plugin = getMediaPlugin())) { diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 4ff4b28c5..fc795f8fb 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1206,7 +1206,7 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty body["everyone_mask"] = LLSD::Integer(everyone_perms); body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost); - LLHTTPClient::post4(url, body, + LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); } else @@ -1379,7 +1379,7 @@ void NewResourceItemCallback::fire(const LLUUID& new_item_id) } if(agent_url.empty()) return; - LLHTTPClient::post4(agent_url, body, + LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, vfile_id, new_item->getType())); } // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 57c65caea..ebdbfc02f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3625,7 +3625,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string authUrl = mesg.substr(8); authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; authUrl += gAuthString; - LLHTTPClient::get4(authUrl, new AuthHandler); + LLHTTPClient::get(authUrl, new AuthHandler); return; } } diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index 8c09f47b2..c341d296b 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -1214,7 +1214,7 @@ void myupload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ LLSDSerialize::toXML(body, llsdxml); LL_DEBUGS("ObjectBackup") << "posting body to capability: " << llsdxml.str() << LL_ENDL; //LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); - LLHTTPClient::post4(url, body, new importResponder(body, uuid, asset_type)); + LLHTTPClient::post(url, body, new importResponder(body, uuid, asset_type)); } else { diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 7f472d32b..5fd7b4aae 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1106,7 +1106,7 @@ void LLViewerObjectList::fetchObjectCosts() LLSD post_data = LLSD::emptyMap(); post_data["object_ids"] = id_list; - LLHTTPClient::post4( + LLHTTPClient::post( url, post_data, new LLObjectCostResponder(id_list)); @@ -1162,7 +1162,7 @@ void LLViewerObjectList::fetchPhysicsFlags() LLSD post_data = LLSD::emptyMap(); post_data["object_ids"] = id_list; - LLHTTPClient::post4( + LLHTTPClient::post( url, post_data, new LLPhysicsFlagsResponder(id_list)); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 474978af1..49cd7a1a3 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -467,7 +467,7 @@ void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) body["agent-id"] = gAgent.getID(); body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); body["url"] = url; - LLHTTPClient::post4(region_url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post(region_url, body, new LLHTTPClient::ResponderIgnore); } else { diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 4c21dc236..9ed016d71 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1310,7 +1310,7 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag parcel->packMessage(body); llinfos << "Sending parcel properties update via capability to: " << url << llendl; - LLHTTPClient::post4(url, body, new LLHTTPClient::ResponderIgnore); + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } else { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ab9b89d13..93699d54b 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1666,7 +1666,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url) llinfos << "posting to seed " << url << llendl; S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post4(url, capabilityNames, + LLHTTPClient::post(url, capabilityNames, BaseCapabilitiesComplete::build(getHandle(), id)); } @@ -1701,7 +1701,7 @@ void LLViewerRegion::failedSeedCapability() << mImpl->mSeedCapAttempts << ")" << llendl; S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post4(url, capabilityNames, + LLHTTPClient::post(url, capabilityNames, BaseCapabilitiesComplete::build(getHandle(), id)); } else @@ -1748,7 +1748,7 @@ private: { mAttempt++; LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get4(mRetryURL, new SimulatorFeaturesReceived(*this)); + LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this)); } } @@ -1774,7 +1774,7 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // kick off a request for simulator features - LLHTTPClient::get4(url, new SimulatorFeaturesReceived(url, getHandle())); + LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle())); } else { diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 799dc4262..d451a0dc5 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -878,6 +878,6 @@ void send_stats() body["MinimalSkin"] = false; LLViewerStats::getInstance()->addToMessage(body); - LLHTTPClient::post4(url, body, new ViewerStatsResponder); + LLHTTPClient::post(url, body, new ViewerStatsResponder); } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index de444efff..a3b432b15 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -1370,7 +1370,7 @@ void LLVoiceClient::requestVoiceAccountProvision(S32 retries) if ( url == "" ) return; - LLHTTPClient::post4( + LLHTTPClient::post( url, LLSD(), new LLViewerVoiceAccountProvisionResponder(retries)); @@ -5067,7 +5067,7 @@ void LLVoiceClient::parcelChanged() std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest"); LLSD data; - LLHTTPClient::post4( + LLHTTPClient::post( url, data, new LLVoiceClientCapResponder); diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 069398964..307edffdd 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -284,7 +284,7 @@ bool LLWaterParamManager::savePresetToNotecard(const std::string & name) file.write((U8*)buffer.c_str(), size); LLSD body; body["item_id"] = item->getUUID(); - LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); + LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else { diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index b1ca3ab82..0495d9c51 100644 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -88,7 +88,7 @@ bool LLEnvironmentRequest::doRequest() } LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; - LLHTTPClient::get4(url, new LLEnvironmentRequestResponder()); + LLHTTPClient::get(url, new LLEnvironmentRequestResponder()); return true; } @@ -160,7 +160,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL; LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL; - LLHTTPClient::post4(url, content, new LLEnvironmentApplyResponder()); + LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder()); return true; } diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 72177a3e7..284da40cd 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -943,7 +943,7 @@ bool LLWLParamManager::savePresetToNotecard(const std::string & name) file.write((U8*)buffer.c_str(), size); LLSD body; body["item_id"] = item->getUUID(); - LLHTTPClient::post4(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); + LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } else { diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 1bb7c43b9..91e1e6cda 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -441,7 +441,7 @@ void LLWorldMap::sendMapLayerRequest() if (!url.empty()) { llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl; - LLHTTPClient::post4(url, body, new LLMapLayerResponder); + LLHTTPClient::post(url, body, new LLMapLayerResponder); } else { From 7549b471c378156642e7b85e832fb89219bb965f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 31 Oct 2012 18:51:52 +0100 Subject: [PATCH 59/64] Moved curl stuff from indra/aistatemachine to indra/llmessage. --- indra/aistatemachine/CMakeLists.txt | 9 --------- indra/llmessage/CMakeLists.txt | 9 +++++++++ indra/{aistatemachine => llmessage}/aicurl.cpp | 0 indra/{aistatemachine => llmessage}/aicurl.h | 0 .../aicurleasyrequeststatemachine.cpp | 0 .../aicurleasyrequeststatemachine.h | 0 indra/{aistatemachine => llmessage}/aicurlprivate.h | 0 indra/{aistatemachine => llmessage}/aicurlthread.cpp | 0 indra/{aistatemachine => llmessage}/aicurlthread.h | 0 indra/{aistatemachine => llmessage}/debug_libcurl.cpp | 0 indra/{aistatemachine => llmessage}/debug_libcurl.h | 0 11 files changed, 9 insertions(+), 9 deletions(-) rename indra/{aistatemachine => llmessage}/aicurl.cpp (100%) rename indra/{aistatemachine => llmessage}/aicurl.h (100%) rename indra/{aistatemachine => llmessage}/aicurleasyrequeststatemachine.cpp (100%) rename indra/{aistatemachine => llmessage}/aicurleasyrequeststatemachine.h (100%) rename indra/{aistatemachine => llmessage}/aicurlprivate.h (100%) rename indra/{aistatemachine => llmessage}/aicurlthread.cpp (100%) rename indra/{aistatemachine => llmessage}/aicurlthread.h (100%) rename indra/{aistatemachine => llmessage}/debug_libcurl.cpp (100%) rename indra/{aistatemachine => llmessage}/debug_libcurl.h (100%) diff --git a/indra/aistatemachine/CMakeLists.txt b/indra/aistatemachine/CMakeLists.txt index c372fecc0..18ba3c034 100644 --- a/indra/aistatemachine/CMakeLists.txt +++ b/indra/aistatemachine/CMakeLists.txt @@ -18,24 +18,15 @@ include_directories( ) set(aistatemachine_SOURCE_FILES - debug_libcurl.cpp aistatemachine.cpp aitimer.cpp - aicurl.cpp - aicurlthread.cpp - aicurleasyrequeststatemachine.cpp ) set(aistatemachine_HEADER_FILES CMakeLists.txt - debug_libcurl.h aistatemachine.h aitimer.h - aicurlprivate.h - aicurl.h - aicurlthread.h - aicurleasyrequeststatemachine.h ) set_source_files_properties(${aistatemachine_HEADER_FILES} diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index de096ba31..8e7f1f577 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -22,8 +22,12 @@ include_directories( ) set(llmessage_SOURCE_FILES + aicurl.cpp + aicurleasyrequeststatemachine.cpp + aicurlthread.cpp aihttpheaders.cpp aihttptimeoutpolicy.cpp + debug_libcurl.cpp llhttpclient.cpp llares.cpp llareslistener.cpp @@ -107,8 +111,13 @@ set(llmessage_SOURCE_FILES set(llmessage_HEADER_FILES CMakeLists.txt + aicurl.h + aicurleasyrequeststatemachine.h + aicurlprivate.h + aicurlthread.h aihttpheaders.h aihttptimeoutpolicy.h + debug_libcurl.h llares.h llareslistener.h llassetstorage.h diff --git a/indra/aistatemachine/aicurl.cpp b/indra/llmessage/aicurl.cpp similarity index 100% rename from indra/aistatemachine/aicurl.cpp rename to indra/llmessage/aicurl.cpp diff --git a/indra/aistatemachine/aicurl.h b/indra/llmessage/aicurl.h similarity index 100% rename from indra/aistatemachine/aicurl.h rename to indra/llmessage/aicurl.h diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.cpp b/indra/llmessage/aicurleasyrequeststatemachine.cpp similarity index 100% rename from indra/aistatemachine/aicurleasyrequeststatemachine.cpp rename to indra/llmessage/aicurleasyrequeststatemachine.cpp diff --git a/indra/aistatemachine/aicurleasyrequeststatemachine.h b/indra/llmessage/aicurleasyrequeststatemachine.h similarity index 100% rename from indra/aistatemachine/aicurleasyrequeststatemachine.h rename to indra/llmessage/aicurleasyrequeststatemachine.h diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/llmessage/aicurlprivate.h similarity index 100% rename from indra/aistatemachine/aicurlprivate.h rename to indra/llmessage/aicurlprivate.h diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp similarity index 100% rename from indra/aistatemachine/aicurlthread.cpp rename to indra/llmessage/aicurlthread.cpp diff --git a/indra/aistatemachine/aicurlthread.h b/indra/llmessage/aicurlthread.h similarity index 100% rename from indra/aistatemachine/aicurlthread.h rename to indra/llmessage/aicurlthread.h diff --git a/indra/aistatemachine/debug_libcurl.cpp b/indra/llmessage/debug_libcurl.cpp similarity index 100% rename from indra/aistatemachine/debug_libcurl.cpp rename to indra/llmessage/debug_libcurl.cpp diff --git a/indra/aistatemachine/debug_libcurl.h b/indra/llmessage/debug_libcurl.h similarity index 100% rename from indra/aistatemachine/debug_libcurl.h rename to indra/llmessage/debug_libcurl.h From c0ac4281798cc28da540b40df6482dddeb799e3e Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 31 Oct 2012 23:02:03 +0100 Subject: [PATCH 60/64] Code cleanup * Moved Responder stuff to LLHTTPClient. * Renamed LLHTTPClient::Responder to LLHTTPClient::ResponderWithResult. * Deleted LLHTTPClientAdapter and LLHTTPClientInterface. * Renamed AICurlInterface::TransferInfo to AITransferInfo and moved it to llhttpclient.h * Removed 'CURLcode code' argument from completed_headers. --- indra/llcommon/llthread.cpp | 6 +- indra/llcrashlogger/llcrashlogger.cpp | 3 +- indra/llmessage/CMakeLists.txt | 4 - indra/llmessage/aicurl.cpp | 151 +-------- indra/llmessage/aicurl.h | 250 +-------------- indra/llmessage/aicurlprivate.h | 15 +- indra/llmessage/aicurlthread.cpp | 8 +- indra/llmessage/llavatarnamecache.cpp | 2 +- indra/llmessage/llhttpclient.cpp | 156 +++++++++- indra/llmessage/llhttpclient.h | 291 +++++++++++++++++- indra/llmessage/llhttpclientadapter.cpp | 53 ---- indra/llmessage/llhttpclientadapter.h | 43 --- indra/llmessage/llhttpclientinterface.h | 45 --- indra/llmessage/llregionpresenceverifier.cpp | 8 +- indra/llmessage/llregionpresenceverifier.h | 7 +- indra/llmessage/llsdmessage.cpp | 4 +- indra/llmessage/llsdmessage.h | 20 +- indra/llmessage/llurlrequest.cpp | 2 +- indra/llmessage/llurlrequest.h | 6 +- indra/llmessage/message.cpp | 2 +- indra/newview/floatervoicelicense.cpp | 2 +- indra/newview/lggdicdownload.cpp | 2 +- indra/newview/llaccountingcostmanager.cpp | 2 +- indra/newview/llagent.cpp | 2 +- indra/newview/llappviewer.cpp | 1 + indra/newview/llassetuploadresponders.h | 4 +- indra/newview/llclassifiedstatsresponder.h | 2 +- indra/newview/lleventpoll.cpp | 4 +- indra/newview/llfloaterregiondebugconsole.cpp | 2 +- indra/newview/llfloaterregioninfo.cpp | 2 +- indra/newview/llfloaterreporter.cpp | 2 +- indra/newview/llfloaterteleport.cpp | 2 +- indra/newview/llfloatertos.cpp | 2 +- indra/newview/llhomelocationresponder.h | 2 +- indra/newview/llimpanel.cpp | 2 +- indra/newview/llimview.cpp | 2 +- indra/newview/llinventorymodel.cpp | 2 +- indra/newview/llinventorymodel.h | 2 +- .../llinventorymodelbackgroundfetch.cpp | 2 +- indra/newview/llmapresponders.h | 2 +- indra/newview/llmeshrepository.cpp | 15 +- indra/newview/llpanelgroupvoting.cpp | 4 +- indra/newview/llpanellogin.cpp | 2 +- indra/newview/llpathfindingmanager.cpp | 14 +- indra/newview/llproductinforequest.cpp | 2 +- indra/newview/llremoteparcelrequest.h | 2 +- indra/newview/lltexturefetch.cpp | 8 +- indra/newview/lltranslate.h | 2 +- indra/newview/lluploadfloaterobservers.h | 2 +- indra/newview/llviewermedia.cpp | 4 +- indra/newview/llviewermessage.cpp | 2 +- indra/newview/llviewerobjectlist.cpp | 4 +- indra/newview/llviewerregion.cpp | 4 +- indra/newview/llviewerstats.cpp | 2 +- indra/newview/llvoiceclient.cpp | 4 +- indra/newview/llwlhandlers.h | 4 +- indra/newview/llxmlrpcresponder.cpp | 4 +- indra/newview/llxmlrpcresponder.h | 8 +- 58 files changed, 549 insertions(+), 657 deletions(-) delete mode 100644 indra/llmessage/llhttpclientadapter.cpp delete mode 100644 indra/llmessage/llhttpclientadapter.h delete mode 100644 indra/llmessage/llhttpclientinterface.h diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 9b2537d98..421ad4513 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -113,9 +113,9 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // Only now print this info [doing that before setting mStatus // to STOPPED makes it much more likely that another thread runs - // after the LLCurl::Multi::run() function exits and we actually - // change this variable (which really SHOULD have been inside - // the critical area of the mSignal lock)]. + // after the AICurlPrivate::curlthread::AICurlThread::run() function + // exits and we actually change this variable (which really SHOULD + // have been inside the critical area of the mSignal lock)]. lldebugs << "LLThread::staticRun() Exiting: " << name << llendl; return NULL; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 9195aafe0..2537a4b87 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -48,6 +48,7 @@ #include "llpumpio.h" #include "llhttpclient.h" #include "llsdserialize.h" +#include "llcurl.h" LLPumpIO* gServicePump; BOOL gBreak = false; @@ -56,7 +57,7 @@ BOOL gSent = false; class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout; -class LLCrashLoggerResponder : public LLHTTPClient::Responder +class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult { public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return crashLoggerResponder_timeout; } diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 8e7f1f577..92615d236 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -44,7 +44,6 @@ set(llmessage_SOURCE_FILES lldispatcher.cpp llfiltersd2xmlrpc.cpp llhost.cpp - llhttpclientadapter.cpp llhttpnode.cpp llhttpsender.cpp llinstantmessage.cpp @@ -139,8 +138,6 @@ set(llmessage_HEADER_FILES llfollowcamparams.h llhost.h llhttpclient.h - llhttpclientinterface.h - llhttpclientadapter.h llhttpnode.h llhttpnodeadapter.h llhttpsender.h @@ -237,7 +234,6 @@ if (LL_TESTS) include(Tut) SET(llmessage_TEST_SOURCE_FILES - # llhttpclientadapter.cpp llmime.cpp llnamevalue.cpp lltrustedmessageservice.cpp diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index d4353226f..34b2211c4 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -429,151 +429,6 @@ std::string strerror(CURLcode errorcode) return curl_easy_strerror(errorcode); } -//----------------------------------------------------------------------------- -// class ResponderBase -// - -ResponderBase::ResponderBase(void) : mReferenceCount(0), mCode(CURLE_FAILED_INIT), mFinished(false) -{ - DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); -} - -ResponderBase::~ResponderBase() -{ - DoutEntering(dc::curl, "AICurlInterface::ResponderBase::~ResponderBase() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount); - llassert(mReferenceCount == 0); -} - -void ResponderBase::setURL(std::string const& url) -{ - // setURL is called from llhttpclient.cpp (request()), before calling any of the below (of course). - // We don't need locking here therefore; it's a case of initializing before use. - mURL = url; -} - -AIHTTPTimeoutPolicy const& ResponderBase::getHTTPTimeoutPolicy(void) const -{ - return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); -} - -void ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) -{ - // If the status indicates success (and we get here) then we expect the body to be LLSD. - bool const should_be_llsd = (200 <= status && status < 300); - if (should_be_llsd) - { - LLBufferStream istr(channels, buffer.get()); - if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE) - { - // Unfortunately we can't show the body of the message... I think this is a pretty serious error - // though, so if this ever happens it has to be investigated by making a copy of the buffer - // before serializing it, as is done below. - llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; - } - // LLSDSerialize::fromXML destructed buffer, we can't initialize content now. - return; - } - // Put the body in content as-is. - std::stringstream ss; - buffer->writeChannelTo(ss, channels.in()); - content = ss.str(); -#ifdef SHOW_ASSERT - if (!should_be_llsd) - { - // Make sure that the server indeed never returns LLSD as body when the http status is an error. - LLSD dummy; - bool server_sent_llsd_with_http_error = LLSDSerialize::fromXML(dummy, ss) > 0; - if (server_sent_llsd_with_http_error) - { - llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl; - } - llassert(!server_sent_llsd_with_http_error); - } -#endif -} - -void ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) -{ - LLMutexLock lock(buffer->getMutex()); - LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); - for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter) - { - if (iter->isOnChannel(channels.in())) - { - content.append((char*)iter->data(), iter->size()); - } - } -} - -// Called with HTML body. -// virtual -void ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) -{ - LLSD content; - decode_llsd_body(status, reason, channels, buffer, content); - - // Allow derived class to override at this point. - completed(status, reason, content); -} - -// virtual -void ResponderWithCompleted::completed(U32 status, std::string const& reason, LLSD const& content) -{ - // Either completedRaw() or this method must be overridden by the derived class. Hence, we should never get here. - llassert_always(false); -} - -// virtual -void Responder::finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) -{ - mCode = code; - - LLSD content; - decode_llsd_body(http_status, reason, channels, buffer, content); - - // HTTP status good? - if (200 <= http_status && http_status < 300) - { - // Allow derived class to override at this point. - result(content); - } - else - { - // Allow derived class to override at this point. - errorWithContent(http_status, reason, content); - } - - mFinished = true; -} - -// virtual -void Responder::errorWithContent(U32 status, std::string const& reason, LLSD const&) -{ - // Allow derived class to override at this point. - error(status, reason); -} - -// virtual -void Responder::error(U32 status, std::string const& reason) -{ - llinfos << mURL << " [" << status << "]: " << reason << llendl; -} - -// Friend functions. - -void intrusive_ptr_add_ref(ResponderBase* responder) -{ - responder->mReferenceCount++; -} - -void intrusive_ptr_release(ResponderBase* responder) -{ - if (--responder->mReferenceCount == 0) - { - delete responder; - } -} - } // namespace AICurlInterface //================================================================================== @@ -1281,7 +1136,7 @@ void CurlEasyRequest::print_curl_timings(void) const DoutCurl("CURLINFO_STARTTRANSFER_TIME = " << t); } -void CurlEasyRequest::getTransferInfo(AICurlInterface::TransferInfo* info) +void CurlEasyRequest::getTransferInfo(AITransferInfo* info) { // Curl explicitly demands a double for these info's. double size, total_time, speed; @@ -1294,7 +1149,7 @@ void CurlEasyRequest::getTransferInfo(AICurlInterface::TransferInfo* info) info->mSpeedDownload = speed; } -void CurlEasyRequest::getResult(CURLcode* result, AICurlInterface::TransferInfo* info) +void CurlEasyRequest::getResult(CURLcode* result, AITransferInfo* info) { *result = mResult; if (info && mResult != CURLE_FAILED_INIT) @@ -1407,7 +1262,7 @@ ThreadSafeBufferedCurlEasyRequest const* CurlResponderBuffer::get_lockobj(void) return static_cast(AIThreadSafeSimple::wrapper_cast(this)); } -void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder) +void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder) { mInput.reset(new LLBufferArray); mInput->setThreaded(true); diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index bafa2c31b..89642e602 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -53,7 +53,7 @@ #include "llatomic.h" // LLAtomicU32 #include "aithreadsafe.h" #include "llhttpstatuscodes.h" -#include "aihttpheaders.h" +#include "llhttpclient.h" // Debug Settings. extern bool gNoVerifySSLCert; @@ -124,28 +124,9 @@ class AICurlNoBody : public AICurlError { // End Exceptions. //----------------------------------------------------------------------------- -// Forward declaration. -namespace AICurlInterface { struct TransferInfo; } - -// Events generated by AICurlPrivate::CurlResponderBuffer. -struct AICurlResponderBufferEvents { - virtual void received_HTTP_header(void) = 0; // For example "HTTP/1.0 200 OK", the first header of a reply. - virtual void received_header(std::string const& key, std::string const& value) = 0; // Subsequent headers. - virtual void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) = 0; // Transaction completed. -}; - // Things defined in this namespace are called from elsewhere in the viewer code. namespace AICurlInterface { -// Output parameter of AICurlPrivate::CurlEasyRequest::getResult. -// Used in XMLRPCResponder. -struct TransferInfo { - TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) { } - F64 mSizeDownload; - F64 mTotalTime; - F64 mSpeedDownload; -}; - //----------------------------------------------------------------------------- // Global functions. @@ -182,235 +163,6 @@ void setCAFile(std::string const& file); // Can be used to set the path to the Certificate Authority file. void setCAPath(std::string const& file); -//----------------------------------------------------------------------------- -// Global classes. - -// ResponderBase - base class for all Responders. -// -// The life cycle of classes derived from this class is as follows: -// They are allocated with new on the line where get(), getByteRange() or post() is called, -// and the pointer to the allocated object is then put in a reference counting ResponderPtr. -// This ResponderPtr is passed to CurlResponderBuffer::prepRequest which stores it in its -// member mResponder. Hence, the life time of a Responder is never longer than its -// associated CurlResponderBuffer, however, if everything works correctly, then normally a -// responder is deleted in CurlResponderBuffer::removed_from_multi_handle by setting -// mReponder to NULL. -// -// Note that the lifetime of CurlResponderBuffer is (a bit) shorter than the associated -// CurlEasyRequest (because of the order of base classes of ThreadSafeBufferedCurlEasyRequest) -// and the callbacks, as set by prepRequest, only use those two. -// A callback locks the CurlEasyRequest before actually making the callback, and the -// destruction of CurlResponderBuffer also first locks the CurlEasyRequest, and then revokes -// the callbacks. This assures that a Responder is never used when the objects it uses are -// destructed. Also, if any of those are destructed then the Responder is automatically -// destructed too. -// -class ResponderBase : public AICurlResponderBufferEvents { - public: - typedef boost::shared_ptr buffer_ptr_t; - - protected: - ResponderBase(void); - virtual ~ResponderBase(); - - // Read body from buffer and put it into content. If status indicates success, interpret it as LLSD, otherwise copy it as-is. - void decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); - - // Read body from buffer and put it into content. Always copy it as-is. - void decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content); - - protected: - // Associated URL, used for debug output. - std::string mURL; - - // Headers received from the server. - AIHTTPReceivedHeaders mReceivedHeaders; - - // The curl result code. - CURLcode mCode; - - // Set when the transaction finished (with or without errors). - bool mFinished; - - public: - // Called to set the URL of the current request for this Responder, - // used only when printing debug output regarding activity of the Responder. - void setURL(std::string const& url); - - // Accessors. - std::string const& getURL(void) const { return mURL; } - CURLcode result_code(void) const { return mCode; } - - // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. - virtual void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; - - // Return true if the curl thread is done with this transaction. - // If this returns true then it is guaranteed that none of the - // virtual functions will be called anymore: the curl thread - // will not access this object anymore. - // Note that normally you don't need to call this function. - bool is_finished(void) const { return mFinished; } - - protected: - // AICurlResponderBufferEvents - - // Called when the "HTTP/1.x " header is received. - /*virtual*/ void received_HTTP_header(void) - { - // It's possible that this page was moved (302), so we already saw headers - // from the 302 page and are starting over on the new page now. - mReceivedHeaders.clear(); - } - - // Called for all remaining headers. - /*virtual*/ void received_header(std::string const& key, std::string const& value) - { - mReceivedHeaders.addHeader(key, value); - } - - // Called when the whole transaction is completed (also the body was received), but before the body is processed. - /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, TransferInfo* info) - { - completedHeaders(status, reason, mReceivedHeaders); - } - - public: - // Derived classes that implement completed_headers()/completedHeaders() should return true here. - virtual bool needsHeaders(void) const { return false; } - - // A derived class should return true if curl should follow redirections. - // The default is not to follow redirections. - virtual bool followRedir(void) { return false; } - - // Timeout policy to use. - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; - - protected: - // Derived classes can override this to get the HTML headers that were received, when the message is completed. - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) - { - // The default does nothing. - } - - private: - // Used by ResponderPtr. Object is deleted when reference count reaches zero. - LLAtomicU32 mReferenceCount; - - friend void intrusive_ptr_add_ref(ResponderBase* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. - friend void intrusive_ptr_release(ResponderBase* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. - // This function must delete the ResponderBase object when the reference count reaches zero. -}; - -// ResponderWithCompleted - base class for Responders that implement completed, or completedRaw if the response is not LLSD. -class ResponderWithCompleted : public ResponderBase { - protected: - // ResponderBase event - - // The responder finished. Do not override this function in derived classes; override completedRaw instead. - /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - mCode = code; - // Allow classes derived from ResponderBase to override completedRaw - // (if not they should override completed or be derived from Responder instead). - completedRaw(http_status, reason, channels, buffer); - mFinished = true; - } - - protected: - // Events generated by this class. - - // Derived classes can override this to get the raw data of the body of the HTML message that was received. - // The default is to interpret the content as LLSD and call completed(). - virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); - - // ... or, derived classes can override this to get LLSD content when the message is completed. - // The default aborts, as it should never be called (can't make it pure virtual though, so - // classes that override completedRaw don't need to implement this function, too). - virtual void completed(U32 status, std::string const& reason, LLSD const& content); - -#ifdef SHOW_ASSERT - // Responders derived from this class must override either completedRaw or completed. - // They may not attempt to override any of the virual functions defined by ResponderBase. - // Define those functions here with different parameters in order to cause a compile - // warning when a class accidently tries to override them. - enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; - virtual void result(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } - virtual void errorWithContent(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } - virtual void error(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } -#endif -}; - -// Responder - base class for reponders that expect LLSD in the body of the reply. -// -// Classes derived from Responder must implement result, and either errorWithContent or error. -class Responder : public ResponderBase { - protected: - // The responder finished. Do not override this function in derived classes; use ResponderWithCompleted instead. - /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); - - protected: - // Events generated by this class. - - // Derived classes must override this to receive the content of a body upon success. - virtual void result(LLSD const& content) = 0; - - // Derived classes can override this to get informed when a bad HTML status code is received. - // The default calls error(). - virtual void errorWithContent(U32 status, std::string const& reason, LLSD const& content); - - // ... or, derived classes can override this to get informed when a bad HTML status code is received. - // The default prints the error to llinfos. - virtual void error(U32 status, std::string const& reason); - - public: - // Called from LLSDMessage::ResponderAdapter::listener. - // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that it needs these functions. - - void pubErrorWithContent(CURLcode code, U32 status, std::string const& reason, LLSD const& content) { mCode = code; errorWithContent(status, reason, content); mFinished = true; } - void pubResult(LLSD const& content) { mCode = CURLE_OK; result(content); mFinished = true; } - -#ifdef SHOW_ASSERT - // Responders derived from this class must override result, and either errorWithContent or error. - // They may not attempt to override any of the virual functions defined by ResponderWithCompleted. - // Define those functions here with different parameter in order to cause a compile - // warning when a class accidently tries to override them. - enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; - virtual void completedRaw(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } - virtual void completed(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } -#endif -}; - -// A Responder is passed around as ResponderPtr, which causes it to automatically -// destruct when there are no pointers left pointing to it. -typedef boost::intrusive_ptr ResponderPtr; - -// Same as above except that this class stores the result, allowing old polling -// code to poll if the transaction finished by calling is_finished() (from the -// main the thread) and then access the results-- as opposed to immediately -// digesting the results when any of the virtual functions are called. -class LegacyPolledResponder : public ResponderWithCompleted { - protected: - U32 mStatus; - std::string mReason; - - protected: - // The responder finished. Do not override this function in derived classes. - /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - mStatus = http_status; - mReason = reason; - // Call base class implementation. - ResponderWithCompleted::finished(code, http_status, reason, channels, buffer); - } - - public: - LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR) { } - - // Accessors. - U32 http_status(void) const { return mStatus; } - std::string const& reason(void) const { return mReason; } -}; - } // namespace AICurlInterface // Forward declaration (see aicurlprivate.h). diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index 1dfd500d6..11d47ce5d 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -358,10 +358,10 @@ class CurlEasyRequest : public CurlEasyHandle { void print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code); // Called by MultiHandle::check_run_count() to fill info with the transfer info. - void getTransferInfo(AICurlInterface::TransferInfo* info); + void getTransferInfo(AITransferInfo* info); // If result != CURLE_FAILED_INIT then also info was filled. - void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL); + void getResult(CURLcode* result, AITransferInfo* info = NULL); // For debugging purposes. void print_curl_timings(void) const; @@ -424,7 +424,8 @@ class CurlEasyRequest : public CurlEasyHandle { // Buffers used by the AICurlInterface::Request API. // Curl callbacks write into and read from these buffers. -// The interface with the rest of the code is through AICurlInterface::Responder. +// The interface with the rest of the code is through +// AICurlInterface::ResponderBase and derived classes. // // The lifetime of a CurlResponderBuffer is slightly shorter than its // associated CurlEasyRequest; this class can only be created as base class @@ -439,10 +440,10 @@ class CurlEasyRequest : public CurlEasyHandle { // is deleted and the CurlResponderBuffer destructed. class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AICurlEasyHandleEvents { public: - typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t; + typedef boost::shared_ptr buffer_ptr_t; void resetState(AICurlEasyRequest_wat& curl_easy_request_w); - void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, AICurlInterface::ResponderPtr responder); + void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder); buffer_ptr_t& getInput(void) { return mInput; } buffer_ptr_t& getOutput(void) { return mOutput; } @@ -463,7 +464,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC // Events from this class. /*virtual*/ void received_HTTP_header(void); /*virtual*/ void received_header(std::string const& key, std::string const& value); - /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); + /*virtual*/ void completed_headers(U32 status, std::string const& reason, AITransferInfo* info); // CurlEasyHandle events. /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); @@ -474,7 +475,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC buffer_ptr_t mInput; U8* mLastRead; // Pointer into mInput where we last stopped reading (or NULL to start at the beginning). buffer_ptr_t mOutput; - AICurlInterface::ResponderPtr mResponder; + LLHTTPClient::ResponderPtr mResponder; //U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used. U32 mStatus; // HTTP status, decoded from the first header line. std::string mReason; // The "reason" from the same header line. diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index b1b518c20..e36792d5b 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -2075,7 +2075,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request std::string responseReason; CURLcode code; - AICurlInterface::TransferInfo info; + AITransferInfo info; curl_easy_request_w->getResult(&code, &info); if (code == CURLE_OK) { @@ -2104,7 +2104,7 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request llassert(mEventsTarget == mResponder.get()); // Allow clients to parse result codes and headers before we attempt to parse // the body and provide completed/result/error calls. - mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); + mEventsTarget->completed_headers(responseCode, responseReason, (code == CURLE_FAILED_INIT) ? NULL : &info); } mResponder->finished(code, responseCode, responseReason, sChannels, mOutput); mResponder = NULL; @@ -2124,10 +2124,10 @@ void CurlResponderBuffer::received_header(std::string const& key, std::string co mEventsTarget->received_header(key, value); } -void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) +void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason, AITransferInfo* info) { if (mEventsTarget) - mEventsTarget->completed_headers(status, reason, code, info); + mEventsTarget->completed_headers(status, reason, info); } //static diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 36518df4b..a3aaebb2a 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -174,7 +174,7 @@ namespace LLAvatarNameCache class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy avatarNameResponder_timeout; -class LLAvatarNameResponder : public LLHTTPClient::Responder +class LLAvatarNameResponder : public LLHTTPClient::ResponderWithResult { private: // need to store agent ids that are part of this request in case of diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 259b671d4..97fce1373 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -35,6 +35,7 @@ #include "llvfile.h" #include "llurlrequest.h" #include "llxmltree.h" +#include "aihttptimeoutpolicy.h" class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy blockingLLSDPost_timeout; @@ -195,7 +196,7 @@ static void request( const std::string& url, LLURLRequest::ERequestAction method, Injector* body_injector, - LLCurl::ResponderPtr responder, + LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth = false, bool no_compression = false) @@ -254,10 +255,159 @@ void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr r } //============================================================================= +// Responders base classes. +// + +//----------------------------------------------------------------------------- +// class LLHTTPClient::ResponderBase +// + +LLHTTPClient::ResponderBase::ResponderBase(void) : mReferenceCount(0), mCode(CURLE_FAILED_INIT), mFinished(false) +{ + DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); +} + +LLHTTPClient::ResponderBase::~ResponderBase() +{ + DoutEntering(dc::curl, "AICurlInterface::ResponderBase::~ResponderBase() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount); + llassert(mReferenceCount == 0); +} + +void LLHTTPClient::ResponderBase::setURL(std::string const& url) +{ + // setURL is called from llhttpclient.cpp (request()), before calling any of the below (of course). + // We don't need locking here therefore; it's a case of initializing before use. + mURL = url; +} + +AIHTTPTimeoutPolicy const& LLHTTPClient::ResponderBase::getHTTPTimeoutPolicy(void) const +{ + return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); +} + +void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) +{ + // If the status indicates success (and we get here) then we expect the body to be LLSD. + bool const should_be_llsd = (200 <= status && status < 300); + if (should_be_llsd) + { + LLBufferStream istr(channels, buffer.get()); + if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE) + { + // Unfortunately we can't show the body of the message... I think this is a pretty serious error + // though, so if this ever happens it has to be investigated by making a copy of the buffer + // before serializing it, as is done below. + llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; + } + // LLSDSerialize::fromXML destructed buffer, we can't initialize content now. + return; + } + // Put the body in content as-is. + std::stringstream ss; + buffer->writeChannelTo(ss, channels.in()); + content = ss.str(); +#ifdef SHOW_ASSERT + if (!should_be_llsd) + { + // Make sure that the server indeed never returns LLSD as body when the http status is an error. + LLSD dummy; + bool server_sent_llsd_with_http_error = LLSDSerialize::fromXML(dummy, ss) > 0; + if (server_sent_llsd_with_http_error) + { + llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl; + } + llassert(!server_sent_llsd_with_http_error); + } +#endif +} + +void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) +{ + LLMutexLock lock(buffer->getMutex()); + LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); + for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter) + { + if (iter->isOnChannel(channels.in())) + { + content.append((char*)iter->data(), iter->size()); + } + } +} + +// Called with HTML body. +// virtual +void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +{ + LLSD content; + decode_llsd_body(status, reason, channels, buffer, content); + + // Allow derived class to override at this point. + completed(status, reason, content); +} + +// virtual +void LLHTTPClient::ResponderWithCompleted::completed(U32 status, std::string const& reason, LLSD const& content) +{ + // Either completedRaw() or this method must be overridden by the derived class. Hence, we should never get here. + llassert_always(false); +} + +// virtual +void LLHTTPClient::ResponderWithResult::finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +{ + mCode = code; + + LLSD content; + decode_llsd_body(http_status, reason, channels, buffer, content); + + // HTTP status good? + if (200 <= http_status && http_status < 300) + { + // Allow derived class to override at this point. + result(content); + } + else + { + // Allow derived class to override at this point. + errorWithContent(http_status, reason, content); + } + + mFinished = true; +} + +// virtual +void LLHTTPClient::ResponderWithResult::errorWithContent(U32 status, std::string const& reason, LLSD const&) +{ + // Allow derived class to override at this point. + error(status, reason); +} + +// virtual +void LLHTTPClient::ResponderWithResult::error(U32 status, std::string const& reason) +{ + llinfos << mURL << " [" << status << "]: " << reason << llendl; +} + +// Friend functions. + +void intrusive_ptr_add_ref(LLHTTPClient::ResponderBase* responder) +{ + responder->mReferenceCount++; +} + +void intrusive_ptr_release(LLHTTPClient::ResponderBase* responder) +{ + if (--responder->mReferenceCount == 0) + { + delete responder; + } +} + +//----------------------------------------------------------------------------- // Blocking Responders. // -class BlockingResponder : public AICurlInterface::LegacyPolledResponder { +class BlockingResponder : public LLHTTPClient::LegacyPolledResponder { private: LLCondition mSignal; // Wait condition to wait till mFinished is true. static LLSD LLSD_dummy; @@ -346,7 +496,7 @@ public: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingRawGet_timeout; } }; -// End blocking responders. +// End (blocking) responders. //============================================================================= // These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome. diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 5234ec736..05f3d4b63 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -32,29 +32,302 @@ */ #include +#include // CURLcode +#include #include "llassettype.h" -#include "llcurl.h" +#include "llhttpstatuscodes.h" #include "aihttpheaders.h" class LLUUID; class LLPumpIO; class LLSD; class AIHTTPTimeoutPolicy; +class LLBufferArray; +class LLChannelDescriptors; extern AIHTTPTimeoutPolicy responderIgnore_timeout; typedef struct _xmlrpc_request* XMLRPC_REQUEST; typedef struct _xmlrpc_value* XMLRPC_VALUE; -class LLHTTPClient -{ -public: - // For convenience - typedef LLCurl::Responder Responder; - typedef LLCurl::ResponderPtr ResponderPtr; +// Output parameter of AICurlPrivate::CurlEasyRequest::getResult. +// Used in XMLRPCResponder. +struct AITransferInfo { + AITransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) { } + F64 mSizeDownload; + F64 mTotalTime; + F64 mSpeedDownload; +}; - class ResponderIgnoreBody : public Responder { void result(LLSD const&) { } }; - class ResponderIgnore : public ResponderIgnoreBody { virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} }; +// Events generated by AICurlPrivate::CurlResponderBuffer. +struct AICurlResponderBufferEvents { + virtual void received_HTTP_header(void) = 0; // For example "HTTP/1.0 200 OK", the first header of a reply. + virtual void received_header(std::string const& key, std::string const& value) = 0; // Subsequent headers. + virtual void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) = 0; // Transaction completed. +}; + +class LLHTTPClient { +public: + + /** @name Responder base classes */ + //@{ + + /** + * @class ResponderBase + * @brief Base class for all Responders. + * + * The life cycle of classes derived from this class is as follows: + * They are allocated with new on the line where get(), getByteRange() or post() is called, + * and the pointer to the allocated object is then put in a reference counting ResponderPtr. + * This ResponderPtr is passed to CurlResponderBuffer::prepRequest which stores it in its + * member mResponder. Hence, the life time of a Responder is never longer than its + * associated CurlResponderBuffer, however, if everything works correctly, then normally a + * responder is deleted in CurlResponderBuffer::removed_from_multi_handle by setting + * mReponder to NULL. + * + * Note that the lifetime of CurlResponderBuffer is (a bit) shorter than the associated + * CurlEasyRequest (because of the order of base classes of ThreadSafeBufferedCurlEasyRequest) + * and the callbacks, as set by prepRequest, only use those two. + * A callback locks the CurlEasyRequest before actually making the callback, and the + * destruction of CurlResponderBuffer also first locks the CurlEasyRequest, and then revokes + * the callbacks. This assures that a Responder is never used when the objects it uses are + * destructed. Also, if any of those are destructed then the Responder is automatically + * destructed too. + */ + class ResponderBase : public AICurlResponderBufferEvents { + public: + typedef boost::shared_ptr buffer_ptr_t; + + protected: + ResponderBase(void); + virtual ~ResponderBase(); + + // Read body from buffer and put it into content. If status indicates success, interpret it as LLSD, otherwise copy it as-is. + void decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); + + // Read body from buffer and put it into content. Always copy it as-is. + void decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content); + + protected: + // Associated URL, used for debug output. + std::string mURL; + + // Headers received from the server. + AIHTTPReceivedHeaders mReceivedHeaders; + + // The curl result code. + CURLcode mCode; + + // Set when the transaction finished (with or without errors). + bool mFinished; + + public: + // Called to set the URL of the current request for this Responder, + // used only when printing debug output regarding activity of the Responder. + void setURL(std::string const& url); + + // Accessors. + std::string const& getURL(void) const { return mURL; } + CURLcode result_code(void) const { return mCode; } + + // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. + virtual void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; + + // Return true if the curl thread is done with this transaction. + // If this returns true then it is guaranteed that none of the + // virtual functions will be called anymore: the curl thread + // will not access this object anymore. + // Note that normally you don't need to call this function. + bool is_finished(void) const { return mFinished; } + + protected: + // AICurlResponderBufferEvents + + // Called when the "HTTP/1.x " header is received. + /*virtual*/ void received_HTTP_header(void) + { + // It's possible that this page was moved (302), so we already saw headers + // from the 302 page and are starting over on the new page now. + mReceivedHeaders.clear(); + } + + // Called for all remaining headers. + /*virtual*/ void received_header(std::string const& key, std::string const& value) + { + mReceivedHeaders.addHeader(key, value); + } + + // Called when the whole transaction is completed (also the body was received), but before the body is processed. + /*virtual*/ void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) + { + completedHeaders(status, reason, mReceivedHeaders); + } + + public: + // Derived classes that implement completed_headers()/completedHeaders() should return true here. + virtual bool needsHeaders(void) const { return false; } + + // A derived class should return true if curl should follow redirections. + // The default is not to follow redirections. + virtual bool followRedir(void) { return false; } + + // Timeout policy to use. + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; + + protected: + // Derived classes can override this to get the HTML headers that were received, when the message is completed. + virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + { + // The default does nothing. + } + + private: + // Used by ResponderPtr. Object is deleted when reference count reaches zero. + LLAtomicU32 mReferenceCount; + + friend void intrusive_ptr_add_ref(ResponderBase* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. + friend void intrusive_ptr_release(ResponderBase* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. + // This function must delete the ResponderBase object when the reference count reaches zero. + }; + + /** + * @class ResponderWithCompleted + * @brief Base class for Responders that implement completed, or completedRaw if the response is not LLSD. + */ + class ResponderWithCompleted : public ResponderBase { + protected: + // ResponderBase event + + // The responder finished. Do not override this function in derived classes; override completedRaw instead. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + mCode = code; + // Allow classes derived from ResponderBase to override completedRaw + // (if not they should override completed or be derived from Responder instead). + completedRaw(http_status, reason, channels, buffer); + mFinished = true; + } + + protected: + // Events generated by this class. + + // Derived classes can override this to get the raw data of the body of the HTML message that was received. + // The default is to interpret the content as LLSD and call completed(). + virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + + // ... or, derived classes can override this to get LLSD content when the message is completed. + // The default aborts, as it should never be called (can't make it pure virtual though, so + // classes that override completedRaw don't need to implement this function, too). + virtual void completed(U32 status, std::string const& reason, LLSD const& content); + +#ifdef SHOW_ASSERT + // Responders derived from this class must override either completedRaw or completed. + // They may not attempt to override any of the virual functions defined by ResponderBase. + // Define those functions here with different parameters in order to cause a compile + // warning when a class accidently tries to override them. + enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; + virtual void result(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void errorWithContent(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void error(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } +#endif + }; + + /** + * @class ResponderWithResult + * @brief Base class for reponders that expect LLSD in the body of the reply. + * + * Classes derived from ResponderWithResult must implement result, and either errorWithContent or error. + */ + class ResponderWithResult : public ResponderBase { + protected: + // The responder finished. Do not override this function in derived classes; use ResponderWithCompleted instead. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + + protected: + // Events generated by this class. + + // Derived classes must override this to receive the content of a body upon success. + virtual void result(LLSD const& content) = 0; + + // Derived classes can override this to get informed when a bad HTML status code is received. + // The default calls error(). + virtual void errorWithContent(U32 status, std::string const& reason, LLSD const& content); + + // ... or, derived classes can override this to get informed when a bad HTML status code is received. + // The default prints the error to llinfos. + virtual void error(U32 status, std::string const& reason); + + public: + // Called from LLSDMessage::ResponderAdapter::listener. + // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that it needs these functions. + + void pubErrorWithContent(CURLcode code, U32 status, std::string const& reason, LLSD const& content) { mCode = code; errorWithContent(status, reason, content); mFinished = true; } + void pubResult(LLSD const& content) { mCode = CURLE_OK; result(content); mFinished = true; } + +#ifdef SHOW_ASSERT + // Responders derived from this class must override result, and either errorWithContent or error. + // They may not attempt to override any of the virual functions defined by ResponderWithCompleted. + // Define those functions here with different parameter in order to cause a compile + // warning when a class accidently tries to override them. + enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; + virtual void completedRaw(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void completed(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } +#endif + }; + + /** + * @class LegacyPolledResponder + * @brief As ResponderWithCompleted but caches the result for polling. + * + * This class allows old polling code to poll if the transaction finished + * by calling is_finished() (from the main the thread) and then access the + * results-- as opposed to immediately digesting the results when any of + * the virtual functions are called. + */ + class LegacyPolledResponder : public ResponderWithCompleted { + protected: + U32 mStatus; + std::string mReason; + + protected: + // The responder finished. Do not override this function in derived classes. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + mStatus = http_status; + mReason = reason; + // Call base class implementation. + ResponderWithCompleted::finished(code, http_status, reason, channels, buffer); + } + + public: + LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR) { } + + // Accessors. + U32 http_status(void) const { return mStatus; } + std::string const& reason(void) const { return mReason; } + }; + + /** + * @class ResponderIgnoreBody + * @brief Base class for responders that ignore the result body. + */ + class ResponderIgnoreBody : public ResponderWithResult { + void result(LLSD const&) { } + }; + + /** + * @class ResponderIgnore + * @brief Responder that ignores the reply, if any, from the server. + */ + class ResponderIgnore : public ResponderIgnoreBody { + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} + }; + + // A Responder is passed around as ResponderPtr, which causes it to automatically + // destruct when there are no pointers left pointing to it. + typedef boost::intrusive_ptr ResponderPtr; + + //@} /** @name non-blocking API */ //@{ diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp deleted file mode 100644 index 3c064d61b..000000000 --- a/indra/llmessage/llhttpclientadapter.cpp +++ /dev/null @@ -1,53 +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) -{ - // Pragma is required to stop curl adding "no-cache" - // Space is required to stop llurlrequest from turnning off proxying - AIHTTPHeaders empty_pragma_header("Pragma", " "); - LLHTTPClient::get(url, responder, empty_pragma_header); -} - -void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) -{ - // as above - AIHTTPHeaders empty_pragma_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); -} - diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h deleted file mode 100644 index aae6426a5..000000000 --- a/indra/llmessage/llhttpclientadapter.h +++ /dev/null @@ -1,43 +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 -{ -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); -}; - -#endif - diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h deleted file mode 100644 index 12a3857a6..000000000 --- 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 - -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/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp index 01d78ed3e..b39b81424 100644 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ b/indra/llmessage/llregionpresenceverifier.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" #include "llregionpresenceverifier.h" -#include "llhttpclientinterface.h" #include #include "net.h" #include "message.h" @@ -78,7 +77,7 @@ void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content) std::stringstream uri; uri << "http://" << destination.getString() << "/state/basic/"; - mSharedData->getHttpClient().get( + LLHTTPClient::get( uri.str(), new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount)); } @@ -131,12 +130,11 @@ void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry() { - LLSD headers; - headers["Cache-Control"] = "no-cache, max-age=0"; + AIHTTPHeaders headers("Cache-Control", "no-cache, max-age=0"); llinfos << "Requesting region information, get uncached for region " << mUri << llendl; --mRetryCount; - mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers); + LLHTTPClient::get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers); } void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason) diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h index 20dccb14c..ea2667210 100644 --- a/indra/llmessage/llregionpresenceverifier.h +++ b/indra/llmessage/llregionpresenceverifier.h @@ -33,7 +33,6 @@ #include "llsd.h" #include -class LLHTTPClientInterface; class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy regionResponder_timeout; extern AIHTTPTimeoutPolicy verifiedDestinationResponder_timeout; @@ -50,15 +49,13 @@ public: virtual void onRegionVerified(const LLSD& region_details) = 0; virtual void onRegionVerificationFailed() = 0; - virtual LLHTTPClientInterface& getHttpClient() = 0; - public: /* but not really -- don't touch this */ U32 mReferenceCount; }; typedef boost::intrusive_ptr ResponsePtr; - class RegionResponder : public LLHTTPClient::Responder + class RegionResponder : public LLHTTPClient::ResponderWithResult { public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return regionResponder_timeout; } @@ -75,7 +72,7 @@ public: S32 mRetryCount; }; - class VerifiedDestinationResponder : public LLHTTPClient::Responder + class VerifiedDestinationResponder : public LLHTTPClient::ResponderWithResult { public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return verifiedDestinationResponder_timeout; } diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 52869f3ef..dc091a543 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -145,7 +145,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string } } -LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::Responder* responder, +LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderWithResult* responder, const std::string& name): mResponder(responder), mReplyPump(name + ".reply", true), // tweak name for uniqueness @@ -162,7 +162,7 @@ std::string LLSDMessage::ResponderAdapter::getTimeoutPolicyName(void) const bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) { - AICurlInterface::Responder* responder = dynamic_cast(mResponder.get()); + LLHTTPClient::ResponderWithResult* responder = dynamic_cast(mResponder.get()); // If this assertion fails then ResponderAdapter has been used for a ResponderWithCompleted derived class, // which is not allowed because ResponderAdapter can only work for classes derived from Responder that // implement result() and errorWithContent (or just error). diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index b839cbc74..72b7dc675 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -66,31 +66,39 @@ public: * 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 + * The LLHTTPClient::ResponderBase 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 + * LLHTTPClient::ResponderWithResult subclasses, we provide this adapter class * for transitional purposes only. 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. + * + * Singularity note: I think this class/API is a bad idea that makes things + * more complex, a lot slower and less OO. The idea to get methods called + * on the same class that does the request is a nice idea, but should + * be implemented through boost::bind and NOT use LLSD. Avoid. + * Also note that this only works for ResponderWithResult derived classes, + * not for responders derived from ResponderWithCompleted. + * --Aleric */ class ResponderAdapter { public: /** - * Bind the new LLHTTPClient::Responder subclass instance. + * Bind the new LLHTTPClient::ResponderWithResult 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::Responder* responder, + ResponderAdapter(LLHTTPClient::ResponderWithResult* responder, const std::string& name="ResponderAdapter"); /// EventPump name on which LLSDMessage should post reply event @@ -125,13 +133,13 @@ private: friend class LLCapabilityListener; /// Responder used for internal purposes by LLSDMessage and /// LLCapabilityListener. Others should use higher-level APIs. - class EventResponder: public LLHTTPClient::Responder + class EventResponder: public LLHTTPClient::ResponderWithResult { public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return *mHTTPTimeoutPolicy; } /** - * LLHTTPClient::Responder that dispatches via named LLEventPump instances. + * LLHTTPClient::ResponderWithResult 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 diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 8dea0c9b2..3653f7058 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -77,7 +77,7 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) // This might throw AICurlNoEasyHandle. LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, - AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) : + LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) : AICurlEasyRequestStateMachine(true), mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression), mBody(body), mResponder(responder), mHeaders(headers) { diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index a356ed786..ba046a2e0 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -42,7 +42,7 @@ class Injector { public: - typedef AICurlInterface::Responder::buffer_ptr_t buffer_ptr_t; + typedef LLHTTPClient::ResponderBase::buffer_ptr_t buffer_ptr_t; virtual char const* contentType(void) const = 0; virtual U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) = 0; }; @@ -75,7 +75,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { * @param action One of the ERequestAction enumerations. * @param url The url of the request. It should already be encoded. */ - LLURLRequest(ERequestAction action, std::string const& url, Injector* body, AICurlInterface::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression); + LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression); protected: // Call abort(), not delete. @@ -118,7 +118,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { bool mNoCompression; // Set to disable using gzip. Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT. U32 mBodySize; - AICurlInterface::ResponderPtr mResponder; + LLHTTPClient::ResponderPtr mResponder; AIHTTPHeaders mHeaders; protected: diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index d082c248c..f36934d49 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -107,7 +107,7 @@ public: namespace { - class LLFnPtrResponder : public LLHTTPClient::Responder + class LLFnPtrResponder : public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLFnPtrResponder); public: diff --git a/indra/newview/floatervoicelicense.cpp b/indra/newview/floatervoicelicense.cpp index ca887663b..322c4778e 100644 --- a/indra/newview/floatervoicelicense.cpp +++ b/indra/newview/floatervoicelicense.cpp @@ -65,7 +65,7 @@ FloaterVoiceLicense::FloaterVoiceLicense(const LLSD& key) // 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 LLIamHereVoice : public LLHTTPClient::Responder +class LLIamHereVoice : public LLHTTPClient::ResponderWithResult { private: LLIamHereVoice( FloaterVoiceLicense* parent ) : diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index 27f9dff7d..d4caa10ae 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -52,7 +52,7 @@ class lggDicDownloadFloater; class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy emeraldDicDownloader_timeout; -class EmeraldDicDownloader : public AICurlInterface::ResponderWithCompleted +class EmeraldDicDownloader : public LLHTTPClient::ResponderWithCompleted { public: EmeraldDicDownloader(lggDicDownloadFloater* spanel, std::string sname); diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 998262c15..a319e38d7 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -38,7 +38,7 @@ LLAccountingCostManager::LLAccountingCostManager() { } //=============================================================================== -class LLAccountingCostResponder : public LLCurl::Responder +class LLAccountingCostResponder : public LLHTTPClient::ResponderWithResult { public: LLAccountingCostResponder( const LLSD& objectIDs ) diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 43eceade5..30415e458 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2171,7 +2171,7 @@ void LLAgent::setStartPosition( U32 location_id ) // This awkward idiom warrants explanation. // For starters, LLSDMessage::ResponderAdapter is ONLY for testing the new - // LLSDMessage functionality with a pre-existing LLHTTPClient::Responder. + // LLSDMessage functionality with a pre-existing LLHTTPClient::ResponderWithResult. // 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. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b2c82a738..9ae51fe20 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -95,6 +95,7 @@ #include "llprimitive.h" #include "llnotifications.h" #include "llnotificationsutil.h" +#include "llcurl.h" #include #if LL_WINDOWS diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 6de99808d..fa4e5a8eb 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -51,7 +51,7 @@ void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, // Abstract class for supporting asset upload // via capabilities -class LLAssetUploadResponder : public LLHTTPClient::Responder +class LLAssetUploadResponder : public LLHTTPClient::ResponderWithResult { public: LLAssetUploadResponder(const LLSD& post_data, @@ -96,7 +96,7 @@ public: // are needed (such as different confirmation messages, etc.) // the functions onApplicationLevelError and showConfirmationDialog. class LLNewAgentInventoryVariablePriceResponder : - public LLHTTPClient::Responder + public LLHTTPClient::ResponderWithResult { public: LLNewAgentInventoryVariablePriceResponder( diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index f09245a66..f317d5851 100644 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -40,7 +40,7 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy classifiedStatsResponder_timeout; -class LLClassifiedStatsResponder : public LLHTTPClient::Responder +class LLClassifiedStatsResponder : public LLHTTPClient::ResponderWithResult { public: LLClassifiedStatsResponder(LLHandle classified_panel_handle, LLUUID classified_id); diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 1499c8363..6548d520b 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -58,7 +58,7 @@ namespace 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 + class LLEventPollResponder : public LLHTTPClient::ResponderWithResult { public: @@ -273,7 +273,7 @@ LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender) LLEventPoll::~LLEventPoll() { - AICurlInterface::ResponderBase* responderp = mImpl.get(); + LLHTTPClient::ResponderBase* responderp = mImpl.get(); LLEventPollResponder* event_poll_responder = dynamic_cast(responderp); if (event_poll_responder) event_poll_responder->stop(); } diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 36ca0daab..a17eeab1e 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -88,7 +88,7 @@ namespace virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return asyncConsoleResponder_timeout; } }; - class ConsoleResponder : public LLHTTPClient::Responder + class ConsoleResponder : public LLHTTPClient::ResponderWithResult { public: ConsoleResponder(LLTextEditor *output) : mOutput(output) diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 482a4af3c..0a6b234f0 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2310,7 +2310,7 @@ void LLPanelEstateInfo::getEstateOwner() } */ -class LLEstateChangeInfoResponder : public LLHTTPClient::Responder +class LLEstateChangeInfoResponder : public LLHTTPClient::ResponderWithResult { public: LLEstateChangeInfoResponder(void* userdata) : mpPanel((LLPanelEstateInfo*)userdata) {}; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index ff8d32af5..5de9bf503 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -858,7 +858,7 @@ public: } }; -class LLUserReportResponder : public LLHTTPClient::Responder +class LLUserReportResponder : public LLHTTPClient::ResponderWithResult { public: LLUserReportResponder() { } diff --git a/indra/newview/llfloaterteleport.cpp b/indra/newview/llfloaterteleport.cpp index cf5a84ee0..04ca6d499 100644 --- a/indra/newview/llfloaterteleport.cpp +++ b/indra/newview/llfloaterteleport.cpp @@ -64,7 +64,7 @@ extern AIHTTPTimeoutPolicy placeAvatarTeleportResponder_timeout; // OGPX TODO: mResult should not get replaced in result(), instead // should replace individual LLSD fields in mResult. class LLPlaceAvatarTeleportResponder : - public LLHTTPClient::Responder + public LLHTTPClient::ResponderWithResult { public: LLPlaceAvatarTeleportResponder() diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index fa010f282..e5237e8f2 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -92,7 +92,7 @@ LLFloaterTOS::LLFloaterTOS(ETOSType type, const std::string & message) // 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 +class LLIamHere : public LLHTTPClient::ResponderWithResult { private: LLIamHere( LLFloaterTOS* parent ) : diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 67ba049fe..c9d098740 100644 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -42,7 +42,7 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy homeLocationResponder_timeout; /* Typedef, Enum, Class, Struct, etc. */ -class LLHomeLocationResponder : public LLHTTPClient::Responder +class LLHomeLocationResponder : public LLHTTPClient::ResponderWithResult { virtual void result( const LLSD& content ); virtual void error( U32 status, const std::string& reason ); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index ff69483ca..bd8ec64be 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -301,7 +301,7 @@ bool send_start_session_messages( return false; } -class LLVoiceCallCapResponder : public LLHTTPClient::Responder +class LLVoiceCallCapResponder : public LLHTTPClient::ResponderWithResult { public: LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 5aec41d50..d6dabcdae 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -95,7 +95,7 @@ LLIMMgr* gIMMgr = NULL; // return (LLStringUtil::compareDict( a->mName, b->mName ) < 0); //} class LLViewerChatterBoxInvitationAcceptResponder : - public LLHTTPClient::Responder + public LLHTTPClient::ResponderWithResult { public: LLViewerChatterBoxInvitationAcceptResponder( diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 70173952a..0b369df09 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -470,7 +470,7 @@ LLUUID LLInventoryModel::findCategoryByName(std::string name) return LLUUID::null; } -class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder +class LLCreateInventoryCategoryResponder : public LLHTTPClient::ResponderWithResult { public: LLCreateInventoryCategoryResponder(LLInventoryModel* model, diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index c567c505d..b22efb9eb 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -83,7 +83,7 @@ public: typedef LLDynamicArray > item_array_t; typedef std::set changed_items_t; - class fetchInventoryResponder : public LLHTTPClient::Responder + class fetchInventoryResponder : public LLHTTPClient::ResponderWithResult { public: fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index cb2be7419..d1ed71e8b 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -393,7 +393,7 @@ void LLInventoryModelFetchItemResponder::error( U32 status, const std::string& r LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); } -class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder +class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::ResponderWithResult { public: LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : diff --git a/indra/newview/llmapresponders.h b/indra/newview/llmapresponders.h index 94843d0e9..8b287c9fb 100644 --- a/indra/newview/llmapresponders.h +++ b/indra/newview/llmapresponders.h @@ -38,7 +38,7 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy mapLayerResponder_timeout; -class LLMapLayerResponder : public LLHTTPClient::Responder +class LLMapLayerResponder : public LLHTTPClient::ResponderWithResult { virtual void result(const LLSD& content); virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mapLayerResponder_timeout; } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 738e327ac..74f090532 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -65,6 +65,7 @@ #include "llinventorymodel.h" #include "llfoldertype.h" #include "llviewerparcelmgr.h" +#include "aicurl.h" #include "boost/lexical_cast.hpp" #ifndef LL_WINDOWS @@ -209,7 +210,7 @@ S32 LLMeshRepoThread::sActiveHeaderRequests = 0; S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; -class LLMeshHeaderResponder : public LLCurl::ResponderWithCompleted +class LLMeshHeaderResponder : public LLHTTPClient::ResponderWithCompleted { public: LLVolumeParams mMeshParams; @@ -232,7 +233,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshHeaderResponder_timeout; } }; -class LLMeshLODResponder : public LLCurl::ResponderWithCompleted +class LLMeshLODResponder : public LLHTTPClient::ResponderWithCompleted { public: LLVolumeParams mMeshParams; @@ -258,7 +259,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshLODResponder_timeout; } }; -class LLMeshSkinInfoResponder : public LLCurl::ResponderWithCompleted +class LLMeshSkinInfoResponder : public LLHTTPClient::ResponderWithCompleted { public: LLUUID mMeshID; @@ -277,7 +278,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshSkinInfoResponder_timeout; } }; -class LLMeshDecompositionResponder : public LLCurl::ResponderWithCompleted +class LLMeshDecompositionResponder : public LLHTTPClient::ResponderWithCompleted { public: LLUUID mMeshID; @@ -296,7 +297,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshDecompositionResponder_timeout; } }; -class LLMeshPhysicsShapeResponder : public LLCurl::ResponderWithCompleted +class LLMeshPhysicsShapeResponder : public LLHTTPClient::ResponderWithCompleted { public: LLUUID mMeshID; @@ -365,7 +366,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s } } -class LLWholeModelFeeResponder: public LLCurl::ResponderWithCompleted +class LLWholeModelFeeResponder: public LLHTTPClient::ResponderWithCompleted { LLMeshUploadThread* mThread; LLSD mModelData; @@ -419,7 +420,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return wholeModelFeeResponder_timeout; } }; -class LLWholeModelUploadResponder: public LLCurl::ResponderWithCompleted +class LLWholeModelUploadResponder: public LLHTTPClient::ResponderWithCompleted { LLMeshUploadThread* mThread; LLSD mModelData; diff --git a/indra/newview/llpanelgroupvoting.cpp b/indra/newview/llpanelgroupvoting.cpp index 68a8bc4be..89134c437 100644 --- a/indra/newview/llpanelgroupvoting.cpp +++ b/indra/newview/llpanelgroupvoting.cpp @@ -684,7 +684,7 @@ void LLPanelGroupVoting::handleFailure( } } -class LLStartGroupVoteResponder : public LLHTTPClient::Responder +class LLStartGroupVoteResponder : public LLHTTPClient::ResponderWithResult { public: LLStartGroupVoteResponder(const LLUUID& group_id) @@ -717,7 +717,7 @@ private: LLUUID mGroupID; }; -class LLGroupProposalBallotResponder : public LLHTTPClient::Responder +class LLGroupProposalBallotResponder : public LLHTTPClient::ResponderWithResult { public: LLGroupProposalBallotResponder(const LLUUID& group_id) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 27e3d1f4d..cc20ab576 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -168,7 +168,7 @@ std::string gFullName; // 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 LLIamHereLogin : public AICurlInterface::ResponderWithCompleted +class LLIamHereLogin : public LLHTTPClient::ResponderWithCompleted { private: LLIamHereLogin( LLPanelLogin* parent ) : diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index a82478557..4f23117cc 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -110,7 +110,7 @@ LLHTTPRegistration gHTTPRegistrationAgentStateChangeNode // NavMeshStatusResponder //--------------------------------------------------------------------------- -class NavMeshStatusResponder : public LLHTTPClient::Responder +class NavMeshStatusResponder : public LLHTTPClient::ResponderWithResult { public: NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly); @@ -133,7 +133,7 @@ private: // NavMeshResponder //--------------------------------------------------------------------------- -class NavMeshResponder : public LLHTTPClient::Responder +class NavMeshResponder : public LLHTTPClient::ResponderWithResult { public: NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); @@ -155,7 +155,7 @@ private: // AgentStateResponder //--------------------------------------------------------------------------- -class AgentStateResponder : public LLHTTPClient::Responder +class AgentStateResponder : public LLHTTPClient::ResponderWithResult { public: AgentStateResponder(const std::string &pCapabilityURL); @@ -175,7 +175,7 @@ private: //--------------------------------------------------------------------------- // NavMeshRebakeResponder //--------------------------------------------------------------------------- -class NavMeshRebakeResponder : public LLHTTPClient::Responder +class NavMeshRebakeResponder : public LLHTTPClient::ResponderWithResult { public: NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); @@ -235,7 +235,7 @@ typedef boost::shared_ptr LinksetsResponderPtr; //--------------------------------------------------------------------------- // ObjectLinksetsResponder //--------------------------------------------------------------------------- -class ObjectLinksetsResponder : public LLHTTPClient::Responder +class ObjectLinksetsResponder : public LLHTTPClient::ResponderWithResult { public: ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); @@ -255,7 +255,7 @@ private: //--------------------------------------------------------------------------- // TerrainLinksetsResponder //--------------------------------------------------------------------------- -class TerrainLinksetsResponder : public LLHTTPClient::Responder +class TerrainLinksetsResponder : public LLHTTPClient::ResponderWithResult { public: TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); @@ -275,7 +275,7 @@ private: //--------------------------------------------------------------------------- // CharactersResponder //--------------------------------------------------------------------------- -class CharactersResponder : public LLHTTPClient::Responder +class CharactersResponder : public LLHTTPClient::ResponderWithResult { public: CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index b164a91fc..ff9014deb 100644 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -42,7 +42,7 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy productInfoRequestResponder_timeout; -class LLProductInfoRequestResponder : public LLHTTPClient::Responder +class LLProductInfoRequestResponder : public LLHTTPClient::ResponderWithResult { public: //If we get back a normal response, handle it here diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index 885b1d65c..abc62a10e 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -41,7 +41,7 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy remoteParcelRequestResponder_timeout; -class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder +class LLRemoteParcelRequestResponder : public LLHTTPClient::ResponderWithResult { public: LLRemoteParcelRequestResponder(LLHandle place_panel_handle); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 6b925da27..95e43e71d 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -153,7 +153,7 @@ public: // void relese() { --mActiveCount; } S32 callbackHttpGet(const LLChannelDescriptors& channels, - const LLHTTPClient::Responder::buffer_ptr_t& buffer, + const LLHTTPClient::ResponderBase::buffer_ptr_t& buffer, bool partial, bool success); void callbackCacheRead(bool success, LLImageFormatted* image, S32 imagesize, BOOL islocal); @@ -292,7 +292,7 @@ private: }; ////////////////////////////////////////////////////////////////////////////// -class HTTPGetResponder : public AICurlInterface::ResponderWithCompleted +class HTTPGetResponder : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(HTTPGetResponder); public: @@ -1811,7 +1811,7 @@ bool LLTextureFetchWorker::processSimulatorPackets() ////////////////////////////////////////////////////////////////////////////// S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, - const LLHTTPClient::Responder::buffer_ptr_t& buffer, + const LLHTTPClient::ResponderBase::buffer_ptr_t& buffer, bool partial, bool success) { S32 data_size = 0 ; @@ -3016,7 +3016,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) * refactoring of the LLQueuedThread usage, these POSTs * could be put in a request object and made more reliable. */ - class lcl_responder : public LLCurl::Responder + class lcl_responder : public LLHTTPClient::ResponderWithResult { public: lcl_responder(LLTextureFetch * fetcher, diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 8b344ae0c..7540dd72c 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -43,7 +43,7 @@ extern AIHTTPTimeoutPolicy translationReceiver_timeout; class LLTranslate { public : - class TranslationReceiver: public LLHTTPClient::Responder + class TranslationReceiver: public LLHTTPClient::ResponderWithResult { protected: TranslationReceiver(const std::string &fromLang, const std::string &toLang) diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 5d4c67788..85cc7b86a 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -98,7 +98,7 @@ protected: }; -class LLUploadModelPremissionsResponder : public LLHTTPClient::Responder +class LLUploadModelPremissionsResponder : public LLHTTPClient::ResponderWithResult { public: diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 1d77bd5e0..26d2c122c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -111,7 +111,7 @@ public: bool mInitialized; }; -class LLViewerMediaOpenIDResponder : public AICurlInterface::ResponderWithCompleted +class LLViewerMediaOpenIDResponder : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(LLViewerMediaOpenIDResponder); public: @@ -150,7 +150,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaOpenIDResponder_timeout; } }; -class LLViewerMediaWebProfileResponder : public AICurlInterface::ResponderWithCompleted +class LLViewerMediaWebProfileResponder : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(LLViewerMediaWebProfileResponder); public: diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index ebdbfc02f..7e9cc32d0 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3350,7 +3350,7 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist // defined in llchatbar.cpp, but not declared in any header void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); -class AuthHandler : public AICurlInterface::ResponderWithCompleted +class AuthHandler : public LLHTTPClient::ResponderWithCompleted { protected: /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 5fd7b4aae..629e766d5 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -688,7 +688,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) LLVOAvatar::cullAvatarsByPixelArea(); } -class LLObjectCostResponder : public LLCurl::Responder +class LLObjectCostResponder : public LLHTTPClient::ResponderWithResult { public: LLObjectCostResponder(const LLSD& object_ids) @@ -778,7 +778,7 @@ private: LLSD mObjectIDs; }; -class LLPhysicsFlagsResponder : public LLCurl::Responder +class LLPhysicsFlagsResponder : public LLHTTPClient::ResponderWithResult { public: LLPhysicsFlagsResponder(const LLSD& object_ids) diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 93699d54b..7df9352f6 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -209,7 +209,7 @@ public: }; LLRegionHandler gRegionHandler; -class BaseCapabilitiesComplete : public LLHTTPClient::Responder +class BaseCapabilitiesComplete : public LLHTTPClient::ResponderWithResult { LOG_CLASS(BaseCapabilitiesComplete); public: @@ -1711,7 +1711,7 @@ void LLViewerRegion::failedSeedCapability() } } -class SimulatorFeaturesReceived : public LLHTTPClient::Responder +class SimulatorFeaturesReceived : public LLHTTPClient::ResponderWithResult { LOG_CLASS(SimulatorFeaturesReceived); public: diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index d451a0dc5..8a7c3d6e1 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -697,7 +697,7 @@ void update_statistics(U32 frame_count) } } -class ViewerStatsResponder : public LLHTTPClient::Responder +class ViewerStatsResponder : public LLHTTPClient::ResponderWithResult { public: ViewerStatsResponder() { } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index a3b432b15..55f4f656b 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -144,7 +144,7 @@ static int scale_speaker_volume(float volume) } class LLViewerVoiceAccountProvisionResponder : - public LLHTTPClient::Responder + public LLHTTPClient::ResponderWithResult { public: LLViewerVoiceAccountProvisionResponder(int retries) @@ -1014,7 +1014,7 @@ static bool sMuteListListener_listening = false; static LLVoiceClientFriendsObserver *friendslist_listener = NULL; /////////////////////////////////////////////////////////////////////////////////////////////// -class LLVoiceClientCapResponder : public LLHTTPClient::Responder +class LLVoiceClientCapResponder : public LLHTTPClient::ResponderWithResult { public: LLVoiceClientCapResponder(void){}; diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 95a2f6c62..af19c74b3 100644 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -52,7 +52,7 @@ private: static bool doRequest(); }; -class LLEnvironmentRequestResponder: public LLHTTPClient::Responder +class LLEnvironmentRequestResponder: public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLEnvironmentRequestResponder); public: @@ -80,7 +80,7 @@ private: static clock_t UPDATE_WAIT_SECONDS; }; -class LLEnvironmentApplyResponder: public LLHTTPClient::Responder +class LLEnvironmentApplyResponder: public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLEnvironmentApplyResponder); public: diff --git a/indra/newview/llxmlrpcresponder.cpp b/indra/newview/llxmlrpcresponder.cpp index a66b0a1f7..43997c60e 100644 --- a/indra/newview/llxmlrpcresponder.cpp +++ b/indra/newview/llxmlrpcresponder.cpp @@ -156,14 +156,14 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const return mV; } -void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) +void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, AITransferInfo* info) { if (info) { mTransferInfo = *info; } // Call base class implementation. - LegacyPolledResponder::completed_headers(status, reason, code, info); + LegacyPolledResponder::completed_headers(status, reason, info); } void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) diff --git a/indra/newview/llxmlrpcresponder.h b/indra/newview/llxmlrpcresponder.h index c52756f03..e42066f1c 100644 --- a/indra/newview/llxmlrpcresponder.h +++ b/indra/newview/llxmlrpcresponder.h @@ -91,9 +91,9 @@ private: XMLRPC_VALUE mV; }; -class XMLRPCResponder : public AICurlInterface::LegacyPolledResponder { +class XMLRPCResponder : public LLHTTPClient::LegacyPolledResponder { private: - AICurlInterface::TransferInfo mTransferInfo; + AITransferInfo mTransferInfo; S32 mBufferSize; bool mReceivedHTTPHeader; XMLRPC_REQUEST mResponse; @@ -105,8 +105,8 @@ public: XMLRPC_REQUEST response(void) const { return mResponse; } LLXMLRPCValue responseValue(void) const; - /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::ResponderBase::received_HTTP_header(); } - /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); + /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLHTTPClient::ResponderBase::received_HTTP_header(); } + /*virtual*/ void completed_headers(U32 status, std::string const& reason, AITransferInfo* info); /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return XMLRPCResponder_timeout; } }; From 756aac1f9ae00d75f58de97e1b1e717fb582fa65 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 1 Nov 2012 02:04:40 +0100 Subject: [PATCH 61/64] Remove AICurlInterface::strerror --- indra/llmessage/aicurl.cpp | 8 -------- indra/llmessage/aicurl.h | 5 ----- indra/llmessage/aicurlthread.cpp | 4 ++-- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 34b2211c4..dd2aed44c 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -422,17 +422,9 @@ void setCAPath(std::string const& path) CertificateAuthority_w->path = path; } -// THREAD-SAFE -std::string strerror(CURLcode errorcode) -{ - // libcurl is thread safe, no locking needed. - return curl_easy_strerror(errorcode); -} - } // namespace AICurlInterface //================================================================================== - //================================================================================== // Local implementation. // diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index 89642e602..dfd64a80c 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -145,11 +145,6 @@ void startCurlThread(U32 CurlConcurrentConnections, bool NoVerifySSLCert); // with purpose to stop curl threads, free curl resources and deinitialize curl. void cleanupCurl(void); -// Called from indra/llmessage/llurlrequest.cpp to print debug output regarding -// an error code returned by EasyRequest::getResult. -// Just returns curl_easy_strerror(errorcode). -std::string strerror(CURLcode errorcode); - // Called from indra/newview/llfloaterabout.cpp for the About floater, and // from newview/llappviewer.cpp in behalf of debug output. // Just returns curl_version(). diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index e36792d5b..f6335cc52 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -2089,8 +2089,8 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request } else { - responseCode = 499; - responseReason = AICurlInterface::strerror(code); + responseCode = HTTP_INTERNAL_ERROR; + responseReason = curl_easy_strerror(code); curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); } From 6c01b6da9b34a7425b0be9b7f0a80627892b5e7f Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 1 Nov 2012 02:40:08 +0100 Subject: [PATCH 62/64] Merging CurlEasyRequest and CurlResponderBuffer, Step 1 --- indra/llmessage/aicurl.cpp | 20 +++++++++---------- .../aicurleasyrequeststatemachine.cpp | 2 +- indra/llmessage/aicurlprivate.h | 10 +++++----- indra/llmessage/aicurlthread.cpp | 18 ++++++++--------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index dd2aed44c..54093e5a9 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -879,7 +879,7 @@ void CurlEasyRequest::resetState(void) mHeaders = NULL; mTimeoutPolicy = NULL; mTimeout = NULL; - mEventsTarget = NULL; + mHandleEventsTarget = NULL; mResult = CURLE_FAILED_INIT; applyDefaultOptions(); } @@ -1152,20 +1152,20 @@ void CurlEasyRequest::getResult(CURLcode* result, AITransferInfo* info) void CurlEasyRequest::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) { - if (mEventsTarget) - mEventsTarget->added_to_multi_handle(curl_easy_request_w); + if (mHandleEventsTarget) + mHandleEventsTarget->added_to_multi_handle(curl_easy_request_w); } void CurlEasyRequest::finished(AICurlEasyRequest_wat& curl_easy_request_w) { - if (mEventsTarget) - mEventsTarget->finished(curl_easy_request_w); + if (mHandleEventsTarget) + mHandleEventsTarget->finished(curl_easy_request_w); } void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) { - if (mEventsTarget) - mEventsTarget->removed_from_multi_handle(curl_easy_request_w); + if (mHandleEventsTarget) + mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w); } void CurlEasyRequest::print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code) @@ -1188,7 +1188,7 @@ static int const HTTP_REDIRECTS_DEFAULT = 10; LLChannelDescriptors const CurlResponderBuffer::sChannels; -CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mEventsTarget(NULL) +CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL) { ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); AICurlEasyRequest_wat curl_easy_request_w(*lockobj); @@ -1205,7 +1205,7 @@ CurlResponderBuffer::~CurlResponderBuffer() { ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); AICurlEasyRequest_wat curl_easy_request_w(*lockobj); // Wait 'til possible callbacks have returned. - send_events_to(NULL); + send_buffer_events_to(NULL); curl_easy_request_w->revokeCallbacks(); if (mResponder) { @@ -1280,7 +1280,7 @@ void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w // Send header events to responder if needed. if (mResponder->needsHeaders()) { - send_events_to(mResponder.get()); + send_buffer_events_to(mResponder.get()); } // Add extra headers. diff --git a/indra/llmessage/aicurleasyrequeststatemachine.cpp b/indra/llmessage/aicurleasyrequeststatemachine.cpp index c45e34335..910bbae1d 100644 --- a/indra/llmessage/aicurleasyrequeststatemachine.cpp +++ b/indra/llmessage/aicurleasyrequeststatemachine.cpp @@ -238,7 +238,7 @@ void AICurlEasyRequestStateMachine::finish_impl(void) if (mBuffered) { AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest); - buffered_easy_request_w->send_events_to(NULL); + buffered_easy_request_w->send_buffer_events_to(NULL); } curl_easy_request_w->send_events_to(NULL); curl_easy_request_w->revokeCallbacks(); diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index 11d47ce5d..5ccac0450 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -368,7 +368,7 @@ class CurlEasyRequest : public CurlEasyHandle { private: curl_slist* mHeaders; - AICurlEasyHandleEvents* mEventsTarget; + AICurlEasyHandleEvents* mHandleEventsTarget; CURLcode mResult; //AIFIXME: this does not belong in the request object, but belongs in the response object. AIHTTPTimeoutPolicy const* mTimeoutPolicy; @@ -396,7 +396,7 @@ class CurlEasyRequest : public CurlEasyHandle { // This class may only be created by constructing a ThreadSafeCurlEasyRequest. friend class ThreadSafeCurlEasyRequest; // Throws AICurlNoEasyHandle. - CurlEasyRequest(void) : mHeaders(NULL), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) + CurlEasyRequest(void) : mHeaders(NULL), mHandleEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) , mDebugIsHeadOrGetMethod(false) #endif @@ -406,7 +406,7 @@ class CurlEasyRequest : public CurlEasyHandle { public: // Post-initialization, set the parent to pass the events to. - void send_events_to(AICurlEasyHandleEvents* target) { mEventsTarget = target; } + void send_events_to(AICurlEasyHandleEvents* target) { mHandleEventsTarget = target; } // For debugging purposes bool is_finalized(void) const { return mTimeoutPolicy; } @@ -458,7 +458,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC //void setBodyLimit(U32 size) { mBodyLimit = size; } // Post-initialization, set the parent to pass the events to. - void send_events_to(AICurlResponderBufferEvents* target) { mEventsTarget = target; } + void send_buffer_events_to(AICurlResponderBufferEvents* target) { mBufferEventsTarget = target; } protected: // Events from this class. @@ -481,7 +481,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC std::string mReason; // The "reason" from the same header line. S32 mRequestTransferedBytes; S32 mResponseTransferedBytes; - AICurlResponderBufferEvents* mEventsTarget; + AICurlResponderBufferEvents* mBufferEventsTarget; public: static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()). diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index f6335cc52..6ffbc464e 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -2098,13 +2098,13 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request { curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); } - if (mEventsTarget) + if (mBufferEventsTarget) { // Only the responder registers for these events. - llassert(mEventsTarget == mResponder.get()); + llassert(mBufferEventsTarget == mResponder.get()); // Allow clients to parse result codes and headers before we attempt to parse // the body and provide completed/result/error calls. - mEventsTarget->completed_headers(responseCode, responseReason, (code == CURLE_FAILED_INIT) ? NULL : &info); + mBufferEventsTarget->completed_headers(responseCode, responseReason, (code == CURLE_FAILED_INIT) ? NULL : &info); } mResponder->finished(code, responseCode, responseReason, sChannels, mOutput); mResponder = NULL; @@ -2114,20 +2114,20 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request void CurlResponderBuffer::received_HTTP_header(void) { - if (mEventsTarget) - mEventsTarget->received_HTTP_header(); + if (mBufferEventsTarget) + mBufferEventsTarget->received_HTTP_header(); } void CurlResponderBuffer::received_header(std::string const& key, std::string const& value) { - if (mEventsTarget) - mEventsTarget->received_header(key, value); + if (mBufferEventsTarget) + mBufferEventsTarget->received_header(key, value); } void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason, AITransferInfo* info) { - if (mEventsTarget) - mEventsTarget->completed_headers(status, reason, info); + if (mBufferEventsTarget) + mBufferEventsTarget->completed_headers(status, reason, info); } //static From 1e1f5e8193316b84291c4b3c959bb60dcf9703c5 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 1 Nov 2012 03:18:00 +0100 Subject: [PATCH 63/64] Fix windows compile errors/warnings --- indra/llmessage/aicurlthread.cpp | 5 +++-- indra/llmessage/aihttptimeoutpolicy.cpp | 29 +++++++++++++------------ indra/llmessage/llurlrequest.h | 2 ++ indra/newview/llxmlrpcresponder.cpp | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 6ffbc464e..a0196b07a 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -41,6 +41,7 @@ #include #endif #include +#include // On linux, add -DDEBUG_WINDOWS_CODE_ON_LINUX to test the windows code used in this file. #if !defined(DEBUG_WINDOWS_CODE_ON_LINUX) || !defined(LL_LINUX) || defined(LL_RELEASE) @@ -1615,8 +1616,8 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons void MultiHandle::check_run_count(void) { - llassert(mAddedEasyRequests.size() >= mRunningHandles); - if (mAddedEasyRequests.size() - mRunningHandles > 0) // There is no need to do this when all easy handles are accounted for. + llassert(mAddedEasyRequests.size() >= (size_t)mRunningHandles); + if (mAddedEasyRequests.size() - (size_t)mRunningHandles > 0) // There is no need to do this when all easy handles are accounted for. { CURLMsg const* msg; int msgs_left; diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index a8099cea4..1add51a09 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -30,6 +30,7 @@ #include "sys.h" #include "aihttptimeoutpolicy.h" +#define NOMINMAX #include "llerror.h" #include "lldefs.h" #include "v3math.h" @@ -290,8 +291,8 @@ struct DNS : PolicyOp { DNS(int seconds) : mSeconds(seconds) { } DNS(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } static void fix(AIHTTPTimeoutPolicy* policy); - static int min(void) { return ABS_min_DNS_lookup; } - static int max(void) { return ABS_max_DNS_lookup; } + static U16 min(void) { return ABS_min_DNS_lookup; } + static U16 max(void) { return ABS_max_DNS_lookup; } virtual void perform(AIHTTPTimeoutPolicy* policy) const; }; @@ -300,8 +301,8 @@ struct Connect : PolicyOp { Connect(int seconds) : mSeconds(seconds) { } Connect(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } static void fix(AIHTTPTimeoutPolicy* policy); - static int min(void) { return ABS_min_connect_time; } - static int max(void) { return ABS_max_connect_time; } + static U16 min(void) { return ABS_min_connect_time; } + static U16 max(void) { return ABS_max_connect_time; } virtual void perform(AIHTTPTimeoutPolicy* policy) const; }; @@ -310,8 +311,8 @@ struct Reply : PolicyOp { Reply(int seconds) : mSeconds(seconds) { } Reply(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } static void fix(AIHTTPTimeoutPolicy* policy); - static int min(void) { return ABS_min_reply_delay; } - static int max(void) { return ABS_max_reply_delay; } + static U16 min(void) { return ABS_min_reply_delay; } + static U16 max(void) { return ABS_max_reply_delay; } virtual void perform(AIHTTPTimeoutPolicy* policy) const; }; @@ -321,10 +322,10 @@ struct Speed : PolicyOp { Speed(int seconds, int rate) : mSeconds(seconds), mRate(rate) { } Speed(int seconds, int rate, PolicyOp& op) : PolicyOp(op), mSeconds(seconds), mRate(rate) { } static void fix(AIHTTPTimeoutPolicy* policy); - static int min(void) { return ABS_min_low_speed_time; } - static int max(AIHTTPTimeoutPolicy const* policy) { return llmin(ABS_max_low_speed_time, (U16)(policy->mMaximumCurlTransaction / 2)); } - static int lmin(void) { return ABS_min_low_speed_limit; } - static int lmax(void) { return ABS_max_low_speed_limit; } + static U16 min(void) { return ABS_min_low_speed_time; } + static U16 max(AIHTTPTimeoutPolicy const* policy) { return llmin(ABS_max_low_speed_time, (U16)(policy->mMaximumCurlTransaction / 2)); } + static U32 lmin(void) { return ABS_min_low_speed_limit; } + static U32 lmax(void) { return ABS_max_low_speed_limit; } virtual void perform(AIHTTPTimeoutPolicy* policy) const; }; @@ -333,8 +334,8 @@ struct Transaction : PolicyOp { Transaction(int seconds) : mSeconds(seconds) { } Transaction(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } static void fix(AIHTTPTimeoutPolicy* policy); - static int min(AIHTTPTimeoutPolicy const* policy) { return llmax((int)ABS_min_transaction, policy->mMaximumConnectTime + policy->mMaximumReplyDelay + 4 * policy->mLowSpeedTime); } - static int max(void) { return ABS_max_transaction; } + static U16 min(AIHTTPTimeoutPolicy const* policy) { return llmax(ABS_min_transaction, (U16)(policy->mMaximumConnectTime + policy->mMaximumReplyDelay + 4 * policy->mLowSpeedTime)); } + static U16 max(void) { return ABS_max_transaction; } virtual void perform(AIHTTPTimeoutPolicy* policy) const; }; @@ -343,8 +344,8 @@ struct Total : PolicyOp { Total(int seconds) : mSeconds(seconds) { } Total(int seconds, PolicyOp& op) : PolicyOp(op), mSeconds(seconds) { } static void fix(AIHTTPTimeoutPolicy* policy); - static int min(AIHTTPTimeoutPolicy const* policy) { return llmax((int)ABS_min_total_delay, policy->mMaximumCurlTransaction + 1); } - static int max(void) { return ABS_max_total_delay; } + static U16 min(AIHTTPTimeoutPolicy const* policy) { return llmax(ABS_min_total_delay, (U16)(policy->mMaximumCurlTransaction + 1)); } + static U16 max(void) { return ABS_max_total_delay; } virtual void perform(AIHTTPTimeoutPolicy* policy) const; }; diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index ba046a2e0..8f019310f 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -45,6 +45,8 @@ class Injector typedef LLHTTPClient::ResponderBase::buffer_ptr_t buffer_ptr_t; virtual char const* contentType(void) const = 0; virtual U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) = 0; + // To avoid compiler warning. + virtual ~Injector() { } }; class LLURLRequest : public AICurlEasyRequestStateMachine { diff --git a/indra/newview/llxmlrpcresponder.cpp b/indra/newview/llxmlrpcresponder.cpp index 43997c60e..dac69a7f1 100644 --- a/indra/newview/llxmlrpcresponder.cpp +++ b/indra/newview/llxmlrpcresponder.cpp @@ -173,7 +173,7 @@ void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChan mBufferSize = buffer->count(channels.in()); if (200 <= status && status < 400) { - char* ptr; + char* ptr = NULL; char* buf = NULL; LLMutexLock lock(buffer->getMutex()); LLBufferArray::const_segment_iterator_t const end = buffer->endSegment(); From 72bde5234a4e5917e96459320fae87bcfda14bd4 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 2 Nov 2012 18:41:23 +0100 Subject: [PATCH 64/64] Rename CurlResponderBuffer to BufferedCurlEasyRequest and derive it from CurlEasyRequest Every curl transaction is a AICurlEasyRequestStateMachine which has a AICurlEasyRequest as member, which is a reference counting pointer to a ThreadSafeBufferedCurlEasyRequest. And now BufferedCurlEasyRequest is derived from CurlEasyRequest which is derived from CurlEasyHandle, but neither are used separatedly. --- indra/llmessage/aicurl.cpp | 84 ++++++------- indra/llmessage/aicurl.h | 69 +++++----- .../aicurleasyrequeststatemachine.cpp | 35 ++---- .../llmessage/aicurleasyrequeststatemachine.h | 3 +- indra/llmessage/aicurlprivate.h | 119 +++++++----------- indra/llmessage/aicurlthread.cpp | 112 +++++++---------- indra/llmessage/llhttpclient.h | 9 -- indra/llmessage/llurlrequest.cpp | 11 +- 8 files changed, 170 insertions(+), 272 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 54093e5a9..06e13e0f0 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -610,12 +610,12 @@ CURLMcode CurlEasyHandle::remove_handle_from_multi(AICurlEasyRequest_wat& curl_e return res; } -void intrusive_ptr_add_ref(ThreadSafeCurlEasyRequest* threadsafe_curl_easy_request) +void intrusive_ptr_add_ref(ThreadSafeBufferedCurlEasyRequest* threadsafe_curl_easy_request) { threadsafe_curl_easy_request->mReferenceCount++; } -void intrusive_ptr_release(ThreadSafeCurlEasyRequest* threadsafe_curl_easy_request) +void intrusive_ptr_release(ThreadSafeBufferedCurlEasyRequest* threadsafe_curl_easy_request) { if (--threadsafe_curl_easy_request->mReferenceCount == 0) { @@ -731,21 +731,11 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data) setopt(CURLOPT_POSTFIELDS, data); // Implies CURLOPT_POST } -ThreadSafeCurlEasyRequest* CurlEasyRequest::get_lockobj(void) -{ - return static_cast(AIThreadSafeSimpleDC::wrapper_cast(this)); -} - -ThreadSafeCurlEasyRequest const* CurlEasyRequest::get_lockobj(void) const -{ - return static_cast(AIThreadSafeSimpleDC::wrapper_cast(this)); -} - //static size_t CurlEasyRequest::headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { CurlEasyRequest* self = static_cast(userdata); - ThreadSafeCurlEasyRequest* lockobj = self->get_lockobj(); + ThreadSafeBufferedCurlEasyRequest* lockobj = self->get_lockobj(); AICurlEasyRequest_wat lock_self(*lockobj); return self->mHeaderCallback(ptr, size, nmemb, self->mHeaderCallbackUserData); } @@ -762,7 +752,7 @@ void CurlEasyRequest::setHeaderCallback(curl_write_callback callback, void* user size_t CurlEasyRequest::writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { CurlEasyRequest* self = static_cast(userdata); - ThreadSafeCurlEasyRequest* lockobj = self->get_lockobj(); + ThreadSafeBufferedCurlEasyRequest* lockobj = self->get_lockobj(); AICurlEasyRequest_wat lock_self(*lockobj); return self->mWriteCallback(ptr, size, nmemb, self->mWriteCallbackUserData); } @@ -779,7 +769,7 @@ void CurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userd size_t CurlEasyRequest::readCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { CurlEasyRequest* self = static_cast(userdata); - ThreadSafeCurlEasyRequest* lockobj = self->get_lockobj(); + ThreadSafeBufferedCurlEasyRequest* lockobj = self->get_lockobj(); AICurlEasyRequest_wat lock_self(*lockobj); return self->mReadCallback(ptr, size, nmemb, self->mReadCallbackUserData); } @@ -796,7 +786,7 @@ void CurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdat CURLcode CurlEasyRequest::SSLCtxCallback(CURL* curl, void* sslctx, void* userdata) { CurlEasyRequest* self = static_cast(userdata); - ThreadSafeCurlEasyRequest* lockobj = self->get_lockobj(); + ThreadSafeBufferedCurlEasyRequest* lockobj = self->get_lockobj(); AICurlEasyRequest_wat lock_self(*lockobj); return self->mSSLCtxCallback(curl, sslctx, self->mSSLCtxCallbackUserData); } @@ -864,7 +854,7 @@ CurlEasyRequest::~CurlEasyRequest() // If the CurlEasyRequest object is destructed then we need to revoke all callbacks, because // we can't set the lock anymore, and neither will mHeaderCallback, mWriteCallback etc, // be available anymore. - send_events_to(NULL); + send_handle_events_to(NULL); revokeCallbacks(); // This wasn't freed yet if the request never finished. curl_slist_free_all(mHeaders); @@ -1094,12 +1084,12 @@ void CurlEasyRequest::set_timeout_opts(void) setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); } -void CurlEasyRequest::create_timeout_object(ThreadSafeCurlEasyRequest* lockobj) +void CurlEasyRequest::create_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj) { mTimeout = new curlthread::HTTPTimeout(mTimeoutPolicy, lockobj); } -LLPointer& CurlEasyRequest::get_timeout_object(ThreadSafeCurlEasyRequest* lockobj) +LLPointer& CurlEasyRequest::get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj) { if (mTimeoutIsOrphan) { @@ -1168,7 +1158,7 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w); } -void CurlEasyRequest::print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code) +void CurlEasyRequest::print_diagnostics(CURLcode code) { if (code == CURLE_OPERATION_TIMEDOUT) { @@ -1176,48 +1166,39 @@ void CurlEasyRequest::print_diagnostics(AICurlEasyRequest_wat const& curlEasyReq // this is far from the code that guaranteeds that it is set. if (mTimeout) { - mTimeout->print_diagnostics(curlEasyRequest_w); + mTimeout->print_diagnostics(this); } } } //----------------------------------------------------------------------------- -// CurlResponderBuffer +// BufferedCurlEasyRequest static int const HTTP_REDIRECTS_DEFAULT = 10; -LLChannelDescriptors const CurlResponderBuffer::sChannels; +LLChannelDescriptors const BufferedCurlEasyRequest::sChannels; -CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL) +BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL) { - ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); - AICurlEasyRequest_wat curl_easy_request_w(*lockobj); - curl_easy_request_w->send_events_to(this); } #define llmaybeerrs lllog(LLApp::isRunning() ? LLError::LEVEL_ERROR : LLError::LEVEL_WARN, NULL, NULL, false, true) -// The callbacks need to be revoked when the CurlResponderBuffer is destructed (because that is what the callbacks use). -// The AIThreadSafeSimple is destructed first (right to left), so when we get here then the -// ThreadSafeCurlEasyRequest base class of ThreadSafeBufferedCurlEasyRequest is still intact and we can create -// and use curl_easy_request_w. -CurlResponderBuffer::~CurlResponderBuffer() +BufferedCurlEasyRequest::~BufferedCurlEasyRequest() { - ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); - AICurlEasyRequest_wat curl_easy_request_w(*lockobj); // Wait 'til possible callbacks have returned. send_buffer_events_to(NULL); - curl_easy_request_w->revokeCallbacks(); + revokeCallbacks(); if (mResponder) { - // If the responder is still alive, then that means that CurlResponderBuffer::processOutput was + // If the responder is still alive, then that means that BufferedCurlEasyRequest::processOutput was // never called, which means that the removed_from_multi_handle event never happened. // This is definitely an internal error as it can only happen when libcurl is too slow, // in which case AICurlEasyRequestStateMachine::mTimer times out, but that already - // calls CurlResponderBuffer::timed_out(). - llmaybeerrs << "Calling ~CurlResponderBuffer() with active responder!" << llendl; + // calls BufferedCurlEasyRequest::timed_out(). + llmaybeerrs << "Calling ~BufferedCurlEasyRequest() with active responder!" << llendl; if (!LLApp::isRunning()) { - // It might happen if some CurlResponderBuffer escaped clean up somehow :/ + // It might happen if some BufferedCurlEasyRequest escaped clean up somehow :/ mResponder = NULL; } else @@ -1228,33 +1209,38 @@ CurlResponderBuffer::~CurlResponderBuffer() } } -void CurlResponderBuffer::timed_out(void) +void BufferedCurlEasyRequest::timed_out(void) { - mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); - mResponder = NULL; + mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); + if (mResponder->needsHeaders()) + { + send_buffer_events_to(NULL); // Revoke buffer events: we sent them to the responder. + } + mResponder = NULL; } -void CurlResponderBuffer::resetState(AICurlEasyRequest_wat& curl_easy_request_w) +void BufferedCurlEasyRequest::resetState(void) { llassert(!mResponder); - curl_easy_request_w->resetState(); + // Call base class implementation. + CurlEasyRequest::resetState(); mOutput.reset(); mInput.reset(); } -ThreadSafeBufferedCurlEasyRequest* CurlResponderBuffer::get_lockobj(void) +ThreadSafeBufferedCurlEasyRequest* BufferedCurlEasyRequest::get_lockobj(void) { - return static_cast(AIThreadSafeSimple::wrapper_cast(this)); + return static_cast(AIThreadSafeSimple::wrapper_cast(this)); } -ThreadSafeBufferedCurlEasyRequest const* CurlResponderBuffer::get_lockobj(void) const +ThreadSafeBufferedCurlEasyRequest const* BufferedCurlEasyRequest::get_lockobj(void) const { - return static_cast(AIThreadSafeSimple::wrapper_cast(this)); + return static_cast(AIThreadSafeSimple::wrapper_cast(this)); } -void CurlResponderBuffer::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder) +void BufferedCurlEasyRequest::prepRequest(AICurlEasyRequest_wat& curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder) { mInput.reset(new LLBufferArray); mInput->setThreaded(true); diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index dfd64a80c..4424e4299 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -162,7 +162,7 @@ void setCAPath(std::string const& file); // Forward declaration (see aicurlprivate.h). namespace AICurlPrivate { - class CurlEasyRequest; + class BufferedCurlEasyRequest; } // namespace AICurlPrivate // Define access types (_crat = Const Read Access Type, _rat = Read Access Type, _wat = Write Access Type). @@ -170,13 +170,13 @@ namespace AICurlPrivate { // AICurlEasyRequest h1; // Create easy handle. // AICurlEasyRequest h2(h1); // Make lightweight copies. // AICurlEasyRequest_wat h2_w(*h2); // Lock and obtain write access to the easy handle. -// Use *h2_w, which is a reference to the locked CurlEasyRequest instance. +// Use *h2_w, which is a reference to the locked BufferedCurlEasyRequest instance. // Note: As it is not allowed to use curl easy handles in any way concurrently, // read access would at most give access to a CURL const*, which will turn out // to be completely useless; therefore it is sufficient and efficient to use // an AIThreadSafeSimple and it's unlikely that AICurlEasyRequest_rat will be used. -typedef AIAccessConst AICurlEasyRequest_rat; -typedef AIAccess AICurlEasyRequest_wat; +typedef AIAccessConst AICurlEasyRequest_rat; +typedef AIAccess AICurlEasyRequest_wat; // Events generated by AICurlPrivate::CurlEasyHandle. struct AICurlEasyHandleEvents { @@ -205,38 +205,38 @@ typedef LLPointer AIPostFieldPtr; #include "aicurlprivate.h" -// AICurlPrivate::CurlEasyRequestPtr, a boost::intrusive_ptr, is no more threadsafe than a +// AICurlPrivate::BufferedCurlEasyRequestPtr, a boost::intrusive_ptr, is no more threadsafe than a // builtin type, but wrapping it in AIThreadSafe is obviously not going to help here. -// Therefore we use the following trick: we wrap CurlEasyRequestPtr too, and only allow +// Therefore we use the following trick: we wrap BufferedCurlEasyRequestPtr too, and only allow // read accesses on it. -// AICurlEasyRequest: a thread safe, reference counting, auto-cleaning curl easy handle. +// AICurlEasyRequest: a thread safe, reference counting, buffered, auto-cleaning curl easy handle. class AICurlEasyRequest { private: // Use AICurlEasyRequestStateMachine, not AICurlEasyRequest. friend class AICurlEasyRequestStateMachine; // Initial construction is allowed (thread-safe). - // Note: If ThreadSafeCurlEasyRequest() throws then the memory allocated is still freed. - // 'new' never returned however and neither the constructor nor destructor of mCurlEasyRequest is called in this case. + // Note: If ThreadSafeBufferedCurlEasyRequest() throws then the memory allocated is still freed. + // 'new' never returned however and neither the constructor nor destructor of mBufferedCurlEasyRequest is called in this case. // This might throw AICurlNoEasyHandle. - AICurlEasyRequest(bool buffered) : - mCurlEasyRequest(buffered ? new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest : new AICurlPrivate::ThreadSafeCurlEasyRequest) { } + AICurlEasyRequest(void) : + mBufferedCurlEasyRequest(new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest) { } public: // Used for storing this object in a standard container (see MultiHandle::add_easy_request). - AICurlEasyRequest(AICurlEasyRequest const& orig) : mCurlEasyRequest(orig.mCurlEasyRequest) { } + AICurlEasyRequest(AICurlEasyRequest const& orig) : mBufferedCurlEasyRequest(orig.mBufferedCurlEasyRequest) { } // For the rest, only allow read operations. - AIThreadSafeSimple& operator*(void) const { llassert(mCurlEasyRequest.get()); return *mCurlEasyRequest; } - AIThreadSafeSimple* operator->(void) const { llassert(mCurlEasyRequest.get()); return mCurlEasyRequest.get(); } - AIThreadSafeSimple* get(void) const { return mCurlEasyRequest.get(); } + AIThreadSafeSimple& operator*(void) const { llassert(mBufferedCurlEasyRequest.get()); return *mBufferedCurlEasyRequest; } + AIThreadSafeSimple* operator->(void) const { llassert(mBufferedCurlEasyRequest.get()); return mBufferedCurlEasyRequest.get(); } + AIThreadSafeSimple* get(void) const { return mBufferedCurlEasyRequest.get(); } - // Returns true if this object points to the same CurlEasyRequest object. - bool operator==(AICurlEasyRequest const& cer) const { return mCurlEasyRequest == cer.mCurlEasyRequest; } + // Returns true if this object points to the same BufferedCurlEasyRequest object. + bool operator==(AICurlEasyRequest const& cer) const { return mBufferedCurlEasyRequest == cer.mBufferedCurlEasyRequest; } - // Returns true if this object points to a different CurlEasyRequest object. - bool operator!=(AICurlEasyRequest const& cer) const { return mCurlEasyRequest != cer.mCurlEasyRequest; } + // Returns true if this object points to a different BufferedCurlEasyRequest object. + bool operator!=(AICurlEasyRequest const& cer) const { return mBufferedCurlEasyRequest != cer.mBufferedCurlEasyRequest; } // Queue this request for insertion in the multi session. void addRequest(void); @@ -244,12 +244,9 @@ class AICurlEasyRequest { // Queue a command to remove this request from the multi session (or cancel a queued command to add it). void removeRequest(void); - // Returns true when this AICurlEasyRequest wraps a AICurlPrivate::ThreadSafeBufferedCurlEasyRequest. - bool isBuffered(void) const { return mCurlEasyRequest->isBuffered(); } - private: - // The actual pointer to the ThreadSafeCurlEasyRequest instance. - AICurlPrivate::CurlEasyRequestPtr mCurlEasyRequest; + // The actual pointer to the ThreadSafeBufferedCurlEasyRequest instance. + AICurlPrivate::BufferedCurlEasyRequestPtr mBufferedCurlEasyRequest; private: // Assignment would not be thread-safe; we may create this object and read from it. @@ -259,7 +256,7 @@ class AICurlEasyRequest { public: // Instead of assignment, it might be helpful to use swap. - void swap(AICurlEasyRequest& cer) { mCurlEasyRequest.swap(cer.mCurlEasyRequest); } + void swap(AICurlEasyRequest& cer) { mBufferedCurlEasyRequest.swap(cer.mBufferedCurlEasyRequest); } public: // The more exotic member functions of this class, to deal with passing this class @@ -267,26 +264,18 @@ class AICurlEasyRequest { // For "internal use" only; don't use things from AICurlPrivate yourself. // It's thread-safe to give read access the underlaying boost::intrusive_ptr. - // It's not OK to then call get() on that and store the AICurlPrivate::ThreadSafeCurlEasyRequest* separately. - AICurlPrivate::CurlEasyRequestPtr const& get_ptr(void) const { return mCurlEasyRequest; } + // It's not OK to then call get() on that and store the AICurlPrivate::ThreadSafeBufferedCurlEasyRequest* separately. + AICurlPrivate::BufferedCurlEasyRequestPtr const& get_ptr(void) const { return mBufferedCurlEasyRequest; } - // If we have a correct (with regard to reference counting) AICurlPrivate::CurlEasyRequestPtr, + // If we have a correct (with regard to reference counting) AICurlPrivate::BufferedCurlEasyRequestPtr, // then it's OK to construct a AICurlEasyRequest from it. - // Note that the external AICurlPrivate::CurlEasyRequestPtr needs its own locking, because + // Note that the external AICurlPrivate::BufferedCurlEasyRequestPtr needs its own locking, because // it's not thread-safe in itself. - AICurlEasyRequest(AICurlPrivate::CurlEasyRequestPtr const& ptr) : mCurlEasyRequest(ptr) { } + AICurlEasyRequest(AICurlPrivate::BufferedCurlEasyRequestPtr const& ptr) : mBufferedCurlEasyRequest(ptr) { } // This one is obviously dangerous. It's for use only in MultiHandle::check_run_count. - // See also the long comment in CurlEasyRequest::finalizeRequest with regard to CURLOPT_PRIVATE. - explicit AICurlEasyRequest(AICurlPrivate::ThreadSafeCurlEasyRequest* ptr) : mCurlEasyRequest(ptr) { } -}; - -// Write Access Type for the buffer. -struct AICurlResponderBuffer_wat : public AIAccess { - explicit AICurlResponderBuffer_wat(AICurlPrivate::ThreadSafeBufferedCurlEasyRequest& lockobj) : - AIAccess(lockobj) { } - AICurlResponderBuffer_wat(AIThreadSafeSimple& lockobj) : - AIAccess(static_cast(lockobj)) { } + // See also the long comment in BufferedCurlEasyRequest::finalizeRequest with regard to CURLOPT_PRIVATE. + explicit AICurlEasyRequest(AICurlPrivate::ThreadSafeBufferedCurlEasyRequest* ptr) : mBufferedCurlEasyRequest(ptr) { } }; #define AICurlPrivate DONTUSE_AICurlPrivate diff --git a/indra/llmessage/aicurleasyrequeststatemachine.cpp b/indra/llmessage/aicurleasyrequeststatemachine.cpp index 910bbae1d..a5c9f9d44 100644 --- a/indra/llmessage/aicurleasyrequeststatemachine.cpp +++ b/indra/llmessage/aicurleasyrequeststatemachine.cpp @@ -63,7 +63,7 @@ void AICurlEasyRequestStateMachine::initialize_impl(void) { AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); llassert(curlEasyRequest_w->is_finalized()); // Call finalizeRequest() before calling run(). - curlEasyRequest_w->send_events_to(this); + curlEasyRequest_w->send_handle_events_to(this); } mAdded = false; mTimedOut = false; @@ -90,7 +90,7 @@ void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_ { llassert(mFinished || mTimedOut); // If we neither finished nor timed out, then why is this being removed? // Note that allowing this would cause an assertion later on for removing - // a CurlResponderBuffer with a still active Responder. + // a BufferedCurlEasyRequest with a still active Responder. set_state(mFinished ? AICurlEasyRequestStateMachine_removed_after_finished : AICurlEasyRequestStateMachine_removed); } @@ -175,12 +175,8 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void) } // The request finished and either data or an error code is available. - if (mBuffered) - { - AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); - AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest); - buffered_easy_request_w->processOutput(easy_request_w); - } + AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); + easy_request_w->processOutput(); } if (current_state == AICurlEasyRequestStateMachine_finished) @@ -196,11 +192,10 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void) case AICurlEasyRequestStateMachine_removed: { // The request was removed from the multi handle. - if (mBuffered && mTimedOut) + if (mTimedOut) { AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); - AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest); - buffered_easy_request_w->timed_out(); + easy_request_w->timed_out(); } // We're done. If we timed out, abort -- or else the application will @@ -235,12 +230,8 @@ void AICurlEasyRequestStateMachine::finish_impl(void) // Revoke callbacks. { AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest); - if (mBuffered) - { - AICurlResponderBuffer_wat buffered_easy_request_w(*mCurlEasyRequest); - buffered_easy_request_w->send_buffer_events_to(NULL); - } - curl_easy_request_w->send_events_to(NULL); + curl_easy_request_w->send_buffer_events_to(NULL); + curl_easy_request_w->send_handle_events_to(NULL); curl_easy_request_w->revokeCallbacks(); } if (mTimer) @@ -254,14 +245,10 @@ void AICurlEasyRequestStateMachine::finish_impl(void) kill(); } -AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : - mBuffered(buffered), mCurlEasyRequest(buffered), mTimer(NULL), mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay()) +AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(void) : + mTimer(NULL), mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay()) { - Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); - if (!mBuffered) - { - llwarns << "Using unbuffered AICurlEasyRequestStateMachine" << llendl; - } + Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); } void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout) diff --git a/indra/llmessage/aicurleasyrequeststatemachine.h b/indra/llmessage/aicurleasyrequeststatemachine.h index 3878a597e..8ece6fc26 100644 --- a/indra/llmessage/aicurleasyrequeststatemachine.h +++ b/indra/llmessage/aicurleasyrequeststatemachine.h @@ -52,13 +52,12 @@ // Construction of a AICurlEasyRequestStateMachine might throw AICurlNoEasyHandle. class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHandleEvents { public: - AICurlEasyRequestStateMachine(bool buffered); + AICurlEasyRequestStateMachine(void); // Transparent access. AICurlEasyRequest mCurlEasyRequest; private: - bool mBuffered; // Argument used for construction of mCurlEasyRequest. bool mAdded; // Set when the last command to the curl thread was to add the request. bool mTimedOut; // Set if the expiration timer timed out. bool mFinished; // Set by the curl thread to signal it finished. diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index 5ccac0450..9fb62ca15 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -41,7 +41,8 @@ class AICurlEasyRequestStateMachine; namespace AICurlPrivate { -class ThreadSafeCurlEasyRequest; +class CurlEasyRequest; +class ThreadSafeBufferedCurlEasyRequest; namespace curlthread { @@ -64,11 +65,11 @@ class HTTPTimeout : public LLRefCount { static F64 const sClockWidth; // Time between two clock ticks in seconds. static U64 sClockCount; // Clock count used as 'now' during one loop of the main loop. #if defined(CWDEBUG) || defined(DEBUG_CURLIO) - ThreadSafeCurlEasyRequest* mLockObj; + ThreadSafeBufferedCurlEasyRequest* mLockObj; #endif public: - HTTPTimeout(AIHTTPTimeoutPolicy const* policy, ThreadSafeCurlEasyRequest* lock_obj) : + HTTPTimeout(AIHTTPTimeoutPolicy const* policy, ThreadSafeBufferedCurlEasyRequest* lock_obj) : mPolicy(policy), mNothingReceivedYet(true), mLowSpeedOn(false), mUploadFinished(false), mStalled((U64)-1) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) , mLockObj(lock_obj) @@ -94,7 +95,7 @@ class HTTPTimeout : public LLRefCount { bool has_stalled(void) const { return mStalled < sClockCount; } // Called from CurlResponderBuffer::processOutput if a timeout occurred. - void print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w); + void print_diagnostics(CurlEasyRequest const* curl_easy_request); #if defined(CWDEBUG) || defined(DEBUG_CURLIO) void* get_lockobj(void) const { return mLockObj; } @@ -129,9 +130,6 @@ bool curlThreadIsRunning(void); void wakeUpCurlThread(void); void stopCurlThread(void); -class ThreadSafeCurlEasyRequest; -class ThreadSafeBufferedCurlEasyRequest; - #define DECLARE_SETOPT(param_type) \ CURLcode setopt(CURLoption option, param_type parameter) @@ -275,9 +273,9 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven // the data exchange. Use getResult() to determine if an error occurred. // // Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest: -// a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest, +// a CurlEasyRequest is only ever created as base class of a ThreadSafeBufferedCurlEasyRequest, // which is only created by creating a AICurlEasyRequest. When the last copy of such -// AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted +// AICurlEasyRequest is deleted, then also the ThreadSafeBufferedCurlEasyRequest is deleted // and the CurlEasyRequest destructed. class CurlEasyRequest : public CurlEasyHandle { private: @@ -315,7 +313,9 @@ class CurlEasyRequest : public CurlEasyHandle { // Call this if the set callbacks are about to be invalidated. void revokeCallbacks(void); + protected: // Reset everything to the state it was in when this object was just created. + // Called by BufferedCurlEasyRequest::resetState. void resetState(void); private: @@ -326,7 +326,7 @@ class CurlEasyRequest : public CurlEasyHandle { static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); // Called from get_timeout_object and httptimeout. - void create_timeout_object(ThreadSafeCurlEasyRequest* lockobj); + void create_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj); public: // Set default options that we want applied to all curl easy handles. @@ -355,7 +355,7 @@ class CurlEasyRequest : public CurlEasyHandle { } // Called by in case of an error. - void print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode code); + void print_diagnostics(CURLcode code); // Called by MultiHandle::check_run_count() to fill info with the transfer info. void getTransferInfo(AITransferInfo* info); @@ -386,15 +386,14 @@ class CurlEasyRequest : public CurlEasyHandle { std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; } // Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request. // This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan). - LLPointer& get_timeout_object(ThreadSafeCurlEasyRequest* lockobj); + LLPointer& get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj); // Accessor for mTimeout with optional creation of orphaned object (if lockobj != NULL). - LLPointer& httptimeout(ThreadSafeCurlEasyRequest* lockobj = NULL) { if (lockobj && !mTimeout) create_timeout_object(lockobj); return mTimeout; } + LLPointer& httptimeout(ThreadSafeBufferedCurlEasyRequest* lockobj = NULL) { if (lockobj && !mTimeout) create_timeout_object(lockobj); return mTimeout; } // Return true if no data has been received on the latest socket (if any) for too long. bool has_stalled(void) const { return mTimeout && mTimeout->has_stalled(); } - private: - // This class may only be created by constructing a ThreadSafeCurlEasyRequest. - friend class ThreadSafeCurlEasyRequest; + protected: + // This class may only be created as base class of BufferedCurlEasyRequest. // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : mHeaders(NULL), mHandleEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) @@ -406,14 +405,14 @@ class CurlEasyRequest : public CurlEasyHandle { public: // Post-initialization, set the parent to pass the events to. - void send_events_to(AICurlEasyHandleEvents* target) { mHandleEventsTarget = target; } + void send_handle_events_to(AICurlEasyHandleEvents* target) { mHandleEventsTarget = target; } // For debugging purposes bool is_finalized(void) const { return mTimeoutPolicy; } // Return pointer to the ThreadSafe (wrapped) version of this object. - ThreadSafeCurlEasyRequest* get_lockobj(void); - ThreadSafeCurlEasyRequest const* get_lockobj(void) const; + inline ThreadSafeBufferedCurlEasyRequest* get_lockobj(void); + inline ThreadSafeBufferedCurlEasyRequest const* get_lockobj(void) const; protected: // Pass events to parent. @@ -422,27 +421,14 @@ class CurlEasyRequest : public CurlEasyHandle { /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); }; -// Buffers used by the AICurlInterface::Request API. -// Curl callbacks write into and read from these buffers. -// The interface with the rest of the code is through -// AICurlInterface::ResponderBase and derived classes. -// -// The lifetime of a CurlResponderBuffer is slightly shorter than its -// associated CurlEasyRequest; this class can only be created as base class -// of ThreadSafeBufferedCurlEasyRequest, and is therefore constructed after -// the construction of the associated CurlEasyRequest and destructed before it. -// Hence, it's safe to use get_lockobj() and through that access the CurlEasyRequest -// object at all times. -// -// A CurlResponderBuffer is thus created when a ThreadSafeBufferedCurlEasyRequest -// is created which only happens by creating a AICurlEasyRequest(true) instance, -// and when the last AICurlEasyRequest is deleted, then the ThreadSafeBufferedCurlEasyRequest -// is deleted and the CurlResponderBuffer destructed. -class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AICurlEasyHandleEvents { +// This class adds input/output buffers to the request and hooks up the libcurl callbacks to use those buffers. +// Received data is partially decoded and made available through various member functions. +class BufferedCurlEasyRequest : public CurlEasyRequest { public: + // The type of the used buffers. typedef boost::shared_ptr buffer_ptr_t; - void resetState(AICurlEasyRequest_wat& curl_easy_request_w); + void resetState(void); void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, AIHTTPHeaders const& headers, LLHTTPClient::ResponderPtr responder); buffer_ptr_t& getInput(void) { return mInput; } @@ -452,7 +438,7 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC void timed_out(void); // Called after removed_from_multi_handle was called. - void processOutput(AICurlEasyRequest_wat& curl_easy_request_w); + void processOutput(void); // Do not write more than this amount. //void setBodyLimit(U32 size) { mBodyLimit = size; } @@ -466,11 +452,6 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC /*virtual*/ void received_header(std::string const& key, std::string const& value); /*virtual*/ void completed_headers(U32 status, std::string const& reason, AITransferInfo* info); - // CurlEasyHandle events. - /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); - /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); - /*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); - private: buffer_ptr_t mInput; U8* mLastRead; // Pointer into mInput where we last stopped reading (or NULL to start at the beginning). @@ -489,9 +470,9 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC private: // This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest. friend class ThreadSafeBufferedCurlEasyRequest; - CurlResponderBuffer(void); + BufferedCurlEasyRequest(void); public: - ~CurlResponderBuffer(); + ~BufferedCurlEasyRequest(); private: static size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data); @@ -511,46 +492,38 @@ class CurlResponderBuffer : protected AICurlResponderBufferEvents, protected AIC bool isValid(void) const { return mResponder; } }; -// This class wraps CurlEasyRequest for thread-safety and adds a reference counter so we can +inline ThreadSafeBufferedCurlEasyRequest* CurlEasyRequest::get_lockobj(void) +{ + return static_cast(this)->get_lockobj(); +} + +inline ThreadSafeBufferedCurlEasyRequest const* CurlEasyRequest::get_lockobj(void) const +{ + return static_cast(this)->get_lockobj(); +} + +// This class wraps BufferedCurlEasyRequest for thread-safety and adds a reference counter so we can // copy it around cheaply and it gets destructed automatically when the last instance is deleted. // It guarantees that the CURL* handle is never used concurrently, which is not allowed by libcurl. // As AIThreadSafeSimpleDC contains a mutex, it cannot be copied. Therefore we need a reference counter for this object. -class ThreadSafeCurlEasyRequest : public AIThreadSafeSimple { +class ThreadSafeBufferedCurlEasyRequest : public AIThreadSafeSimple { public: // Throws AICurlNoEasyHandle. - ThreadSafeCurlEasyRequest(void) : mReferenceCount(0) - { new (ptr()) CurlEasyRequest; - Dout(dc::curl, "Creating ThreadSafeCurlEasyRequest with this = " << (void*)this); } - virtual ~ThreadSafeCurlEasyRequest() - { Dout(dc::curl, "Destructing ThreadSafeCurlEasyRequest with this = " << (void*)this); } - - // Returns true if this is a base class of ThreadSafeBufferedCurlEasyRequest. - virtual bool isBuffered(void) const { return false; } + ThreadSafeBufferedCurlEasyRequest(void) : mReferenceCount(0) + { new (ptr()) BufferedCurlEasyRequest; + Dout(dc::curl, "Creating ThreadSafeBufferedCurlEasyRequest with this = " << (void*)this); } + virtual ~ThreadSafeBufferedCurlEasyRequest() + { Dout(dc::curl, "Destructing ThreadSafeBufferedCurlEasyRequest with this = " << (void*)this); } private: LLAtomicU32 mReferenceCount; - friend void intrusive_ptr_add_ref(ThreadSafeCurlEasyRequest* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. - friend void intrusive_ptr_release(ThreadSafeCurlEasyRequest* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. -}; - -// Same as the above but adds a CurlResponderBuffer. The latter has its own locking in order to -// allow casting the underlying CurlEasyRequest to ThreadSafeCurlEasyRequest, independent of -// what class it is part of: ThreadSafeCurlEasyRequest or ThreadSafeBufferedCurlEasyRequest. -// The virtual destructor of ThreadSafeCurlEasyRequest allows to treat each easy handle transparently -// as a ThreadSafeCurlEasyRequest object, or optionally dynamic_cast it to a ThreadSafeBufferedCurlEasyRequest. -// Note: the order of these base classes is important: AIThreadSafeSimple is now -// destructed before ThreadSafeCurlEasyRequest is. -class ThreadSafeBufferedCurlEasyRequest : public ThreadSafeCurlEasyRequest, public AIThreadSafeSimple { - public: - // Throws AICurlNoEasyHandle. - ThreadSafeBufferedCurlEasyRequest(void) { new (AIThreadSafeSimple::ptr()) CurlResponderBuffer; } - - /*virtual*/ bool isBuffered(void) const { return true; } + friend void intrusive_ptr_add_ref(ThreadSafeBufferedCurlEasyRequest* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. + friend void intrusive_ptr_release(ThreadSafeBufferedCurlEasyRequest* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. }; // The curl easy request type wrapped in a reference counting pointer. -typedef boost::intrusive_ptr CurlEasyRequestPtr; +typedef boost::intrusive_ptr BufferedCurlEasyRequestPtr; // This class wraps CURLM*'s. // It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl. diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index a0196b07a..91744ce23 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -215,14 +215,14 @@ class Command { Command(AICurlEasyRequest const& easy_request, command_st command) : mCurlEasyRequest(easy_request.get_ptr()), mCommand(command) { } command_st command(void) const { return mCommand; } - CurlEasyRequestPtr const& easy_request(void) const { return mCurlEasyRequest; } + BufferedCurlEasyRequestPtr const& easy_request(void) const { return mCurlEasyRequest; } bool operator==(AICurlEasyRequest const& easy_request) const { return mCurlEasyRequest == easy_request.get_ptr(); } void reset(void); private: - CurlEasyRequestPtr mCurlEasyRequest; + BufferedCurlEasyRequestPtr mCurlEasyRequest; command_st mCommand; }; @@ -237,11 +237,11 @@ void Command::reset(void) // // MAIN-THREAD (AICurlEasyRequest::addRequest) // * command_queue locked -// - A non-active (mActiveMultiHandle is NULL) ThreadSafeCurlEasyRequest (by means of an AICurlEasyRequest pointing to it) is added to command_queue with as command cmd_add. +// - A non-active (mActiveMultiHandle is NULL) ThreadSafeBufferedCurlEasyRequest (by means of an AICurlEasyRequest pointing to it) is added to command_queue with as command cmd_add. // * command_queue unlocked // // If at this point addRequest is called again, then it is detected that the last command added to the queue -// for this ThreadSafeCurlEasyRequest is cmd_add. +// for this ThreadSafeBufferedCurlEasyRequest is cmd_add. // // CURL-THREAD (AICurlThread::wakeup): // * command_queue locked @@ -251,7 +251,7 @@ void Command::reset(void) // - The command is removed from command_queue // * command_queue unlocked // -// If at this point addRequest is called again, then it is detected that command_being_processed adds the same ThreadSafeCurlEasyRequest. +// If at this point addRequest is called again, then it is detected that command_being_processed adds the same ThreadSafeBufferedCurlEasyRequest. // // * command_being_processed is read-locked // - mActiveMultiHandle is set to point to the curl multi handle @@ -260,7 +260,7 @@ void Command::reset(void) // - command_being_processed is reset // * command_being_processed is unlocked // -// If at this point addRequest is called again, then it is detected that the ThreadSafeCurlEasyRequest is active. +// If at this point addRequest is called again, then it is detected that the ThreadSafeBufferedCurlEasyRequest is active. // Multi-threaded queue for passing Command objects from the main-thread to the curl-thread. AIThreadSafeSimpleDC > command_queue; @@ -746,7 +746,7 @@ std::ostream& operator<<(std::ostream& os, DebugFdSet const& s) class CurlSocketInfo { public: - CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeCurlEasyRequest* lockobj); + CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj); ~CurlSocketInfo(); void set_action(int action); @@ -760,7 +760,7 @@ class CurlSocketInfo LLPointer mTimeout; }; -CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeCurlEasyRequest* lockobj) : +CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj) : mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mEasyRequest(lockobj) { llassert(*AICurlEasyRequest_wat(*mEasyRequest) == easy); @@ -1464,7 +1464,7 @@ void MultiHandle::handle_stalls(void) int MultiHandle::socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp) { #ifdef CWDEBUG - ThreadSafeCurlEasyRequest* lockobj = NULL; + ThreadSafeBufferedCurlEasyRequest* lockobj = NULL; curl_easy_getinfo(easy, CURLINFO_PRIVATE, &lockobj); DoutEntering(dc::curl, "MultiHandle::socket_callback((CURL*)" << (void*)easy << ", " << s << ", " << action_str(action) << ", " << (void*)userp << ", " << (void*)socketp << ") [CURLINFO_PRIVATE = " << (void*)lockobj << "]"); @@ -1479,7 +1479,7 @@ int MultiHandle::socket_callback(CURL* easy, curl_socket_t s, int action, void* { if (!sock_info) { - ThreadSafeCurlEasyRequest* ptr; + ThreadSafeBufferedCurlEasyRequest* ptr; CURLcode rese = curl_easy_getinfo(easy, CURLINFO_PRIVATE, &ptr); llassert_always(rese == CURLE_OK); sock_info = new CurlSocketInfo(self, easy, s, action, ptr); @@ -1599,7 +1599,7 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons #endif } #if CWDEBUG - ThreadSafeCurlEasyRequest* lockobj = iter->get_ptr().get(); + ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get(); #endif mAddedEasyRequests.erase(iter); Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles."); @@ -1626,7 +1626,7 @@ void MultiHandle::check_run_count(void) if (msg->msg == CURLMSG_DONE) { CURL* easy = msg->easy_handle; - ThreadSafeCurlEasyRequest* ptr; + ThreadSafeBufferedCurlEasyRequest* ptr; CURLcode rese = curl_easy_getinfo(easy, CURLINFO_PRIVATE, &ptr); llassert_always(rese == CURLE_OK); AICurlEasyRequest easy_request(ptr); @@ -1973,9 +1973,9 @@ void HTTPTimeout::done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode DoutCurl("done: mStalled set to -1"); } -void HTTPTimeout::print_diagnostics(AICurlEasyRequest_wat const& curlEasyRequest_w) +void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request) { - llwarns << "Request to " << curlEasyRequest_w->getLowercaseHostname() << " timed out for " << curlEasyRequest_w->getTimeoutPolicy()->name() << llendl; + llwarns << "Request to " << curl_easy_request->getLowercaseHostname() << " timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl; } } // namespace curlthread @@ -2039,48 +2039,25 @@ void stopCurlThread(void) } //----------------------------------------------------------------------------- -// CurlResponderBuffer +// BufferedCurlEasyRequest -void CurlResponderBuffer::setStatusAndReason(U32 status, std::string const& reason) +void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const& reason) { mStatus = status; mReason = reason; } -void CurlResponderBuffer::added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) -{ - llerrs << "Unexpected call to added_to_multi_handle()." << llendl; -} - -void CurlResponderBuffer::finished(AICurlEasyRequest_wat& curl_easy_request_w) -{ - llerrs << "Unexpected call to finished()." << llendl; -} - -void CurlResponderBuffer::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) -{ - DoutCurl("Calling CurlResponderBuffer::removed_from_multi_handle(@" << (void*)&*curl_easy_request_w << ") for this = " << (void*)this); - - // Lock self. - ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); - llassert(dynamic_cast(static_cast(ThreadSafeCurlEasyRequest::wrapper_cast(&*curl_easy_request_w))) == lockobj); - AICurlResponderBuffer_wat buffer_w(*lockobj); - llassert(&*buffer_w == this); - - processOutput(curl_easy_request_w); -} - -void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request_w) +void BufferedCurlEasyRequest::processOutput(void) { U32 responseCode = 0; std::string responseReason; CURLcode code; AITransferInfo info; - curl_easy_request_w->getResult(&code, &info); + getResult(&code, &info); if (code == CURLE_OK) { - curl_easy_request_w->getinfo(CURLINFO_RESPONSE_CODE, &responseCode); + getinfo(CURLINFO_RESPONSE_CODE, &responseCode); // If getResult code is CURLE_OK then we should have decoded the first header line ourselves. llassert(responseCode == mStatus); if (responseCode == mStatus) @@ -2092,12 +2069,12 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request { responseCode = HTTP_INTERNAL_ERROR; responseReason = curl_easy_strerror(code); - curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); + setopt(CURLOPT_FRESH_CONNECT, TRUE); } if (code != CURLE_OK) { - curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); + print_diagnostics(code); } if (mBufferEventsTarget) { @@ -2110,43 +2087,42 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request mResponder->finished(code, responseCode, responseReason, sChannels, mOutput); mResponder = NULL; - resetState(curl_easy_request_w); + resetState(); } -void CurlResponderBuffer::received_HTTP_header(void) +void BufferedCurlEasyRequest::received_HTTP_header(void) { if (mBufferEventsTarget) mBufferEventsTarget->received_HTTP_header(); } -void CurlResponderBuffer::received_header(std::string const& key, std::string const& value) +void BufferedCurlEasyRequest::received_header(std::string const& key, std::string const& value) { if (mBufferEventsTarget) mBufferEventsTarget->received_header(key, value); } -void CurlResponderBuffer::completed_headers(U32 status, std::string const& reason, AITransferInfo* info) +void BufferedCurlEasyRequest::completed_headers(U32 status, std::string const& reason, AITransferInfo* info) { if (mBufferEventsTarget) mBufferEventsTarget->completed_headers(status, reason, info); } //static -size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data) +size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data) { ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); // We need to lock the curl easy request object too, because that lock is used // to make sure that callbacks and destruction aren't done simultaneously. - AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + AICurlEasyRequest_wat self_w(*lockobj); S32 bytes = size * nmemb; // The amount to write. - AICurlResponderBuffer_wat buffer_w(*lockobj); - // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. + // BufferedCurlEasyRequest::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; - buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); - buffer_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. - if (buffered_easy_request_w->httptimeout()->data_received(bytes)) // Update timeout administration. + self_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); + self_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. + if (self_w->httptimeout()->data_received(bytes)) // Update timeout administration. { // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. return 0; @@ -2155,23 +2131,22 @@ size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nm } //static -size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) +size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) { ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); // We need to lock the curl easy request object too, because that lock is used // to make sure that callbacks and destruction aren't done simultaneously. - AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + AICurlEasyRequest_wat self_w(*lockobj); S32 bytes = size * nmemb; // The maximum amount to read. - AICurlResponderBuffer_wat buffer_w(*lockobj); - buffer_w->mLastRead = buffer_w->getInput()->readAfter(sChannels.out(), buffer_w->mLastRead, (U8*)data, bytes); - buffer_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. + self_w->mLastRead = self_w->getInput()->readAfter(sChannels.out(), self_w->mLastRead, (U8*)data, bytes); + self_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. // Timeout administration. Note that it can happen that we get here // before the socket callback has been called, because the silly libcurl // writes headers without informing us. In that case it's OK to create // the Timeout object on the fly, so pass lockobj. - if (buffered_easy_request_w->httptimeout(lockobj)->data_sent(bytes)) + if (self_w->httptimeout(lockobj)->data_sent(bytes)) { // Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK. return CURL_READFUNC_ABORT; @@ -2180,19 +2155,19 @@ size_t CurlResponderBuffer::curlReadCallback(char* data, size_t size, size_t nme } //static -size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data) +size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data) { ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); // We need to lock the curl easy request object, because that lock is used // to make sure that callbacks and destruction aren't done simultaneously. - AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); + AICurlEasyRequest_wat self_w(*lockobj); // This used to be headerCallback() in llurlrequest.cpp. char const* const header_line = static_cast(data); size_t const header_len = size * nmemb; - if (buffered_easy_request_w->httptimeout()->data_received(header_len)) // Update timeout administration. + if (self_w->httptimeout()->data_received(header_len)) // Update timeout administration. { // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. return 0; @@ -2231,9 +2206,8 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n llwarns << "Received broken header line from server: \"" << header << "\"" << llendl; } { - AICurlResponderBuffer_wat curl_responder_buffer_w(*lockobj); - curl_responder_buffer_w->received_HTTP_header(); - curl_responder_buffer_w->setStatusAndReason(status, reason); + self_w->received_HTTP_header(); + self_w->setStatusAndReason(status, reason); } return header_len; } @@ -2248,7 +2222,7 @@ size_t CurlResponderBuffer::curlHeaderCallback(char* data, size_t size, size_t n key = utf8str_tolower(utf8str_trim(key)); value = utf8str_trim(value); - AICurlResponderBuffer_wat(*lockobj)->received_header(key, value); + self_w->received_header(key, value); } else { @@ -2268,7 +2242,7 @@ int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* #ifdef CWDEBUG using namespace ::libcwd; - CurlEasyRequest* request = (CurlEasyRequest*)user_ptr; + BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr; std::ostringstream marker; marker << (void*)request->get_lockobj(); libcw_do.push_marker(); diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 05f3d4b63..1c8fe9c65 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -84,15 +84,6 @@ public: * associated CurlResponderBuffer, however, if everything works correctly, then normally a * responder is deleted in CurlResponderBuffer::removed_from_multi_handle by setting * mReponder to NULL. - * - * Note that the lifetime of CurlResponderBuffer is (a bit) shorter than the associated - * CurlEasyRequest (because of the order of base classes of ThreadSafeBufferedCurlEasyRequest) - * and the callbacks, as set by prepRequest, only use those two. - * A callback locks the CurlEasyRequest before actually making the callback, and the - * destruction of CurlResponderBuffer also first locks the CurlEasyRequest, and then revokes - * the callbacks. This assures that a Responder is never used when the objects it uses are - * destructed. Also, if any of those are destructed then the Responder is automatically - * destructed too. */ class ResponderBase : public AICurlResponderBufferEvents { public: diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 3653f7058..e6b4ee4c3 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -78,7 +78,7 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) // This might throw AICurlNoEasyHandle. LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) : - AICurlEasyRequestStateMachine(true), mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression), + mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression), mBody(body), mResponder(responder), mHeaders(headers) { } @@ -121,17 +121,16 @@ void LLURLRequest::initialize_impl(void) bool success = false; try { - AICurlEasyRequest_wat buffered_easy_request_w(*mCurlEasyRequest); - AICurlResponderBuffer_wat buffer_w(*mCurlEasyRequest); - buffer_w->prepRequest(buffered_easy_request_w, mHeaders, mResponder); + AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); + easy_request_w->prepRequest(easy_request_w, mHeaders, mResponder); if (mBody) { // This might throw AICurlNoBody. - mBodySize = mBody->get_body(buffer_w->sChannels, buffer_w->getInput()); + mBodySize = mBody->get_body(easy_request_w->sChannels, easy_request_w->getInput()); } - success = configure(buffered_easy_request_w); + success = configure(easy_request_w); } catch (AICurlNoBody const& error) {