From cd93aba002bb3248e3e099d80ce68242531035c0 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 25 Jul 2012 03:27:02 +0200 Subject: [PATCH 001/138] 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 002/138] 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 003/138] 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 004/138] 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 005/138] 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 006/138] 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 007/138] 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 008/138] 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 009/138] 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 010/138] 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 011/138] 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 9b358a1b397063ce87b7abcae9b38a2921e70d17 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Sat, 8 Sep 2012 02:01:25 -0400 Subject: [PATCH 012/138] Initial llqtwebkit --- LICENSES/FLOSS-exception.txt | 114 ++ LICENSES/GPL-license.txt | 339 +++++ LICENSES/LLQTWEBKIT_LICENSE.txt | 36 + indra/CMakeLists.txt | 4 + indra/cmake/CMakeLists.txt | 2 + indra/cmake/GooglePerfTools.cmake | 6 +- indra/cmake/LLQtWebkit.cmake | 11 + indra/cmake/Qt4.cmake | 12 + indra/cmake/WebKitLibPlugin.cmake | 25 +- indra/llplugin/llpluginclassmedia.cpp | 2 - indra/llqtwebkit/CMakeLists.txt | 70 + .../llembeddedbrowser/llembeddedbrowser.pro | 14 + .../tst_llembeddedbrowser.cpp | 400 ++++++ .../llembeddedbrowserwindow.pro | 14 + .../tst_llembeddedbrowserwindow.cpp | 1027 +++++++++++++++ indra/llqtwebkit/llembeddedbrowser.cpp | 759 +++++++++++ indra/llqtwebkit/llembeddedbrowser.h | 115 ++ indra/llqtwebkit/llembeddedbrowser_p.h | 90 ++ indra/llqtwebkit/llembeddedbrowserwindow.cpp | 1136 +++++++++++++++++ indra/llqtwebkit/llembeddedbrowserwindow.h | 185 +++ indra/llqtwebkit/llembeddedbrowserwindow_p.h | 251 ++++ indra/llqtwebkit/lljsobject.cpp | 153 +++ indra/llqtwebkit/lljsobject.h | 71 ++ indra/llqtwebkit/llnetworkaccessmanager.cpp | 247 ++++ indra/llqtwebkit/llnetworkaccessmanager.h | 57 + indra/llqtwebkit/llqtwebkit.cpp | 820 ++++++++++++ indra/llqtwebkit/llqtwebkit.h | 470 +++++++ indra/llqtwebkit/llqtwebkit.pri | 47 + indra/llqtwebkit/llqtwebkit.pro | 18 + indra/llqtwebkit/llstyle.cpp | 79 ++ indra/llqtwebkit/llstyle.h | 42 + indra/llqtwebkit/llwebpage.cpp | 536 ++++++++ indra/llqtwebkit/llwebpage.h | 108 ++ indra/llqtwebkit/llwebpageopenshim.cpp | 176 +++ indra/llqtwebkit/llwebpageopenshim.h | 63 + indra/llqtwebkit/passworddialog.ui | 137 ++ indra/llqtwebkit/pstdint.h | 728 +++++++++++ .../qtwebkit_cookiejar/CMakeLists.txt | 3 + .../qtwebkit_cookiejar/autotest/trie/trie.pro | 15 + .../autotest/trie/tst_trie.cpp | 270 ++++ .../benchmark/networkcookiejar/cookiejar.pro | 17 + .../benchmark/networkcookiejar/main.cpp | 159 +++ .../manualtest/browser/browser.pro | 11 + .../manualtest/browser/main.cpp | 85 ++ .../manualtest/fuzz/fuzz.pro | 12 + .../manualtest/fuzz/main.cpp | 100 ++ .../qtwebkit_cookiejar/src/CMakeLists.txt | 27 + .../src/networkcookiejar.cpp | 444 +++++++ .../qtwebkit_cookiejar/src/networkcookiejar.h | 61 + .../src/networkcookiejar_p.h | 66 + .../llqtwebkit/qtwebkit_cookiejar/src/src.pri | 5 + .../qtwebkit_cookiejar/src/trie_p.h | 247 ++++ .../src/twoleveldomains_p.h | 92 ++ indra/llqtwebkit/static.pri | 18 + indra/llqtwebkit/tests/3dgl/3dgl.cpp | 269 ++++ indra/llqtwebkit/tests/3dgl/3dgl.pro | 38 + indra/llqtwebkit/tests/3dgl/zpr.c | 429 +++++++ indra/llqtwebkit/tests/3dgl/zpr.h | 88 ++ indra/llqtwebkit/tests/qttestapp/main.cpp | 341 +++++ .../llqtwebkit/tests/qttestapp/qttestapp.pro | 38 + indra/llqtwebkit/tests/qttestapp/webpage.h | 0 indra/llqtwebkit/tests/qttestapp/window.ui | 79 ++ indra/llqtwebkit/tests/ssltest/ssltest.cpp | 229 ++++ indra/llqtwebkit/tests/ssltest/ssltest.pro | 28 + indra/llqtwebkit/tests/testgl/testgl.cpp | 1002 +++++++++++++++ indra/llqtwebkit/tests/testgl/testgl.pro | 38 + indra/llqtwebkit/tests/textmode/textmode.cpp | 292 +++++ indra/llqtwebkit/tests/textmode/textmode.pro | 28 + indra/llqtwebkit/win32/3p-qt-vars.bat | 6 + .../win32/Qt Command Prompt (3p-qt).lnk | Bin 0 -> 2369 bytes indra/plugins/webkit/CMakeLists.txt | 1 + indra/plugins/webkit/media_plugin_webkit.cpp | 4 +- 72 files changed, 12876 insertions(+), 30 deletions(-) create mode 100644 LICENSES/FLOSS-exception.txt create mode 100644 LICENSES/GPL-license.txt create mode 100644 LICENSES/LLQTWEBKIT_LICENSE.txt create mode 100644 indra/cmake/LLQtWebkit.cmake create mode 100644 indra/cmake/Qt4.cmake create mode 100644 indra/llqtwebkit/CMakeLists.txt create mode 100644 indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro create mode 100644 indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp create mode 100644 indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro create mode 100644 indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp create mode 100644 indra/llqtwebkit/llembeddedbrowser.cpp create mode 100644 indra/llqtwebkit/llembeddedbrowser.h create mode 100644 indra/llqtwebkit/llembeddedbrowser_p.h create mode 100644 indra/llqtwebkit/llembeddedbrowserwindow.cpp create mode 100644 indra/llqtwebkit/llembeddedbrowserwindow.h create mode 100644 indra/llqtwebkit/llembeddedbrowserwindow_p.h create mode 100644 indra/llqtwebkit/lljsobject.cpp create mode 100644 indra/llqtwebkit/lljsobject.h create mode 100644 indra/llqtwebkit/llnetworkaccessmanager.cpp create mode 100644 indra/llqtwebkit/llnetworkaccessmanager.h create mode 100644 indra/llqtwebkit/llqtwebkit.cpp create mode 100644 indra/llqtwebkit/llqtwebkit.h create mode 100644 indra/llqtwebkit/llqtwebkit.pri create mode 100644 indra/llqtwebkit/llqtwebkit.pro create mode 100644 indra/llqtwebkit/llstyle.cpp create mode 100644 indra/llqtwebkit/llstyle.h create mode 100644 indra/llqtwebkit/llwebpage.cpp create mode 100644 indra/llqtwebkit/llwebpage.h create mode 100644 indra/llqtwebkit/llwebpageopenshim.cpp create mode 100644 indra/llqtwebkit/llwebpageopenshim.h create mode 100644 indra/llqtwebkit/passworddialog.ui create mode 100644 indra/llqtwebkit/pstdint.h create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h create mode 100644 indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h create mode 100644 indra/llqtwebkit/static.pri create mode 100644 indra/llqtwebkit/tests/3dgl/3dgl.cpp create mode 100644 indra/llqtwebkit/tests/3dgl/3dgl.pro create mode 100644 indra/llqtwebkit/tests/3dgl/zpr.c create mode 100644 indra/llqtwebkit/tests/3dgl/zpr.h create mode 100644 indra/llqtwebkit/tests/qttestapp/main.cpp create mode 100644 indra/llqtwebkit/tests/qttestapp/qttestapp.pro create mode 100644 indra/llqtwebkit/tests/qttestapp/webpage.h create mode 100644 indra/llqtwebkit/tests/qttestapp/window.ui create mode 100644 indra/llqtwebkit/tests/ssltest/ssltest.cpp create mode 100644 indra/llqtwebkit/tests/ssltest/ssltest.pro create mode 100644 indra/llqtwebkit/tests/testgl/testgl.cpp create mode 100644 indra/llqtwebkit/tests/testgl/testgl.pro create mode 100644 indra/llqtwebkit/tests/textmode/textmode.cpp create mode 100644 indra/llqtwebkit/tests/textmode/textmode.pro create mode 100644 indra/llqtwebkit/win32/3p-qt-vars.bat create mode 100644 indra/llqtwebkit/win32/Qt Command Prompt (3p-qt).lnk diff --git a/LICENSES/FLOSS-exception.txt b/LICENSES/FLOSS-exception.txt new file mode 100644 index 000000000..483246685 --- /dev/null +++ b/LICENSES/FLOSS-exception.txt @@ -0,0 +1,114 @@ +Linden Research, Inc. ("Linden Lab") Viewer FLOSS License Exception v0.5 + +The Linden Lab Exception for Free/Libre and Open Source Software-only +Applications Using Linden Lab Viewer Software (the "FLOSS Exception"). + +Exception Intent + +Linden Lab is releasing the source code for certain software that +enables users to view or otherwise access the Second Life virtual +world environment (the "Viewer Software"), under version 2 of the GNU +General Public License (the "GPL"). The creation or distribution of +works based on the Program (as defined under the GPL) of the Viewer +Software may require the use of certain Free/Libre and Open Source +Software ("FLOSS") works that are subject to license agreements not +compatible with re-licensing under the GPL. Because we want to allow +the Viewer Software to be distributed with these FLOSS works, this +FLOSS Exception following exception applies subject to the terms and +conditions below. + +Legal Terms and Conditions + +As a special exception to the terms and conditions of version 2.0 of +the GPL: + +You are free to distribute a work based on the Program that is formed +entirely from the Viewer Software (and any modifications thereof) and +one or more works that are independent and separate works not derived +from the Viewer Software, and are licensed under one or more of the +licenses listed below in section 1 (each, a "FLOSS Work") , as long +as: + + A. You obey the GPL in all respects for the Viewer Software and any + work based on the Program, except for the FLOSS Works, for which + you must comply with B below, + + B. all FLOSS Works, + + i. are distributed subject to one of the FLOSS licenses + listed below, and + + ii. the object code or executable form of the FLOSS Works are + accompanied by the complete corresponding + machine-readable source code for those FLOSS Works on the + same medium and under the same FLOSS license as the + corresponding object code or executable forms thereof, + and + + C. any works that are aggregated with the Viewer Software or a work + based on the Program on a volume of a storage or distribution + medium in accordance with the GPL, and are not licensed under + the FLOSS licenses listed below, are independent and separate + works in themselves which are not derivatives of either the + Viewer Software, a work based on the Program or a FLOSS Work. + +If the above conditions are not met, then the Viewer Software may only +be copied, modified, distributed or used under the terms and +conditions of the GPL or another valid licensing option from Linden +Lab. + +1. FLOSS License List + +License name Version(s)/Copyright Date +Academic Free License 2.0 +Apache Software License 1.0/1.1/2.0 +Apple Public Source License 2.0 +Artistic license From Perl 5.8.0 +BSD license "July 22 1999" +Common Development and + Distribution License (CDDL) 1.0 +Common Public License 1.0 +GNU Library or "Lesser" General + Public License (LGPL) 2.0/2.1 +Jabber Open Source License 1.0 +MIT License (As listed in file MIT-License.txt) - +Mozilla Public License (MPL) 1.0/1.1 +Open Software License 2.0 +OpenSSL license (with + original SSLeay license) "2003" ("1998") +PHP License 3.0 +Python license (CNRI Python License) - +Python Software Foundation License 2.1.1 +Sleepycat License "1999" +W3C License "2001" +X11 License "2001" +Zlib/libpng License - +Zope Public License 2.0 + +Due to the many variants of some of the above licenses, we require +that any variant of the above licenses be identical in substance to +the form approved by the Open Source Initiative and follow the 2003 +version of the Free Software Foundation's Free Software Definition +(http://www.gnu.org/philosophy/free-sw.html) or version 1.9 of the +Open Source Definition by the Open Source Initiative +(http://www.opensource.org/docs/definition.php). + +2. Definitions + +Terms used, but not defined, herein shall have the meaning provided in +the GPL. + +3. Applicability + +This FLOSS Exception applies to all Viewer Software files that contain +a notice placed by Linden Lab saying that the Viewer Software may be +distributed under the terms of this FLOSS Exception. If you create or +distribute a work which is a work based on the Program for the Viewer +Software and any other work licensed under the GPL, then this FLOSS +Exception is not available for that work; thus, you must remove the +FLOSS Exception notice from that work and comply with the GPL in all +respects, including by retaining all GPL notices. You may choose to +redistribute a copy of the Viewer Software exclusively under the terms +of the GPL by removing the FLOSS Exception notice from that copy of +the Viewer Software, provided that the copy has never been modified by +you or any third party. diff --git a/LICENSES/GPL-license.txt b/LICENSES/GPL-license.txt new file mode 100644 index 000000000..d511905c1 --- /dev/null +++ b/LICENSES/GPL-license.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSES/LLQTWEBKIT_LICENSE.txt b/LICENSES/LLQTWEBKIT_LICENSE.txt new file mode 100644 index 000000000..405d89131 --- /dev/null +++ b/LICENSES/LLQTWEBKIT_LICENSE.txt @@ -0,0 +1,36 @@ +Source code +======== +The license for the source code in this distribution should be clearly +marked on each source file. Unless otherwise specified, the source +code in this distribution ("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 GPL-license.txt in this distribution, or +online at http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or +online at http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + +Logos and trademarks +============== + +"Second Life" and "Linden Lab" are registered trademarks of Linden +Research, Inc. Other trademarks include (but are not limited to): the +names Linden and Linden Research, as well as the Linden Lab Hexagon +Design and the Second Life Hand Design logos. + +Use of logos and trademarks are subject to the Linden Lab trademark +policy, available at: + +http://secondlife.com/corporate/trademark/ diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 08daa9681..d5f75fa89 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -62,6 +62,10 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llvfs) add_subdirectory(${LIBS_OPEN_PREFIX}llwindow) add_subdirectory(${LIBS_OPEN_PREFIX}llxml) +if(STANDALONE) + add_subdirectory(${LIBS_OPEN_PREFIX}llqtwebkit) +endif(STANDALONE) + if (EXISTS ${LIBS_CLOSED_DIR}llkdu AND NOT STANDALONE) add_subdirectory(${LIBS_CLOSED_PREFIX}llkdu) endif (EXISTS ${LIBS_CLOSED_DIR}llkdu AND NOT STANDALONE) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 21eee45ac..ce860a988 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -54,6 +54,7 @@ set(cmake_SOURCE_FILES LLMessage.cmake LLPlugin.cmake LLPrimitive.cmake + LLQtWebkit.cmake LLRender.cmake LLScene.cmake LLUI.cmake @@ -70,6 +71,7 @@ set(cmake_SOURCE_FILES PNG.cmake Python.cmake Prebuilt.cmake + Qt4.cmake RunBuildTest.cmake TemplateCheck.cmake Tut.cmake diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake index c102542e0..c65012162 100644 --- a/indra/cmake/GooglePerfTools.cmake +++ b/indra/cmake/GooglePerfTools.cmake @@ -1,9 +1,9 @@ # -*- cmake -*- include(Prebuilt) -if(WORD_SIZE EQUAL 64) - set(DISABLE_TCMALLOC TRUE) -endif(WORD_SIZE EQUAL 64) +#if(WORD_SIZE EQUAL 64) +# set(DISABLE_TCMALLOC TRUE) +#endif(WORD_SIZE EQUAL 64) if (STANDALONE) include(FindGooglePerfTools) diff --git a/indra/cmake/LLQtWebkit.cmake b/indra/cmake/LLQtWebkit.cmake new file mode 100644 index 000000000..cec7e22e9 --- /dev/null +++ b/indra/cmake/LLQtWebkit.cmake @@ -0,0 +1,11 @@ +# -*- cmake -*- + +if (STANDALONE) + set(LLQTWEBKIT_INCLUDE_DIR + ${LIBS_OPEN_DIR}/llqtwebkit + ) + + set(LLQTWEBKIT_LIBRARY + llqtwebkit + ) +endif (STANDALONE) diff --git a/indra/cmake/Qt4.cmake b/indra/cmake/Qt4.cmake new file mode 100644 index 000000000..37d2799a2 --- /dev/null +++ b/indra/cmake/Qt4.cmake @@ -0,0 +1,12 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + set(Qt4_FIND_REQUIRED ON) + + include(FindQt4) + + find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED) + include(${QT_USE_FILE}) + add_definitions(${QT_DEFINITIONS}) +endif (STANDALONE) diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake index 7ed824aea..5d1036c6f 100644 --- a/indra/cmake/WebKitLibPlugin.cmake +++ b/indra/cmake/WebKitLibPlugin.cmake @@ -1,31 +1,10 @@ # -*- cmake -*- include(Linking) include(Prebuilt) +include(LLQtWebkit) +include(Qt4) if (STANDALONE) - # The minimal version, 4.4.3, is rather arbitrary: it's the version in Debian/Lenny. - find_package(Qt4 4.4.3 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED) - include(${QT_USE_FILE}) - set(QTDIR $ENV{QTDIR}) - if (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") - message(FATAL_ERROR "\"${QT_BINARY_DIR}\" is unequal \"${QTDIR}/bin\"; " - "Qt is found by looking for qmake in your PATH. " - "Please set your PATH such that 'qmake' is found in \$QTDIR/bin, " - "or unset QTDIR if the found Qt is correct.") - endif (QTDIR AND NOT "${QT_BINARY_DIR}" STREQUAL "${QTDIR}/bin") - find_package(LLQtWebkit REQUIRED QUIET) - # Add the plugins. - set(QT_PLUGIN_LIBRARIES) - foreach(qlibname qgif qjpeg) - find_library(QT_PLUGIN_${qlibname} ${qlibname} PATHS ${QT_PLUGINS_DIR}/imageformats NO_DEFAULT_PATH) - if (QT_PLUGIN_${qlibname}) - list(APPEND QT_PLUGIN_LIBRARIES ${QT_PLUGIN_${qlibname}}) - else (QT_PLUGIN_${qtlibname}) - message(FATAL_ERROR "Could not find the Qt plugin ${qlibname} in \"${QT_PLUGINS_DIR}/imageformats\"!") - endif (QT_PLUGIN_${qlibname}) - endforeach(qlibname) - # qjpeg depends on libjpeg - list(APPEND QT_PLUGIN_LIBRARIES jpeg) set(WEBKITLIBPLUGIN OFF CACHE BOOL "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") else (STANDALONE) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index c71515496..064b12da1 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -39,8 +39,6 @@ #include "llpluginclassmedia.h" #include "llpluginmessageclasses.h" -#include "llqtwebkit.h" - static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; static int nextPowerOf2( int value ) diff --git a/indra/llqtwebkit/CMakeLists.txt b/indra/llqtwebkit/CMakeLists.txt new file mode 100644 index 000000000..6fbf5e960 --- /dev/null +++ b/indra/llqtwebkit/CMakeLists.txt @@ -0,0 +1,70 @@ +# -*- cmake -*- + +project(llqtwebkit) + +include(00-Common) +include(Qt4) + +if(NOT WORD_SIZE EQUAL 32) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) + add_definitions(-fPIC) + endif(WINDOWS) +endif(NOT WORD_SIZE EQUAL 32) + +include_directories(${QT_INCLUDES}) + +add_subdirectory(qtwebkit_cookiejar) +include_directories(qtwebkit_cookiejar/src/) + +set(llqtwebkit_SOURCE_FILES + llembeddedbrowser.cpp + llembeddedbrowserwindow.cpp + lljsobject.cpp + llnetworkaccessmanager.cpp + llqtwebkit.cpp + llstyle.cpp + llwebpage.cpp + llwebpageopenshim.cpp + ) + +set(llqtwebkit_HEADER_FILES + llembeddedbrowser.h + llembeddedbrowser_p.h + llembeddedbrowserwindow.h + llembeddedbrowserwindow_p.h + lljsobject.h + llnetworkaccessmanager.h + llqtwebkit.h + llstyle.h + llwebpage.h + llwebpageopenshim.h + pstdint.h + ) + +set(llqtwebkit_UI_FILES + passworddialog.ui + ) + +set(llqtwebkit_LINK_LIBRARIES + networkcookiejar +) + +QT4_WRAP_UI(llqtwebkit_UI_MOC ${llqtwebkit_UI_FILES}) +QT4_WRAP_CPP(llqtwebkit_HEADERS_MOC ${llqtwebkit_HEADER_FILES}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_library(llqtwebkit + ${llqtwebkit_SOURCE_FILES} + ${llqtwebkit_HEADERS_MOC} + ${llqtwebkit_UI_MOC} +) + +add_dependencies(llqtwebkit prepare) + +target_link_libraries(llqtwebkit ${llqtwebkit_LINK_LIBRARIES}) + +add_dependencies(llqtwebkit + networkcookiejar +) diff --git a/indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro b/indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro new file mode 100644 index 000000000..02ecce5a2 --- /dev/null +++ b/indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +CONFIG += qtestlib +QT += webkit opengl network + +include(../../llmozlib2.pri) +DEFINES += AUTOTEST + +# Input +SOURCES += tst_llembeddedbrowser.cpp + diff --git a/indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp b/indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp new file mode 100644 index 000000000..a59cc9e19 --- /dev/null +++ b/indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp @@ -0,0 +1,400 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include +#include + +class tst_LLEmbeddedBrowser : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void llembeddedbrowser_data(); + void llembeddedbrowser(); + + void clearAllCookies(); + void clearCache_data(); + void clearCache(); + void clearLastError_data(); + void clearLastError(); + void createBrowserWindow_data(); + void createBrowserWindow(); + void destroyBrowserWindow(); + void enableCookies_data(); + void enableCookies(); + void enablePlugins_data(); + void enablePlugins(); + void enableProxy_data(); + void enableProxy(); + void getGREVersion_data(); + void getGREVersion(); + void getInstance(); + void getLastError_data(); + void getLastError(); + void initBrowser_data(); + void initBrowser(); //change function init as initbrowser + void reset(); + void setBrowserAgentId_data(); + void setBrowserAgentId(); + void setLastError_data(); + void setLastError(); +}; + +// Subclass that exposes the protected functions. +class SubLLEmbeddedBrowser : public LLEmbeddedBrowser +{ +public: + +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_LLEmbeddedBrowser::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_LLEmbeddedBrowser::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_LLEmbeddedBrowser::init() +{ +} + +// This will be called after every test function. +void tst_LLEmbeddedBrowser::cleanup() +{ +} + +void tst_LLEmbeddedBrowser::llembeddedbrowser_data() +{ +} + +void tst_LLEmbeddedBrowser::llembeddedbrowser() +{ + SubLLEmbeddedBrowser browser; + QCOMPARE(browser.clearAllCookies(), false); + QCOMPARE(browser.clearCache(), false); + browser.clearLastError(); + QCOMPARE(browser.enableCookies(false), false); + QCOMPARE(browser.enablePlugins(false), true); + QCOMPARE(browser.enableProxy(false, std::string(""), -1), true); + QCOMPARE(browser.getGREVersion(), std::string(QT_VERSION_STR)); + QVERIFY(browser.getInstance() != NULL); + QCOMPARE(browser.getLastError(), 0); + browser.setBrowserAgentId("uBrowser"); + browser.setLastError(-1); + QCOMPARE(browser.reset(), true); + browser.destroyBrowserWindow(0); + browser.destroyBrowserWindow((LLEmbeddedBrowserWindow*)6); + QCOMPARE(browser.getWindowCount(), 0); + QCOMPARE(browser.init(std::string(""),std::string(""),std::string(""),0), true); +} + +// public bool clearAllCookies() +void tst_LLEmbeddedBrowser::clearAllCookies() +{ + SubLLEmbeddedBrowser browser; + + QCOMPARE(browser.clearAllCookies(), false); + browser.reset(); + QCOMPARE(browser.clearAllCookies(), true); +} + +void tst_LLEmbeddedBrowser::clearCache_data() +{ + QTest::addColumn("clearCache"); +#if QT_VERSION < 0x040500 + QTest::newRow("QTVersion < 4.5") << false; +#else + QTest::newRow("QTVersion > 4.5") << true; +#endif +} + +// public bool clearCache() +void tst_LLEmbeddedBrowser::clearCache() +{ + QFETCH(bool, clearCache); + + SubLLEmbeddedBrowser browser; + browser.reset(); + QCOMPARE(browser.clearCache(), clearCache); +} + +void tst_LLEmbeddedBrowser::clearLastError_data() +{ + QTest::addColumn("lastError"); + QTest::newRow("1") << 1; +} + +// public void clearLastError() +void tst_LLEmbeddedBrowser::clearLastError() +{ + SubLLEmbeddedBrowser browser; + QFETCH(int, lastError); + + browser.setLastError(lastError); + browser.clearLastError(); + QCOMPARE(browser.getLastError(), 0); +} + +void tst_LLEmbeddedBrowser::createBrowserWindow_data() +{ + QTest::addColumn("width"); + QTest::addColumn("height"); + QTest::newRow("0,0") << 0 << 0; + QTest::newRow("800,600") << 800 << 600; +} + +// public LLEmbeddedBrowserWindow* createBrowserWindow(int width, int height) +void tst_LLEmbeddedBrowser::createBrowserWindow() +{ + QFETCH(int, width); + QFETCH(int, height); + SubLLEmbeddedBrowser browser; + + LLEmbeddedBrowserWindow *window = browser.createBrowserWindow(width, height); + QVERIFY(window); + QCOMPARE(browser.getLastError(), 0); + QCOMPARE(browser.getWindowCount(), 1); + QCOMPARE(window->getBrowserWidth(), (int16_t)width); + QCOMPARE(window->getBrowserHeight(), (int16_t)height); +} + +// public bool destroyBrowserWindow(LLEmbeddedBrowserWindow* browser_window) +void tst_LLEmbeddedBrowser::destroyBrowserWindow() +{ + SubLLEmbeddedBrowser browser; + browser.reset(); + LLEmbeddedBrowserWindow* browser_window = browser.createBrowserWindow(200, 100); + if (browser_window) + { + QCOMPARE(browser.getWindowCount(), 1); + browser.destroyBrowserWindow(browser_window); + QCOMPARE(browser.getLastError(), 0); + QCOMPARE(browser.getWindowCount(), 0); + } + + browser_window = browser.createBrowserWindow(800, 600); + if (browser_window) + { + QCOMPARE(browser.getWindowCount(), 1); + browser.destroyBrowserWindow(browser_window); + QCOMPARE(browser.getLastError(), 0); + QCOMPARE(browser.getWindowCount(), 0); + } +} + +void tst_LLEmbeddedBrowser::enableCookies_data() +{ + QTest::addColumn("enabled"); + QTest::addColumn("enableCookies"); + QTest::newRow("disable") << false << false; + QTest::newRow("enable") << true << false; +} + +// public bool enableCookies(bool enabled) +void tst_LLEmbeddedBrowser::enableCookies() +{ + QFETCH(bool, enabled); + QFETCH(bool, enableCookies); + + SubLLEmbeddedBrowser browser; + browser.reset(); + QCOMPARE(browser.enableCookies(enabled), enableCookies); + // TODO check that cookies are not saved +} + +void tst_LLEmbeddedBrowser::enablePlugins_data() +{ + QTest::addColumn("enabled"); + QTest::addColumn("enablePlugins"); + QTest::newRow("disable") << false << true; + QTest::newRow("enable") << true << true; +} + +// public bool enablePlugins(bool enabled) +void tst_LLEmbeddedBrowser::enablePlugins() +{ + QFETCH(bool, enabled); + QFETCH(bool, enablePlugins); + + SubLLEmbeddedBrowser browser; + browser.reset(); + QCOMPARE(browser.enablePlugins(enabled), enablePlugins); + // TODO check that plugins work/do not work +} + +Q_DECLARE_METATYPE(std::string) +void tst_LLEmbeddedBrowser::enableProxy_data() +{ + QTest::addColumn("enabled"); + QTest::addColumn("host_name"); + QTest::addColumn("port"); + QTest::addColumn("enableProxy"); + QTest::newRow("null") << false << std::string() << 0 << true; + QTest::newRow("valid") << true << std::string("wtfsurf.com") << 80 << true; +} + +// public bool enableProxy(bool enabled, std::string host_name, int port) +void tst_LLEmbeddedBrowser::enableProxy() +{ + QFETCH(bool, enabled); + QFETCH(std::string, host_name); + QFETCH(int, port); + QFETCH(bool, enableProxy); + + SubLLEmbeddedBrowser browser; + browser.reset(); + QCOMPARE(browser.enableProxy(enabled, host_name, port), enableProxy); + // TODO need some proxy servers to test this +} + +void tst_LLEmbeddedBrowser::getGREVersion_data() +{ + QTest::addColumn("getGREVersion"); + QTest::newRow("valid") << std::string(QT_VERSION_STR); +} + +// public std::string getGREVersion() +void tst_LLEmbeddedBrowser::getGREVersion() +{ + QFETCH(std::string, getGREVersion); + + SubLLEmbeddedBrowser browser; + browser.reset(); + QCOMPARE(browser.getGREVersion(), getGREVersion); +} + +// public static LLEmbeddedBrowser* getInstance() +void tst_LLEmbeddedBrowser::getInstance() +{ + SubLLEmbeddedBrowser browser; + QVERIFY(browser.getInstance() != NULL); +} + +void tst_LLEmbeddedBrowser::getLastError_data() +{ + QTest::addColumn("error"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("100") << 100; +} + +// public int getLastError() +void tst_LLEmbeddedBrowser::getLastError() +{ + QFETCH(int, error); + SubLLEmbeddedBrowser browser; + browser.setLastError(error); + QCOMPARE(browser.getLastError(), error); +} + +void tst_LLEmbeddedBrowser::initBrowser_data() +{ + QTest::addColumn("application_directory"); + QTest::addColumn("component_directory"); + QTest::addColumn("profile_directory"); + QTest::addColumn("native_window_handleCount"); + QTest::addColumn("init"); + QTest::newRow("null") << std::string() << std::string() << std::string() << (void *)0 << true; + QTest::newRow("valid") << std::string("/home/crystal/Settings/") << std::string() << std::string() << (void *)0 << true; +} +void tst_LLEmbeddedBrowser::initBrowser() +{ + QFETCH(std::string, application_directory); + QFETCH(std::string, component_directory); + QFETCH(std::string, profile_directory); + QFETCH(void *, native_window_handleCount); + SubLLEmbeddedBrowser browser; + browser.init(application_directory,component_directory,profile_directory,native_window_handleCount); + QCOMPARE(browser.getLastError(), 0); +} + +// public bool reset() +void tst_LLEmbeddedBrowser::reset() +{ + SubLLEmbeddedBrowser browser; + + browser.setLastError(100); + QCOMPARE(browser.getLastError(), 100); + QVERIFY(browser.reset()); + QCOMPARE(browser.getLastError(), 0); + // TODO what should reset really do? +} + +void tst_LLEmbeddedBrowser::setBrowserAgentId_data() +{ + QTest::addColumn("id"); + QTest::newRow("null") << std::string(); + QTest::newRow("valid") << std::string("uBrowser"); + +} + +// public void setBrowserAgentId(std::string id) +void tst_LLEmbeddedBrowser::setBrowserAgentId() +{ + QFETCH(std::string, id); + + SubLLEmbeddedBrowser browser; + browser.reset(); + browser.setBrowserAgentId(id); + LLEmbeddedBrowserWindow *window = browser.createBrowserWindow(0, 0); + Q_UNUSED(window); + // TODO confirm that the page is actually sending the agent ID +} + +void tst_LLEmbeddedBrowser::setLastError_data() +{ + QTest::addColumn("error_number"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("100") << 100; +} + +// public void setLastError(int error_number) +void tst_LLEmbeddedBrowser::setLastError() +{ + QFETCH(int, error_number); + + SubLLEmbeddedBrowser browser; + + browser.setLastError(error_number); + QCOMPARE(browser.getLastError(), error_number); +} + +QTEST_MAIN(tst_LLEmbeddedBrowser) +#include "tst_llembeddedbrowser.moc" + diff --git a/indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro b/indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro new file mode 100644 index 000000000..a89f50065 --- /dev/null +++ b/indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +CONFIG += qtestlib +QT += webkit opengl network + +include(../../llmozlib2.pri) +DEFINES += AUTOTEST + +# Input +SOURCES += tst_llembeddedbrowserwindow.cpp + diff --git a/indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp b/indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp new file mode 100644 index 000000000..4c365d371 --- /dev/null +++ b/indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp @@ -0,0 +1,1027 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include + +#include "llembeddedbrowserwindow.h" +#include "llembeddedbrowser.h" + +#ifndef QTRY_COMPARE + +#define __TRY_TIMEOUT__ 10000 +#define __TRY_STEP__ 50 + +#define __QTRY(__expression__, __functionToCall__) \ + do { \ + int __i = 0; \ + while (!(__expression__) && __i < __TRY_TIMEOUT__) { \ + QTest::qWait(__TRY_STEP__); \ + __i += __TRY_STEP__; \ + } \ + __functionToCall__; \ + } while(0) + +#define QTRY_COMPARE(__expression__, __expected__) \ + __QTRY((__expression__ == __expected__), QCOMPARE(__expression__, __expected__)); + +#define QTRY_VERIFY(__expression__) \ + __QTRY(__expression__, QVERIFY(__expression__)); + +#endif // QTRY_COMPARE + +class tst_LLEmbeddedBrowserWindow : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void llembeddedbrowserwindow_data(); + void llembeddedbrowserwindow(); + + void addObserver_data(); + void addObserver(); + void canNavigateBack_data(); + void canNavigateBack(); + void canNavigateForward_data(); + void canNavigateForward(); + void evaluateJavascript_data(); + void evaluateJavascript(); + void flipWindow_data(); + void flipWindow(); + void focusBrowser_data(); + void focusBrowser(); + void getBrowserDepth_data(); + void getBrowserDepth(); + void getBrowserHeight_data(); + void getBrowserHeight(); + void getBrowserRowSpan_data(); + void getBrowserRowSpan(); + void getBrowserWidth_data(); + void getBrowserWidth(); + void getClickLinkHref_data(); + void getClickLinkHref(); + void getClickLinkTarget_data(); + void getClickLinkTarget(); + void getCurrentUri_data(); + void getCurrentUri(); + void getNoFollowScheme_data(); + void getNoFollowScheme(); + void getPageBuffer_data(); + void getPageBuffer(); + void getPercentComplete_data(); + void getPercentComplete(); + void getStatusMsg_data(); + void getStatusMsg(); + void getWindowId_data(); + void getWindowId(); + void grabWindow_data(); + void grabWindow(); + void keyPress_data(); + void keyPress(); + void mouseDown_data(); + void mouseDown(); + void mouseLeftDoubleClick_data(); + void mouseLeftDoubleClick(); + void mouseMove_data(); + void mouseMove(); + void mouseUp_data(); + void mouseUp(); + void navigateBack_data(); + void navigateBack(); + void navigateForward_data(); + void navigateForward(); + void navigateReload_data(); + void navigateReload(); + void navigateStop_data(); + void navigateStop(); + void navigateTo_data(); + void navigateTo(); + void remObserver_data(); + void remObserver(); + void scrollByLines_data(); + void scrollByLines(); + void setBackgroundColor_data(); + void setBackgroundColor(); + void setCaretColor_data(); + void setCaretColor(); + void setEnabled_data(); + void setEnabled(); + void setNoFollowScheme_data(); + void setNoFollowScheme(); + void setParent_data(); + void setParent(); + void setSize_data(); + void setSize(); + void setWindowId_data(); + void setWindowId(); + void unicodeInput_data(); + void unicodeInput(); +}; + +// Subclass that exposes the protected functions. +class SubLLEmbeddedBrowserWindow : public LLEmbeddedBrowserWindow +{ +public: + +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_LLEmbeddedBrowserWindow::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_LLEmbeddedBrowserWindow::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_LLEmbeddedBrowserWindow::init() +{ +} + +// This will be called after every test function. +void tst_LLEmbeddedBrowserWindow::cleanup() +{ +} + +void tst_LLEmbeddedBrowserWindow::llembeddedbrowserwindow_data() +{ +} + +void tst_LLEmbeddedBrowserWindow::llembeddedbrowserwindow() +{ + SubLLEmbeddedBrowserWindow window; + QCOMPARE(window.addObserver((LLEmbeddedBrowserWindowObserver*)0), false); + QCOMPARE(window.canNavigateBack(), false); + QCOMPARE(window.canNavigateForward(), false); + QCOMPARE(window.evaluateJavascript(std::string()), std::string()); + QCOMPARE(window.flipWindow(false), true); + window.focusBrowser(false); + QCOMPARE(window.getBrowserDepth(), (int16_t)4); + QCOMPARE(window.getBrowserHeight(), (int16_t)0); + QCOMPARE(window.getBrowserRowSpan(), (int32_t)0); + QCOMPARE(window.getBrowserWidth(), (int16_t)0); + QCOMPARE(window.getClickLinkHref(), std::string()); + QCOMPARE(window.getClickLinkTarget(), std::string()); + QCOMPARE(window.getCurrentUri(), std::string()); + QCOMPARE(window.getNoFollowScheme(), std::string("secondlife")); + QCOMPARE(window.getPageBuffer(), (unsigned char*)0); + QCOMPARE(window.getPercentComplete(), (int16_t)0); + QCOMPARE(window.getStatusMsg(), std::string()); + QCOMPARE(window.getWindowId(), -1); + QCOMPARE(window.grabWindow(-1, -1, -1, -1), (unsigned char*)0); + window.keyPress(0); + window.mouseDown(0, 0); + window.mouseLeftDoubleClick(0, 0); + window.mouseMove(0, 0); + window.mouseUp(0, 0); + window.navigateBack(); + window.navigateForward(); + window.navigateReload(); + window.navigateStop(); + QCOMPARE(window.navigateTo(std::string()), true); + QCOMPARE(window.remObserver((LLEmbeddedBrowserWindowObserver*)0), false); + window.scrollByLines(0); + window.setBackgroundColor(0, 0, 0); + window.setCaretColor(0, 0, 0); + window.setEnabled(false); + window.setNoFollowScheme(std::string()); + window.setParent((LLEmbeddedBrowser*)0); + QCOMPARE(window.setSize(0, 0), true); + window.setWindowId(-1); + window.unicodeInput((uint32_t)0); +} + +void tst_LLEmbeddedBrowserWindow::addObserver_data() +{ +#if 0 + QTest::addColumn("observerCount"); + QTest::addColumn("addObserver"); + QTest::newRow("null") << 0 << false; +#endif +} + +// public bool addObserver(LLEmbeddedBrowserWindowObserver* observer) +void tst_LLEmbeddedBrowserWindow::addObserver() +{ +#if 0 + QFETCH(int, observerCount); + QFETCH(bool, addObserver); + + SubLLEmbeddedBrowserWindow window; + + QCOMPARE(window.addObserver(observer), addObserver); +#endif + QSKIP("Test is same with remObserver.", SkipAll); +} + +void tst_LLEmbeddedBrowserWindow::canNavigateBack_data() +{ +#if 0 + QTest::addColumn("canNavigateBack"); + QTest::newRow("true") << true; + QTest::newRow("false") << false; +#endif +} + +// public bool canNavigateBack() +void tst_LLEmbeddedBrowserWindow::canNavigateBack() +{ + //QFETCH(bool, canNavigateForward); + + SubLLEmbeddedBrowserWindow window; + window.setSize(800,600); + window.setParent(new LLEmbeddedBrowser()); + QCOMPARE(window.canNavigateForward(), false); + window.navigateTo(std::string("http://www.google.com")); + QTest::qWait(__TRY_TIMEOUT__); + QCOMPARE(window.canNavigateBack(), false); + window.navigateTo(std::string("http://www.cnn.com")); + QTest::qWait(__TRY_TIMEOUT__); + QCOMPARE(window.canNavigateBack(), true); + window.navigateBack(); + QTRY_COMPARE(window.canNavigateForward(), true); + window.navigateForward(); + QTRY_COMPARE(window.canNavigateBack(), true); +} + +void tst_LLEmbeddedBrowserWindow::canNavigateForward_data() +{ +#if 0 + QTest::addColumn("canNavigateForward"); + QTest::newRow("true") << true; + QTest::newRow("false") << false; +#endif +} + +// public bool canNavigateForward() +void tst_LLEmbeddedBrowserWindow::canNavigateForward() +{ + QSKIP("Test is same with canNavigateBack().", SkipAll); +} + +Q_DECLARE_METATYPE(std::string) +void tst_LLEmbeddedBrowserWindow::evaluateJavascript_data() +{ + QTest::addColumn("script"); + QTest::addColumn("evaluateJavascript"); + QTest::newRow("null") << std::string() << std::string(); + //QTest::newRow("valid") << std::string("alert(\"hey!\")") << std::string("alert(\"hey!\")"); +} + +// public std::string evaluateJavascript(std::string script) +void tst_LLEmbeddedBrowserWindow::evaluateJavascript() +{ + QFETCH(std::string, script); + QFETCH(std::string, evaluateJavascript); + + SubLLEmbeddedBrowserWindow window; + + window.evaluateJavascript(script); +} + +void tst_LLEmbeddedBrowserWindow::flipWindow_data() +{ + QTest::addColumn("flip"); + QTest::addColumn("flipWindow"); + QTest::newRow("false") << false << true; + QTest::newRow("true") << true << true; +} + +// public bool flipWindow(bool flip) +void tst_LLEmbeddedBrowserWindow::flipWindow() +{ + QFETCH(bool, flip); + QFETCH(bool, flipWindow); + + SubLLEmbeddedBrowserWindow window; + + QCOMPARE(window.flipWindow(flip), flipWindow); +} + +void tst_LLEmbeddedBrowserWindow::focusBrowser_data() +{ + QTest::addColumn("focus_browser"); + QTest::newRow("true") << true; + QTest::newRow("false") << false; +} + +// public void focusBrowser(bool focus_browser) +void tst_LLEmbeddedBrowserWindow::focusBrowser() +{ + QFETCH(bool, focus_browser); + + SubLLEmbeddedBrowserWindow window; + window.focusBrowser(focus_browser); +} + +Q_DECLARE_METATYPE(int16_t) +void tst_LLEmbeddedBrowserWindow::getBrowserDepth_data() +{ +#if 0 + QTest::addColumn("getBrowserDepth"); + QTest::newRow("null") << int16_t(); +#endif +} + +// public int16_t getBrowserDepth() +void tst_LLEmbeddedBrowserWindow::getBrowserDepth() +{ + //QFETCH(int16_t, getBrowserDepth); + + SubLLEmbeddedBrowserWindow window; + + QCOMPARE(window.getBrowserDepth(), int16_t(4)); +} + +void tst_LLEmbeddedBrowserWindow::getBrowserHeight_data() +{ +#if 0 + QTest::addColumn("getBrowserHeight"); + QTest::newRow("null") << int16_t(); +#endif +} + +// public int16_t getBrowserHeight() +void tst_LLEmbeddedBrowserWindow::getBrowserHeight() +{ +#if 0 + QFETCH(int16_t, getBrowserHeight); + + SubLLEmbeddedBrowserWindow window; + + QCOMPARE(window.getBrowserHeight(), getBrowserHeight); +#endif + QSKIP("Test is same with setSize().", SkipAll); +} + +Q_DECLARE_METATYPE(int32_t) +void tst_LLEmbeddedBrowserWindow::getBrowserRowSpan_data() +{ +#if 0 + QTest::addColumn("getBrowserRowSpan"); + QTest::newRow("null") << int32_t(); +#endif +} + +// public int32_t getBrowserRowSpan() +void tst_LLEmbeddedBrowserWindow::getBrowserRowSpan() +{ +#if 0 + SubLLEmbeddedBrowserWindow window; + window.setSize(0, 0); + + QCOMPARE(window.getBrowserWidth(), int16_t(0)); + QCOMPARE(window.getBrowserRowSpan(), int32_t(0)); + window.setSize(100, 100); + + QCOMPARE(window.getBrowserWidth(), int16_t(100)); + QCOMPARE(window.getBrowserRowSpan(), int32_t(400)); +#endif + QSKIP("Test is same with setSize().", SkipAll); +} + +void tst_LLEmbeddedBrowserWindow::getBrowserWidth_data() +{ +#if 0 + QTest::addColumn("getBrowserWidth"); + QTest::newRow("null") << int16_t(); +#endif +} + +// public int16_t getBrowserWidth() +void tst_LLEmbeddedBrowserWindow::getBrowserWidth() +{ +#if 0 + //QFETCH(int16_t, getBrowserWidth); + + SubLLEmbeddedBrowserWindow window; + window.setSize(0, 0); + + QCOMPARE(window.getBrowserWidth(), int16_t(0)); + QCOMPARE(window.getBrowserHeight(), int16_t(0)); + window.setSize(100, 100); + + QCOMPARE(window.getBrowserWidth(), int16_t(100)); + QCOMPARE(window.getBrowserHeight(), int16_t(100)); +#endif + QSKIP("Test is same with setSize().", SkipAll); +} + +//Q_DECLARE_METATYPE(std::string const) +void tst_LLEmbeddedBrowserWindow::getClickLinkHref_data() +{ +#if 0 + QTest::addColumn("getClickLinkHref"); + QTest::newRow("null") << std::string const(); +#endif +} + +// public std::string const getClickLinkHref() +void tst_LLEmbeddedBrowserWindow::getClickLinkHref() +{ + //QFETCH(std::string const, getClickLinkHref); + + SubLLEmbeddedBrowserWindow window; + + window.getClickLinkHref(); +} + +void tst_LLEmbeddedBrowserWindow::getClickLinkTarget_data() +{ +#if 0 + QTest::addColumn("getClickLinkTarget"); + QTest::newRow("null") << std::string const(); +#endif +} + +// public std::string const getClickLinkTarget() +void tst_LLEmbeddedBrowserWindow::getClickLinkTarget() +{ + //QFETCH(std::string const, getClickLinkTarget); + + SubLLEmbeddedBrowserWindow window; + + window.getClickLinkTarget(); +} + +void tst_LLEmbeddedBrowserWindow::getCurrentUri_data() +{ +#if 0 + QTest::addColumn("getCurrentUri"); + QTest::newRow("null") << std::string const(); +#endif +} + +// public std::string const getCurrentUri() +void tst_LLEmbeddedBrowserWindow::getCurrentUri() +{ + //QFETCH(std::string const, getCurrentUri); + + SubLLEmbeddedBrowserWindow window; + window.navigateTo(std::string("http://www.google.ca/")); + QTRY_COMPARE(QString::fromStdString(window.getCurrentUri()), QString::fromStdString(std::string("http://www.google.ca/"))); +} + +void tst_LLEmbeddedBrowserWindow::getNoFollowScheme_data() +{ +#if 0 + QTest::addColumn("getNoFollowScheme"); + QTest::newRow("FTP") << std::string("FTP"); +#endif +} + +// public std::string getNoFollowScheme() +void tst_LLEmbeddedBrowserWindow::getNoFollowScheme() +{ + //QFETCH(std::string, getNoFollowScheme); + + SubLLEmbeddedBrowserWindow window; + window.setNoFollowScheme("FTP://www.google.com"); + + QCOMPARE(window.getNoFollowScheme(), std::string("FTP")); +} + +//Q_DECLARE_METATYPE(unsigned char*) +void tst_LLEmbeddedBrowserWindow::getPageBuffer_data() +{ +#if 0 + QTest::addColumn("getPageBuffer"); + QTest::newRow("null") << unsigned char*(); +#endif +} + +// public unsigned char* getPageBuffer() +void tst_LLEmbeddedBrowserWindow::getPageBuffer() +{ + //QFETCH(unsigned char*, getPageBuffer); + + SubLLEmbeddedBrowserWindow window; + window.setSize(100,100); + window.grabWindow(0, 0, 100, 100); + + QVERIFY(window.getPageBuffer() != NULL); +} + +//Q_DECLARE_METATYPE(int16_t const) +void tst_LLEmbeddedBrowserWindow::getPercentComplete_data() +{ +#if 0 + QTest::addColumn("getPercentComplete"); + QTest::newRow("null") << int16_t const(); +#endif +} + +// public int16_t const getPercentComplete() +void tst_LLEmbeddedBrowserWindow::getPercentComplete() +{ + //QFETCH(int16_t const, getPercentComplete); + SubLLEmbeddedBrowserWindow window; + window.navigateTo(std::string("http://www.google.com")); + QTest::qWait(1000); + QVERIFY(window.getPercentComplete() > 0); +} + +void tst_LLEmbeddedBrowserWindow::getStatusMsg_data() +{ +#if 0 + QTest::addColumn("getStatusMsg"); + QTest::newRow("null") << std::string const(); +#endif +} + +// public std::string const getStatusMsg() +void tst_LLEmbeddedBrowserWindow::getStatusMsg() +{ + //QFETCH(std::string const, getStatusMsg); + + SubLLEmbeddedBrowserWindow window; + window.navigateTo(std::string("http://www.google.com")); + QTest::qWait(1000); + window.navigateStop(); + window.navigateTo(std::string("http://www.yahoo.com")); + // Seems status msg will always be null during navigating. + //QTRY_VERIFY(QString::fromStdString(window.getStatusMsg())!= NULL); + QSKIP("Status msg will always be null during navigating", SkipAll); +} + +void tst_LLEmbeddedBrowserWindow::getWindowId_data() +{ +#if 0 + QTest::addColumn("getWindowId"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; +#endif +} + +// public int getWindowId() +void tst_LLEmbeddedBrowserWindow::getWindowId() +{ + //QFETCH(int, getWindowId); + + SubLLEmbeddedBrowserWindow window; + window.setWindowId(0); + QCOMPARE(window.getWindowId(), 0); + window.setWindowId(100); + QCOMPARE(window.getWindowId(), 100); +} + +void tst_LLEmbeddedBrowserWindow::grabWindow_data() +{ +#if 0 + QTest::addColumn("x"); + QTest::addColumn("y"); + QTest::addColumn("width"); + QTest::addColumn("height"); + QTest::addColumn("grabWindow"); + QTest::newRow("null") << 0 << 0 << 0 << 0 << 0; +#endif +} + +// public unsigned char* grabWindow(int x, int y, int width, int height) +void tst_LLEmbeddedBrowserWindow::grabWindow() +{ + QSKIP("Test is same with getPageBuffer().", SkipAll); +} + +void tst_LLEmbeddedBrowserWindow::keyPress_data() +{ + QTest::addColumn("key_code"); + QTest::newRow("null") << int16_t(0); + QTest::newRow("valid") << int16_t(0x0E); +} + +// public void keyPress(int16_t key_code) +void tst_LLEmbeddedBrowserWindow::keyPress() +{ + QFETCH(int16_t, key_code); + + SubLLEmbeddedBrowserWindow window; + window.keyPress(key_code); +} + +void tst_LLEmbeddedBrowserWindow::mouseDown_data() +{ + QTest::addColumn("x"); + QTest::addColumn("y"); + QTest::newRow("0") << int16_t(0) << int16_t(0); + QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); + QTest::newRow("valid") << int16_t(100) << int16_t(100); +} + +// public void mouseDown(int16_t x, int16_t y) +void tst_LLEmbeddedBrowserWindow::mouseDown() +{ + QFETCH(int16_t, x); + QFETCH(int16_t, y); + + SubLLEmbeddedBrowserWindow window; + window.mouseDown(x, y); +} + +void tst_LLEmbeddedBrowserWindow::mouseLeftDoubleClick_data() +{ + QTest::addColumn("x"); + QTest::addColumn("y"); + QTest::newRow("0") << int16_t(0) << int16_t(0); + QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); + QTest::newRow("valid") << int16_t(100) << int16_t(100); +} + +// public void mouseLeftDoubleClick(int16_t x, int16_t y) +void tst_LLEmbeddedBrowserWindow::mouseLeftDoubleClick() +{ + QFETCH(int16_t, x); + QFETCH(int16_t, y); + + SubLLEmbeddedBrowserWindow window; + window.mouseLeftDoubleClick(x, y); +} + +void tst_LLEmbeddedBrowserWindow::mouseMove_data() +{ + QTest::addColumn("x"); + QTest::addColumn("y"); + QTest::newRow("0") << int16_t(0) << int16_t(0); + QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); + QTest::newRow("valid") << int16_t(100) << int16_t(100); +} + +// public void mouseMove(int16_t x, int16_t y) +void tst_LLEmbeddedBrowserWindow::mouseMove() +{ + QFETCH(int16_t, x); + QFETCH(int16_t, y); + + SubLLEmbeddedBrowserWindow window; + window.mouseMove(x, y); +} + +void tst_LLEmbeddedBrowserWindow::mouseUp_data() +{ + QTest::addColumn("x"); + QTest::addColumn("y"); + QTest::newRow("0") << int16_t(0) << int16_t(0); + QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); + QTest::newRow("valid") << int16_t(100) << int16_t(100); +} + +// public void mouseUp(int16_t x, int16_t y) +void tst_LLEmbeddedBrowserWindow::mouseUp() +{ + QFETCH(int16_t, x); + QFETCH(int16_t, y); + + SubLLEmbeddedBrowserWindow window; + window.mouseUp(x, y); +} + +void tst_LLEmbeddedBrowserWindow::navigateBack_data() +{ +#if 0 + QTest::addColumn("foo"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; +#endif +} + +// public void navigateBack() +void tst_LLEmbeddedBrowserWindow::navigateBack() +{ + //QFETCH(int, foo); + + SubLLEmbeddedBrowserWindow window; + window.navigateTo(std::string("http://www.google.ca/")); + QTest::qWait(__TRY_TIMEOUT__); + QCOMPARE(window.canNavigateForward(), false); + window.navigateTo(std::string("http://www.yahoo.com/")); + QTest::qWait(__TRY_TIMEOUT__); + QCOMPARE(window.canNavigateBack(), true); + window.navigateBack(); + QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); + window.navigateBack(); + QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); +} + +void tst_LLEmbeddedBrowserWindow::navigateForward_data() +{ +#if 0 + QTest::addColumn("foo"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; +#endif +} + +// public void navigateForward() +void tst_LLEmbeddedBrowserWindow::navigateForward() +{ + // QFETCH(int, foo); + SubLLEmbeddedBrowserWindow window; + window.navigateTo(std::string("http://www.google.ca/")); + QTest::qWait(__TRY_TIMEOUT__); + QCOMPARE(window.canNavigateForward(), false); + window.navigateTo(std::string("http://www.yahoo.ca/")); + QTest::qWait(__TRY_TIMEOUT__); + QCOMPARE(window.canNavigateBack(), true); + window.navigateBack(); + QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); + window.navigateForward(); + QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://ca.yahoo.com/")); + window.navigateForward(); + QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://ca.yahoo.com/")); +} + +void tst_LLEmbeddedBrowserWindow::navigateReload_data() +{ +#if 0 + QTest::addColumn("foo"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; +#endif +} + +// public void navigateReload() +void tst_LLEmbeddedBrowserWindow::navigateReload() +{ + SubLLEmbeddedBrowserWindow window; + + window.navigateTo(std::string("http://www.google.ca/")); + QTest::qWait(__TRY_TIMEOUT__); + window.navigateReload(); + QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); +} + +void tst_LLEmbeddedBrowserWindow::navigateStop_data() +{ +#if 0 + QTest::addColumn("foo"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; +#endif +} + +// public void navigateStop() +void tst_LLEmbeddedBrowserWindow::navigateStop() +{ + SubLLEmbeddedBrowserWindow window; + window.navigateTo("www.google.com"); + window.navigateStop(); +} + +void tst_LLEmbeddedBrowserWindow::navigateTo_data() +{ + QTest::addColumn("uri"); + QTest::addColumn("navigateTo"); + QTest::newRow("null") << std::string() << std::string(); + QTest::newRow("valid") << std::string("http://www.google.ca/") << std::string("http://www.google.ca/"); +} + +// public bool navigateTo(std::string const uri) +void tst_LLEmbeddedBrowserWindow::navigateTo() +{ + QSKIP("Test is same with navigateBack(), navigateForward().", SkipAll); +} + +void tst_LLEmbeddedBrowserWindow::remObserver_data() +{ +#if 0 + QTest::addColumn("observerCount"); + QTest::addColumn("remObserver"); + QTest::newRow("null") << 0 << false; +#endif +} + +// public bool remObserver(LLEmbeddedBrowserWindowObserver* observer) +void tst_LLEmbeddedBrowserWindow::remObserver() +{ +// QFETCH(int, observerCount); +// QFETCH(bool, remObserver); + + SubLLEmbeddedBrowserWindow window; + LLEmbeddedBrowserWindowObserver* observer = new LLEmbeddedBrowserWindowObserver(); + window.addObserver(observer); + QCOMPARE(window.getObserverNumber(), 1); + window.remObserver(observer); + QCOMPARE(window.getObserverNumber(), 0); +} + +void tst_LLEmbeddedBrowserWindow::scrollByLines_data() +{ + QTest::addColumn("lines"); + QTest::newRow("null") << int16_t(0); + QTest::addColumn("lines"); + QTest::newRow("100") << int16_t(100); +} + +// public void scrollByLines(int16_t lines) +void tst_LLEmbeddedBrowserWindow::scrollByLines() +{ + QFETCH(int16_t, lines); + + SubLLEmbeddedBrowserWindow window; + + window.scrollByLines(lines); +} + +Q_DECLARE_METATYPE(uint8_t) +void tst_LLEmbeddedBrowserWindow::setBackgroundColor_data() +{ + QTest::addColumn("red"); + QTest::addColumn("green"); + QTest::addColumn("blue"); + QTest::newRow("black") << uint8_t(0) << uint8_t(0) << uint8_t(0); + QTest::newRow("red") << uint8_t(255) << uint8_t(0) << uint8_t(0); + QTest::newRow("green") << uint8_t(0) << uint8_t(255) << uint8_t(0); + QTest::newRow("blue") << uint8_t(0) << uint8_t(0) << uint8_t(255); +} + +// public void setBackgroundColor(uint8_t const red, uint8_t const green, uint8_t const blue) +void tst_LLEmbeddedBrowserWindow::setBackgroundColor() +{ + QFETCH(uint8_t, red); + QFETCH(uint8_t, green); + QFETCH(uint8_t, blue); + + SubLLEmbeddedBrowserWindow window; + + window.setBackgroundColor(red, green, blue); +} + +void tst_LLEmbeddedBrowserWindow::setCaretColor_data() +{ + QTest::addColumn("red"); + QTest::addColumn("green"); + QTest::addColumn("blue"); + QTest::newRow("black") << uint8_t(0) << uint8_t(0) << uint8_t(0); + QTest::newRow("red") << uint8_t(255) << uint8_t(0) << uint8_t(0); + QTest::newRow("green") << uint8_t(0) << uint8_t(255) << uint8_t(0); + QTest::newRow("blue") << uint8_t(0) << uint8_t(0) << uint8_t(255); +} + +// public void setCaretColor(uint8_t const red, uint8_t const green, uint8_t const blue) +void tst_LLEmbeddedBrowserWindow::setCaretColor() +{ + QFETCH(uint8_t, red); + QFETCH(uint8_t, green); + QFETCH(uint8_t, blue); + + SubLLEmbeddedBrowserWindow window; + + window.setCaretColor(red, green, blue); +} + +void tst_LLEmbeddedBrowserWindow::setEnabled_data() +{ + QTest::addColumn("enabledIn"); + QTest::newRow("true") << true; + QTest::newRow("false") << false; +} + +// public void setEnabled(bool enabledIn) +void tst_LLEmbeddedBrowserWindow::setEnabled() +{ + QFETCH(bool, enabledIn); + + SubLLEmbeddedBrowserWindow window; + + window.setEnabled(enabledIn); +} + +void tst_LLEmbeddedBrowserWindow::setNoFollowScheme_data() +{ + QTest::addColumn("scheme"); + QTest::addColumn("result"); + QTest::newRow("null") << std::string() << std::string(); + QTest::newRow("valid") << std::string("ftp://www.google.com") << std::string("ftp");; +} + +// public void setNoFollowScheme(std::string scheme) +void tst_LLEmbeddedBrowserWindow::setNoFollowScheme() +{ + QFETCH(std::string, scheme); + QFETCH(std::string, result); + + SubLLEmbeddedBrowserWindow window; + + window.setNoFollowScheme(scheme); + QCOMPARE(window.getNoFollowScheme(), result); +} + +void tst_LLEmbeddedBrowserWindow::setParent_data() +{ +#if 0 + QTest::addColumn("parentCount"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; +#endif +} + +// public void setParent(LLEmbeddedBrowser* parent) +void tst_LLEmbeddedBrowserWindow::setParent() +{ +#if 0 + QFETCH(int, parentCount); + + SubLLEmbeddedBrowserWindow window; + LLEmbeddedBrowser* parent = new LLEmbeddedBrowser(); + + window.setParent(parent); +#endif + QSKIP("Has been tested before.", SkipAll); +} + +void tst_LLEmbeddedBrowserWindow::setSize_data() +{ + QTest::addColumn("width"); + QTest::addColumn("height"); + QTest::addColumn("setSize"); + QTest::newRow("null") << int16_t(0) << int16_t(0) << true; + QTest::newRow("valid") << int16_t(100) << int16_t(200) << true; +} + +// public bool setSize(int16_t width, int16_t height) +void tst_LLEmbeddedBrowserWindow::setSize() +{ + QFETCH(int16_t, width); + QFETCH(int16_t, height); + QFETCH(bool, setSize); + + SubLLEmbeddedBrowserWindow window; + QCOMPARE(window.setSize(width, height), setSize); + window.grabWindow(0, 0, 800, 600); + + QCOMPARE(window.getBrowserWidth(), width); + QCOMPARE(window.getBrowserHeight(), height); + QCOMPARE(window.getBrowserRowSpan(), (int32_t)width * 4); +} + +void tst_LLEmbeddedBrowserWindow::setWindowId_data() +{ + QTest::addColumn("window_id"); + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("100") << 100; +} + +// public void setWindowId(int window_id) +void tst_LLEmbeddedBrowserWindow::setWindowId() +{ + QFETCH(int, window_id); + + SubLLEmbeddedBrowserWindow window; + + window.setWindowId(window_id); + QCOMPARE(window.getWindowId(), window_id); +} + +Q_DECLARE_METATYPE(uint32_t) +void tst_LLEmbeddedBrowserWindow::unicodeInput_data() +{ + QTest::addColumn("unicode_char"); + QTest::newRow("null") << uint32_t(); + QTest::newRow("valid") << uint32_t(54); +} + +// public void unicodeInput(uint32_t unicode_char) +void tst_LLEmbeddedBrowserWindow::unicodeInput() +{ + QFETCH(uint32_t, unicode_char); + + SubLLEmbeddedBrowserWindow window; + + window.unicodeInput(unicode_char); +} + +QTEST_MAIN(tst_LLEmbeddedBrowserWindow) +#include "tst_llembeddedbrowserwindow.moc" + diff --git a/indra/llqtwebkit/llembeddedbrowser.cpp b/indra/llqtwebkit/llembeddedbrowser.cpp new file mode 100644 index 000000000..f38019b9b --- /dev/null +++ b/indra/llqtwebkit/llembeddedbrowser.cpp @@ -0,0 +1,759 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include "llembeddedbrowser.h" + +#include "llembeddedbrowser_p.h" +#include "llembeddedbrowserwindow.h" +#include "llnetworkaccessmanager.h" +#include "llstyle.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// singleton pattern - initialization +LLEmbeddedBrowser* LLEmbeddedBrowser::sInstance = 0; + +LLEmbeddedBrowserPrivate::LLEmbeddedBrowserPrivate() + : mErrorNum(0) + , mNativeWindowHandle(0) + , mNetworkAccessManager(0) + , mApplication(0) +#if QT_VERSION >= 0x040500 + , mDiskCache(0) +#endif + , mNetworkCookieJar(0) + , mHostLanguage( "en" ) + , mIgnoreSSLCertErrors(false) +{ + if (!qApp) + { + static int argc = 0; + static const char* argv[] = {""}; + QApplication::setAttribute(Qt::AA_MacPluginApplication); + QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + + mApplication = new QApplication(argc, (char **)argv); + mApplication->addLibraryPath(qApp->applicationDirPath()); + } + qApp->setStyle(new LLStyle()); + mNetworkAccessManager = new LLNetworkAccessManager(this); +#if LL_DARWIN + // HACK: Qt installs CarbonEvent handlers that steal events from our main event loop. + // This uninstalls them. + // It's not clear whether calling this internal function is really a good idea. It's probably not. + // It does, however, seem to fix at least one problem ( https://jira.secondlife.com/browse/MOZ-12 ). + extern void qt_release_app_proc_handler(); + qt_release_app_proc_handler(); + + // This is defined and exported from qwidget_mac.mm. + // Calling it with false should prevent qwidget from bringing its process to the foreground, such as when bringing up a popup menu. + extern void qt_mac_set_raise_process(bool b); + qt_mac_set_raise_process(false); +#endif +} + +LLEmbeddedBrowserPrivate::~LLEmbeddedBrowserPrivate() +{ + delete mApplication; + delete mNetworkAccessManager; + delete mNetworkCookieJar; +} + + + +LLEmbeddedBrowser::LLEmbeddedBrowser() + : d(new LLEmbeddedBrowserPrivate) + , mPluginsEnabled( false ) + , mJavaScriptEnabled( false ) + , mCookiesEnabled( false ) +{ +} + +LLEmbeddedBrowser::~LLEmbeddedBrowser() +{ + if(d->mNetworkCookieJar) + { + d->mNetworkCookieJar->mBrowser = NULL; + } + + delete d; +} + +LLEmbeddedBrowser* LLEmbeddedBrowser::getInstance() +{ + if (!sInstance) + sInstance = new LLEmbeddedBrowser; + return sInstance; +} + +void LLEmbeddedBrowser::setLastError(int error_number) +{ + d->mErrorNum = error_number; +} + +void LLEmbeddedBrowser::clearLastError() +{ + d->mErrorNum = 0x0000; +} + +int LLEmbeddedBrowser::getLastError() +{ + return d->mErrorNum; +} + +std::string LLEmbeddedBrowser::getGREVersion() +{ + // take the string directly from Qt + return std::string(QT_VERSION_STR); +} + +bool LLEmbeddedBrowser::init(std::string application_directory, + std::string component_directory, + std::string profile_directory, + void* native_window_handle) +{ + Q_UNUSED(application_directory); + Q_UNUSED(component_directory); + Q_UNUSED(native_window_handle); + d->mStorageDirectory = QString::fromStdString(profile_directory); + QWebSettings::setIconDatabasePath(d->mStorageDirectory); + // The gif and jpeg libraries should be installed in component_directory/imageformats/ + QCoreApplication::addLibraryPath(QString::fromStdString(component_directory)); + + // turn on plugins by default + enablePlugins( true ); + + // Until QtWebkit defaults to 16 + QWebSettings::globalSettings()->setFontSize(QWebSettings::DefaultFontSize, 16); + QWebSettings::globalSettings()->setFontSize(QWebSettings::DefaultFixedFontSize, 16); + + + QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true); + QWebSettings::globalSettings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation)); + + // use default text encoding - not sure how this helps right now so commenting out until we + // understand how to use it a little better. + //QWebSettings::globalSettings()->setDefaultTextEncoding ( "" ); + + return reset(); +} + +bool LLEmbeddedBrowser::reset() +{ + foreach(LLEmbeddedBrowserWindow *window, d->windows) + delete window; + d->windows.clear(); + delete d->mNetworkAccessManager; + d->mNetworkAccessManager = new LLNetworkAccessManager(d); +#if QT_VERSION >= 0x040500 + d->mDiskCache = new QNetworkDiskCache(d->mNetworkAccessManager); + d->mDiskCache->setCacheDirectory(d->mStorageDirectory + "/cache"); + if (QLatin1String(qVersion()) != QLatin1String("4.5.1")) + d->mNetworkAccessManager->setCache(d->mDiskCache); +#endif + d->mNetworkCookieJar = new LLNetworkCookieJar(d->mNetworkAccessManager, this); + d->mNetworkAccessManager->setCookieJar(d->mNetworkCookieJar); + clearLastError(); + return true; +} + +bool LLEmbeddedBrowser::clearCache() +{ +#if QT_VERSION >= 0x040500 + if (d->mDiskCache) + { + d->mDiskCache->clear(); + return true; + } +#endif + return false; +} + +bool LLEmbeddedBrowser::enableProxy(bool enabled, std::string host_name, int port) +{ + QNetworkProxy proxy; + if (enabled) + { + proxy.setType(QNetworkProxy::HttpProxy); + QString q_host_name = QString::fromStdString(host_name); + proxy.setHostName(q_host_name); + proxy.setPort(port); + } + d->mNetworkAccessManager->setProxy(proxy); + return true; +} + +bool LLEmbeddedBrowser::clearAllCookies() +{ + if (!d->mNetworkCookieJar) + return false; + d->mNetworkCookieJar->clear(); + return true; +} + +void LLEmbeddedBrowser::setCookies(const std::string &cookies) +{ + if (d->mNetworkCookieJar) + { + d->mNetworkCookieJar->setCookiesFromRawForm(cookies); + } +} + +std::string LLEmbeddedBrowser::getAllCookies() +{ + std::string result; + + if (d->mNetworkCookieJar) + { + result = d->mNetworkCookieJar->getAllCookiesInRawForm(); + } + + return result; +} + +void LLEmbeddedBrowser::enableCookies( bool enabled ) +{ + mCookiesEnabled = enabled; + enableCookiesTransient( mCookiesEnabled ); +} + +void LLEmbeddedBrowser::enableCookiesTransient( bool enabled ) +{ + if ( d->mNetworkCookieJar ) + { + d->mNetworkCookieJar->mAllowCookies = enabled; + } +} + +bool LLEmbeddedBrowser::areCookiesEnabled() +{ + return mCookiesEnabled; +} + +void LLEmbeddedBrowser::enablePlugins( bool enabled ) +{ + mPluginsEnabled = enabled; // record state + enablePluginsTransient( mPluginsEnabled ); +} + +void LLEmbeddedBrowser::enablePluginsTransient( bool enabled ) +{ + QWebSettings* default_settings = QWebSettings::globalSettings(); + default_settings->setAttribute( QWebSettings::PluginsEnabled, enabled ); +} + +bool LLEmbeddedBrowser::arePluginsEnabled() +{ + return mPluginsEnabled; +} + +void LLEmbeddedBrowser::enableJavaScript( bool enabled ) +{ + mJavaScriptEnabled = enabled; // record state + enableJavaScriptTransient( mJavaScriptEnabled ); +} + +void LLEmbeddedBrowser::enableJavaScriptTransient( bool enabled ) +{ + QWebSettings* default_settings = QWebSettings::globalSettings(); + default_settings->setAttribute( QWebSettings::JavascriptEnabled, enabled ); + default_settings->setAttribute( QWebSettings::JavascriptCanOpenWindows, enabled ); +} + +bool LLEmbeddedBrowser::isJavaScriptEnabled() +{ + return mJavaScriptEnabled; +} + +bool LLEmbeddedBrowser::showWebInspector(bool show) +{ + QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, show); + foreach (LLEmbeddedBrowserWindow* window, d->windows) + { + window->showWebInspector(show); + } + return true; +} + +/* + Sets a string that should be addded to the user agent to identify the application +*/ +void LLEmbeddedBrowser::setBrowserAgentId(std::string id) +{ + QCoreApplication::setApplicationName(QString::fromStdString(id)); +} + +// updates value of 'hostLanguage' in JavaScript 'Navigator' obect that +// embedded pages can query to see what language the host app is set to +// IMPORTANT: call this before any windows are created - only gets passed +// to LLWebPage when new window is created +void LLEmbeddedBrowser::setHostLanguage( const std::string& host_language ) +{ + d->mHostLanguage = host_language; +} + +LLEmbeddedBrowserWindow* LLEmbeddedBrowser::createBrowserWindow(int width, int height, const std::string target) +{ + LLEmbeddedBrowserWindow *newWin = new LLEmbeddedBrowserWindow(); + if (newWin) + { + newWin->setSize(width, height); + newWin->setParent(this); + newWin->setHostLanguage(d->mHostLanguage); + clearLastError(); + d->windows.append(newWin); + + if(!target.empty() && (target != "_blank")) + { + newWin->setTarget(target); + } + + return newWin; + } + return 0; +} + +bool LLEmbeddedBrowser::destroyBrowserWindow(LLEmbeddedBrowserWindow* browser_window) +{ + // check if exists in windows list + if (d->windows.removeOne(browser_window)) + { + delete browser_window; + clearLastError(); + return true; + } + return false; +} + +int LLEmbeddedBrowser::getWindowCount() const +{ + return d->windows.size(); +} + +void LLEmbeddedBrowser::pump(int max_milliseconds) +{ +#if 0 + // This USED to be necessary on the mac, but with Qt 4.6 it seems to cause trouble loading some pages, + // and using processEvents() seems to work properly now. + // Leaving this here in case these issues ever come back. + + // On the Mac, calling processEvents hangs the viewer. + // I'm not entirely sure this does everything we need, but it seems to work better, and allows things like animated gifs to work. + qApp->sendPostedEvents(); + qApp->sendPostedEvents(0, QEvent::DeferredDelete); +#else + qApp->processEvents(QEventLoop::AllEvents, max_milliseconds); +#endif +} + +void LLEmbeddedBrowser::cookieChanged(const std::string &cookie, const std::string &url, bool dead) +{ + foreach (LLEmbeddedBrowserWindow* window, d->windows) + { + window->cookieChanged(cookie, url, dead); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLEmbeddedBrowser::setCAFile(const std::string &ca_file) +{ + bool result = false; + //qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "attempting to read certs from file: " << QString::fromStdString(ca_file); + + // Extract the list of certificates from the specified file + QList certs = QSslCertificate::fromPath(QString::fromStdString(ca_file)); + + if(!certs.isEmpty()) + { + //qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "certs read: " << certs; + + // Set the default CA cert for Qt's SSL implementation. + QSslConfiguration config = QSslConfiguration::defaultConfiguration(); + config.setCaCertificates(certs); + QSslConfiguration::setDefaultConfiguration(config); + result = true; + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLEmbeddedBrowser::addCAFile(const std::string &ca_file) +{ + // Enabling this can help diagnose certificate verification issues. + const bool cert_debugging_on = false; + + if ( cert_debugging_on ) + { + //qDebug() << "\n\nLLEmbeddedBrowser::" << __FUNCTION__ << " ------------------- (Before add)"; + QSslCertificate cert; + foreach(cert, QSslSocket::defaultCaCertificates()) + { + //qDebug() << cert.issuerInfo(QSslCertificate::CommonName) << " --- " << cert.subjectInfo(QSslCertificate::CommonName); + } + } + + bool result = false; + //qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "attempting to read certs from file: " << QString::fromStdString(ca_file); + + if ( cert_debugging_on ) + { + //qDebug() << "\n\nLLEmbeddedBrowser::" << __FUNCTION__ << " ------------------- (From CA.pem)"; + QList certs = QSslCertificate::fromPath(QString::fromStdString(ca_file)); + QSslCertificate cert; + foreach(cert, certs) + { + //qDebug() << cert.issuerInfo(QSslCertificate::CommonName) << " --- " << cert.subjectInfo(QSslCertificate::CommonName); + } + } + + result = QSslSocket::addDefaultCaCertificates(QString::fromStdString(ca_file)); + + if ( cert_debugging_on ) + { + //qDebug() << "\n\nLLEmbeddedBrowser::" << __FUNCTION__ << " ------------------- (After add)"; + QSslCertificate cert; + foreach(cert, QSslSocket::defaultCaCertificates()) + { + //qDebug() << cert.issuerInfo(QSslCertificate::CommonName) << " --- " << cert.subjectInfo(QSslCertificate::CommonName); + } + } + + return result; +} + +void LLEmbeddedBrowser::setIgnoreSSLCertErrors(bool ignore) +{ + d->mIgnoreSSLCertErrors = ignore; +} + +bool LLEmbeddedBrowser::getIgnoreSSLCertErrors() +{ + return d->mIgnoreSSLCertErrors; +} + +const std::vector< std::string > LLEmbeddedBrowser::getInstalledCertsList() +{ + std::vector< std::string > cert_list; + + QSslCertificate cert; + foreach(cert, QSslSocket::defaultCaCertificates()) + { + QString cert_info=""; + + QString issuer_info=""; + issuer_info+="C="; + issuer_info+=cert.issuerInfo(QSslCertificate::CountryName); + issuer_info+=", ST="; + issuer_info+=cert.issuerInfo(QSslCertificate::StateOrProvinceName); + issuer_info+=", L="; + issuer_info+=cert.issuerInfo(QSslCertificate::LocalityName); + issuer_info+=", O="; + issuer_info+=cert.issuerInfo(QSslCertificate::Organization); + issuer_info+=", OU="; + issuer_info+=cert.issuerInfo(QSslCertificate::OrganizationalUnitName); + issuer_info+=", CN="; + issuer_info+=cert.issuerInfo(QSslCertificate::CommonName); + cert_info+=issuer_info; + cert_info+="\n"; + + QString subject_info=""; + subject_info+="C="; + subject_info+=cert.subjectInfo(QSslCertificate::CountryName); + subject_info+=", ST="; + subject_info+=cert.subjectInfo(QSslCertificate::StateOrProvinceName); + subject_info+=", L="; + subject_info+=cert.subjectInfo(QSslCertificate::LocalityName); + subject_info+=", O="; + subject_info+=cert.subjectInfo(QSslCertificate::Organization); + subject_info+=", OU="; + subject_info+=cert.subjectInfo(QSslCertificate::OrganizationalUnitName); + subject_info+=", CN="; + subject_info+=cert.subjectInfo(QSslCertificate::CommonName); + cert_info+=subject_info; + cert_info+="\n"; + + cert_info+="Not valid before: "; + cert_info+=cert.effectiveDate().toString(); + cert_info+="\n"; + cert_info+="Not valid after: "; + cert_info+=cert.expiryDate().toString(); + cert_info+="\n"; + + cert_list.push_back( llToStdString(cert_info) ); + } + return cert_list; +} + +// Second Life viewer specific functions +void LLEmbeddedBrowser::setSLObjectEnabled( bool enabled ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setSLObjectEnabled( enabled ); + } +} + +void LLEmbeddedBrowser::setAgentLanguage( const std::string& agent_language ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setAgentLanguage( agent_language ); + } +} + +void LLEmbeddedBrowser::setAgentRegion( const std::string& agent_region ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setAgentRegion( agent_region ); + } +} + +void LLEmbeddedBrowser::setAgentLocation( double x, double y, double z ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setAgentLocation( x, y, z ); + } +} + +void LLEmbeddedBrowser::setAgentGlobalLocation( double x, double y, double z ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setAgentGlobalLocation( x, y, z ); + } +} + +void LLEmbeddedBrowser::setAgentOrientation( double angle ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setAgentOrientation( angle ); + } +} + +void LLEmbeddedBrowser::setAgentMaturity( const std::string& agent_maturity ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setAgentMaturity( agent_maturity ); + } +} + +void LLEmbeddedBrowser::emitLocation() +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->emitLocation(); + } +} + +void LLEmbeddedBrowser::emitMaturity() +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->emitMaturity(); + } +} + +void LLEmbeddedBrowser::emitLanguage() +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->emitLanguage(); + } +} + +void LLEmbeddedBrowser::setPageZoomFactor( double factor ) +{ + foreach ( LLEmbeddedBrowserWindow* window, d->windows ) + { + window->setPageZoomFactor( factor ); + } +} + +void LLEmbeddedBrowser::qtMessageHandler(QtMsgType type, const char *msg) +{ + std::string msg_type(""); + switch (type) + { + case QtDebugMsg: + msg_type="Debug"; + break; + case QtWarningMsg: + msg_type="Warning"; + break; + case QtCriticalMsg: + msg_type="Critical"; + break; + case QtFatalMsg: + msg_type="Fatal"; + break; + }; + + foreach ( LLEmbeddedBrowserWindow* window, sInstance->d->windows ) + { + + window->onQtDebugMessage( std::string( msg ), msg_type); + } +} + +void LLEmbeddedBrowser::enableQtMessageHandler( bool enable ) +{ + if ( enable ) + { + qInstallMsgHandler( qtMessageHandler ); + } + else + { + // remove handler + qInstallMsgHandler(0); + }; +} + +LLNetworkCookieJar::LLNetworkCookieJar(QObject* parent, LLEmbeddedBrowser *browser) + : NetworkCookieJar(parent) + , mAllowCookies(true) + , mBrowser(browser) +{ +} + +LLNetworkCookieJar::~LLNetworkCookieJar() +{ +} + +QList LLNetworkCookieJar::cookiesForUrl(const QUrl& url) const +{ + if (!mAllowCookies) + return QList(); + return NetworkCookieJar::cookiesForUrl(url); +} + +bool LLNetworkCookieJar::setCookiesFromUrl(const QList &cookie_list, const QUrl& url) +{ + if (!mAllowCookies) + return false; + return NetworkCookieJar::setCookiesFromUrl(cookie_list, url); +} + +void LLNetworkCookieJar::onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead) +{ +// qDebug() << "LLNetworkCookieJar::" << __FUNCTION__ << (already_dead?"set dead cookie":"set cookie ") << cookie; + + if(mBrowser) + { + QByteArray cookie_bytes = cookie.toRawForm(QNetworkCookie::Full); + std::string cookie_string(cookie_bytes.data(), cookie_bytes.size()); + std::string url_string = llToStdString(url); + mBrowser->cookieChanged(cookie_string, url_string, already_dead); + } +} + +void LLNetworkCookieJar::clear() +{ + clearCookies(); +} + +void LLNetworkCookieJar::setCookiesFromRawForm(const std::string &cookie_string) +{ + QByteArray cookie_bytearray(cookie_string.data(), cookie_string.size()); + QList cookie_list = QNetworkCookie::parseCookies(cookie_bytearray); + setCookies(cookie_list); +} + +std::string LLNetworkCookieJar::getAllCookiesInRawForm() +{ + std::string result; + + QList cookie_list = allCookies(); + + foreach (const QNetworkCookie &cookie, cookie_list) + { + QByteArray raw_form = cookie.toRawForm(QNetworkCookie::Full); + result.append(raw_form.data(), raw_form.size()); + result.append("\n"); + } + + return result; +} + +#include "llembeddedbrowserwindow_p.h" +#include + +QGraphicsWebView *LLEmbeddedBrowserPrivate::findView(QNetworkReply *reply) +{ + for (int i = 0; i < windows.count(); ++i) + if (windows[i]->d->mView->url() == reply->url()) + return windows[i]->d->mView; + return windows[0]->d->mView; +} + +bool LLEmbeddedBrowserPrivate::authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) +{ + bool result = false; + +// qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "requesting auth for url " << QString::fromStdString(in_url) << ", realm " << QString::fromStdString(in_realm); +// +// qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "window count is " << windows.count(); + + if(windows.count() > 1) + { + qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "WARNING: authRequest called with more than one window, using the first one"; + } + + LLEmbeddedBrowserWindow* window = windows.first(); + + if(window) + { + result = window->authRequest(in_url, in_realm, out_username, out_password); + } + + return result; +} + +bool LLEmbeddedBrowserPrivate::certError(const std::string &in_url, const std::string &in_msg) +{ + bool result = false; + + LLEmbeddedBrowserWindow* window = windows.first(); + if(window) + { + result = window->certError(in_url, in_msg); + } + + return result; +} diff --git a/indra/llqtwebkit/llembeddedbrowser.h b/indra/llqtwebkit/llembeddedbrowser.h new file mode 100644 index 000000000..c21a6b063 --- /dev/null +++ b/indra/llqtwebkit/llembeddedbrowser.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLEMBEDDEDBROWSER_H +#define LLEMBEDDEDBROWSER_H + +#include +#include +#include +#include + +class LLEmbeddedBrowserWindow; +class LLEmbeddedBrowserWindowObserver; + +class LLEmbeddedBrowserPrivate; +class LLEmbeddedBrowser +{ + public: + LLEmbeddedBrowser(); + virtual ~LLEmbeddedBrowser(); + + static LLEmbeddedBrowser* getInstance(); + + bool init(std::string application_directory, + std::string component_directory, + std::string profile_directory, + void* native_window_handle); + bool reset(); + bool clearCache(); + bool enableProxy(bool enabled, std::string host_name, int port); + bool clearAllCookies(); + void setCookies(const std::string &cookies); + std::string getAllCookies(); + + void enableCookies( bool enabled ); + void enableCookiesTransient( bool enabled ); + bool areCookiesEnabled(); + void enablePlugins( bool enabled ); + void enablePluginsTransient( bool enabled ); + bool arePluginsEnabled(); + void enableJavaScript( bool enabled ); + void enableJavaScriptTransient( bool enabled ); + bool isJavaScriptEnabled(); + + bool showWebInspector(bool show); + std::string getGREVersion(); + void setBrowserAgentId(std::string id); + void setHostLanguage( const std::string& host_language ); + LLEmbeddedBrowserWindow* createBrowserWindow(int width, int height, const std::string target); + bool destroyBrowserWindow(LLEmbeddedBrowserWindow* browser_window); + void setLastError(int error_number); + void clearLastError(); + int getLastError(); + int getWindowCount() const; + void pump(int max_milliseconds); + void cookieChanged(const std::string &cookie, const std::string &url, bool dead); + bool setCAFile(const std::string &ca_file); + bool addCAFile(const std::string &ca_file); + void setIgnoreSSLCertErrors(bool ignore); + bool getIgnoreSSLCertErrors(); + const std::vector< std::string > getInstalledCertsList(); + + void enableQtMessageHandler( bool enable ); + + void setPageZoomFactor( double factor ); + + // Second Life specific functions + void setSLObjectEnabled( bool enabled ); + void setAgentLanguage( const std::string& agent_language ); + void setAgentRegion( const std::string& agent_region ); + void setAgentLocation( double x, double y, double z ); + void setAgentGlobalLocation( double x, double y, double z ); + void setAgentOrientation( double angle ); + void setAgentMaturity( const std::string& agent_maturity ); + void emitLocation(); + void emitMaturity(); + void emitLanguage(); + + private: + friend class LLEmbeddedBrowserWindow; + friend class LLEmbeddedBrowserWindowPrivate; + LLEmbeddedBrowserPrivate *d; + bool mPluginsEnabled; + bool mJavaScriptEnabled; + bool mCookiesEnabled; + + static void qtMessageHandler(QtMsgType type, const char *msg); + + static LLEmbeddedBrowser* sInstance; +}; + +#endif // LLEMBEDDEDBROWSER_H + diff --git a/indra/llqtwebkit/llembeddedbrowser_p.h b/indra/llqtwebkit/llembeddedbrowser_p.h new file mode 100644 index 000000000..9f9f9cd02 --- /dev/null +++ b/indra/llqtwebkit/llembeddedbrowser_p.h @@ -0,0 +1,90 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLEMBEDDEDBROWSER_P_H +#define LLEMBEDDEDBROWSER_P_H + +#include +#include +#if QT_VERSION >= 0x040500 +#include +#endif + +#include "networkcookiejar.h" +#include "llembeddedbrowser.h" + +#include + +class LLEmbeddedBrowser; +class LLNetworkCookieJar : public NetworkCookieJar +{ +public: + LLNetworkCookieJar(QObject *parent, LLEmbeddedBrowser *browser); + ~LLNetworkCookieJar(); + + QList cookiesForUrl(const QUrl& url) const; + bool setCookiesFromUrl(const QList &cookie_list, const QUrl& url); + + /*virtual*/ void onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead); + + void clear(); + + void setCookiesFromRawForm(const std::string &cookie_string); + std::string getAllCookiesInRawForm(); + + bool mAllowCookies; + LLEmbeddedBrowser *mBrowser; +}; + +class LLNetworkAccessManager; +class LLEmbeddedBrowserPrivate +{ +public: + LLEmbeddedBrowserPrivate(); + ~LLEmbeddedBrowserPrivate(); + + bool authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password); + bool certError(const std::string &in_url, const std::string &in_msg); + + int mErrorNum; + void* mNativeWindowHandle; + LLNetworkAccessManager *mNetworkAccessManager; + QApplication *mApplication; +#if QT_VERSION >= 0x040500 + QNetworkDiskCache *mDiskCache; +#endif + LLNetworkCookieJar *mNetworkCookieJar; + + QGraphicsWebView *findView(QNetworkReply *); + + QString mStorageDirectory; + QList windows; + + std::string mHostLanguage; + bool mIgnoreSSLCertErrors; +}; + +#endif + diff --git a/indra/llqtwebkit/llembeddedbrowserwindow.cpp b/indra/llqtwebkit/llembeddedbrowserwindow.cpp new file mode 100644 index 000000000..c990d5567 --- /dev/null +++ b/indra/llqtwebkit/llembeddedbrowserwindow.cpp @@ -0,0 +1,1136 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "llembeddedbrowserwindow.h" +#include "llembeddedbrowserwindow_p.h" + +#include "llembeddedbrowser.h" +#include "llembeddedbrowser_p.h" +#include "llnetworkaccessmanager.h" + +#ifdef STATIC_QT + #include + // Enable gif and jpeg plugins, since web pages look pretty bleak without gifs or jpegs. + // Qt 4.7 uses the system gif and jpeg libraries by default, so this is no longer necessary. +// Q_IMPORT_PLUGIN(qgif) +// Q_IMPORT_PLUGIN(qjpeg) +#ifndef LL_LINUX + // Qt also has its own translators for CJK text encodings we need to pull in. + Q_IMPORT_PLUGIN(qcncodecs) + Q_IMPORT_PLUGIN(qjpcodecs) + Q_IMPORT_PLUGIN(qkrcodecs) + Q_IMPORT_PLUGIN(qtwcodecs) +#endif +#endif + +//#define LLEMBEDDEDBROWSER_DEBUG 1 + +#ifdef LLEMBEDDEDBROWSER_DEBUG +#include +#endif + +#if LL_DARWIN || defined(STATIC_QT) + // Don't define qt_sendSpontaneousEvent on the mac -- it causes a multiply-defined symbol. + extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); +#else + #include + bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event) + { + return QCoreApplication::sendSpontaneousEvent(receiver, event); + } +#endif + +LLEmbeddedBrowserWindow::LLEmbeddedBrowserWindow() +{ + d = new LLEmbeddedBrowserWindowPrivate(); + + d->mPage = new LLWebPage; + d->mInspector = new QWebInspector; + d->mInspector->setPage(d->mPage); + d->mPage->window = this; + d->mView = new LLWebView; + d->mPage->webView = d->mView; + d->mView->window = this; + d->mView->setPage(d->mPage); + d->mGraphicsScene = new LLGraphicsScene; + d->mGraphicsScene->window = this; + d->mGraphicsView = new QGraphicsView; + d->mGraphicsScene->addItem(d->mView); + d->mGraphicsView->setScene(d->mGraphicsScene); + d->mGraphicsScene->setStickyFocus(true); + d->mGraphicsView->viewport()->setParent(0); + + mEnableLoadingOverlay = false; +} + +LLEmbeddedBrowserWindow::~LLEmbeddedBrowserWindow() +{ + delete d; +} + +void LLEmbeddedBrowserWindow::setParent(LLEmbeddedBrowser* parent) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << parent; +#endif + d->mParent = parent; + if (parent) + { + d->mPage->setNetworkAccessManager(parent->d->mNetworkAccessManager); + } else + { + d->mPage->setNetworkAccessManager(0); + } +} + +void LLEmbeddedBrowserWindow::showWebInspector(bool show) +{ + if ( d ) + { + if ( d->mInspector ) + { + d->mInspector->setVisible( show ); + } + } +} + +void LLEmbeddedBrowserWindow::enableLoadingOverlay(bool enable) +{ + mEnableLoadingOverlay = enable; +} + +// change the background color that gets used between pages (usually white) +void LLEmbeddedBrowserWindow::setBackgroundColor(const uint8_t red, const uint8_t green, const uint8_t blue) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << red << green << blue; +#endif + d->backgroundColor = QColor(red, green, blue); +} + +// +void LLEmbeddedBrowserWindow::setEnabled(bool enabled) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << enabled; +#endif + d->mEnabled = enabled; +} + +// allow consumers of this class to observe events - add themselves as an observer +bool LLEmbeddedBrowserWindow::addObserver(LLEmbeddedBrowserWindowObserver* observer) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << observer; +#endif + return d->mEventEmitter.addObserver(observer); +} + +// allow consumers of this class to observe events - remove themselves as an observer +bool LLEmbeddedBrowserWindow::remObserver(LLEmbeddedBrowserWindowObserver* observer) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << observer; +#endif + return d->mEventEmitter.remObserver(observer); +} + +int LLEmbeddedBrowserWindow::getObserverNumber() +{ + return d->mEventEmitter.getObserverNumber(); +} + +// used by observers of this class to get the current URI +std::string& LLEmbeddedBrowserWindow::getCurrentUri() +{ + d->mCurrentUri = llToStdString(d->mPage->mainFrame()->url()); + return d->mCurrentUri; +} + +// utility method that is used by observers to retrieve data after an event +int16_t LLEmbeddedBrowserWindow::getPercentComplete() +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return d->mPercentComplete; +} + +// utility method that is used by observers to retrieve data after an event +std::string& LLEmbeddedBrowserWindow::getStatusMsg() +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return d->mStatusText; +} + +// render a page into memory and grab the window +unsigned char* LLEmbeddedBrowserWindow::grabWindow(int x, int y, int width, int height) +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y << width << height; +#endif + // only grab the window if it's enabled + if (!d->mEnabled) + return 0; + + if (!d->mDirty) + return d->mPageBuffer; + + Q_ASSERT(d->mImage.size() == d->mView->size()); + if (!d->mPage->mainFrame()->url().isValid()) + { + d->mImage.fill(d->backgroundColor.value()); + } else + { + QPainter painter(&d->mImage); + + QRectF r(x, y, width, height); + QRect g(0, 0, d->mView->width(), d->mView->height()); + d->mGraphicsView->render(&painter, r, g); + + d->mDirty = false; + + const bool spinner_enabled = false; + if ( spinner_enabled ) + { + const time_t seconds_before_show_overlay = 1; + + if ( mEnableLoadingOverlay && + d->mShowLoadingOverlay && + time(NULL) - d->mTimeLoadStarted >= seconds_before_show_overlay ) + { + painter.setRenderHint(QPainter::Antialiasing);; + + QBrush brush; + QPen pen; + + int size = width; + if ( height < width ) + size = height; + + const int symbol_translucency = 64; // 0=fully trans, 255=opaque + const int symbol_proportion_of_sceen = 8; // (1/8) + const int symbol_diameter = size/(symbol_proportion_of_sceen); + const int symbol_start_line = symbol_diameter*2/3; + const int symbol_end_line = symbol_diameter; + const int symbol_num_segments = 20; + const int symbol_line_width = size/60; + if ( size < 4 ) size = 4; + + QColor background_color(QColor(128,128,128,symbol_translucency)); + brush.setColor(background_color); + brush.setStyle(Qt::SolidPattern); + pen.setColor(background_color); + painter.setPen(pen); + painter.setBrush(brush); + painter.drawRect(0,0,width, height); + + painter.translate(QPoint(width/2, height/2)); + + static int offset=0; + painter.rotate(((qreal)(offset++%(symbol_num_segments))/(qreal)symbol_num_segments)*360.0f); + + for ( int count=0; countmDirty = true; // force dirty so updates happen frequently during load + } + } + + painter.end(); + if (d->mFlipBitmap) + { + d->mImage = d->mImage.mirrored(); + } + d->mImage = d->mImage.rgbSwapped(); + } + + d->mPageBuffer = d->mImage.bits(); + + return d->mPageBuffer; +} + +// return the buffer that contains the rendered page +unsigned char* LLEmbeddedBrowserWindow::getPageBuffer() +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return d->mPageBuffer; +} + +int16_t LLEmbeddedBrowserWindow::getBrowserWidth() +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return d->mImage.width(); +} + +int16_t LLEmbeddedBrowserWindow::getBrowserHeight() +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return d->mImage.height(); +} + +int16_t LLEmbeddedBrowserWindow::getBrowserDepth() +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return 4; +} + +int32_t LLEmbeddedBrowserWindow::getBrowserRowSpan() +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return 4 * getBrowserWidth(); +} + +bool LLEmbeddedBrowserWindow::navigateTo(const std::string uri) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(uri); +#endif + QUrl url = QUrl::fromUserInput(QString::fromStdString(uri)); + + d->mPage->triggerAction(QWebPage::Stop); + d->mPage->mainFrame()->setUrl(url); + d->mPage->mainFrame()->load(url); + return true; +} + +bool LLEmbeddedBrowserWindow::userAction(LLQtWebKit::EUserAction action) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << action; +#endif + bool result = true; + + switch(action) + { + case LLQtWebKit::UA_EDIT_CUT: + d->mPage->triggerAction(QWebPage::Cut); + break; + case LLQtWebKit::UA_EDIT_COPY: + d->mPage->triggerAction(QWebPage::Copy); + break; + case LLQtWebKit::UA_EDIT_PASTE: + d->mPage->triggerAction(QWebPage::Paste); + break; + case LLQtWebKit::UA_NAVIGATE_STOP: + d->mPage->triggerAction(QWebPage::Stop); + break; + case LLQtWebKit::UA_NAVIGATE_BACK: + d->mPage->triggerAction(QWebPage::Back); + break; + case LLQtWebKit::UA_NAVIGATE_FORWARD: + d->mPage->triggerAction(QWebPage::Forward); + break; + case LLQtWebKit::UA_NAVIGATE_RELOAD: + d->mPage->triggerAction(QWebPage::ReloadAndBypassCache); + break; + default: + result = false; + break; + } + + return result; +} + +bool LLEmbeddedBrowserWindow::userActionIsEnabled(LLQtWebKit::EUserAction action) +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << action; +#endif + + bool result; + + switch(action) + { + case LLQtWebKit::UA_EDIT_CUT: + result = d->mPage->action(QWebPage::Cut)->isEnabled(); + break; + case LLQtWebKit::UA_EDIT_COPY: + result = d->mPage->action(QWebPage::Copy)->isEnabled(); + break; + case LLQtWebKit::UA_EDIT_PASTE: + result = d->mPage->action(QWebPage::Paste)->isEnabled(); + break; + case LLQtWebKit::UA_NAVIGATE_STOP: + result = true; + break; + case LLQtWebKit::UA_NAVIGATE_BACK: + result = d->mPage->history()->canGoBack(); + break; + case LLQtWebKit::UA_NAVIGATE_FORWARD: + result = d->mPage->history()->canGoForward(); + break; + case LLQtWebKit::UA_NAVIGATE_RELOAD: + result = true; + break; + default: + result = false; + break; + } + return result; +} + +// set the size of the browser window +bool LLEmbeddedBrowserWindow::setSize(int16_t width, int16_t height) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << width << height; +#endif + d->mPageBuffer = NULL; + d->mImage = QImage(QSize(width, height), QImage::Format_RGB32); + d->mGraphicsView->resize(width, height); + d->mView->resize(width, height); + d->mImage.fill(d->backgroundColor.rgb()); + return true; +} + +bool LLEmbeddedBrowserWindow::flipWindow(bool flip) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << flip; +#endif + d->mFlipBitmap = flip; + return true; +} + +static Qt::KeyboardModifiers convert_modifiers(LLQtWebKit::EKeyboardModifier modifiers) +{ + Qt::KeyboardModifiers result = Qt::NoModifier; + + if(modifiers & LLQtWebKit::KM_MODIFIER_SHIFT) + result |= Qt::ShiftModifier; + + if(modifiers & LLQtWebKit::KM_MODIFIER_CONTROL) + result |= Qt::ControlModifier; + + if(modifiers & LLQtWebKit::KM_MODIFIER_ALT) + result |= Qt::AltModifier; + + if(modifiers & LLQtWebKit::KM_MODIFIER_META) + result |= Qt::MetaModifier; + + return result; +} + +static Qt::MouseButton qt_button_from_button_number(int button) +{ + Qt::MouseButton result; + + switch(button) + { + default: result = Qt::NoButton; break; + case 0: result = Qt::LeftButton; break; + case 1: result = Qt::RightButton; break; + case 2: result = Qt::MidButton; break; + case 3: result = Qt::XButton1; break; + case 4: result = Qt::XButton2; break; + } + + return result; +} + +static QEvent::Type event_from_mouse_event(LLQtWebKit::EMouseEvent mouse_event) +{ + QEvent::Type result; + + switch(mouse_event) + { + default: + result = QEvent::None; + break; + + case LLQtWebKit::ME_MOUSE_MOVE: + result = QEvent::MouseMove; + break; + + case LLQtWebKit::ME_MOUSE_DOWN: + result = QEvent::MouseButtonPress; + break; + + case LLQtWebKit::ME_MOUSE_UP: + result = QEvent::MouseButtonRelease; + break; + + case LLQtWebKit::ME_MOUSE_DOUBLE_CLICK: + result = QEvent::MouseButtonDblClick; + break; + } + + return result; +} + +static QEvent::Type event_from_keyboard_event(LLQtWebKit::EKeyEvent keyboard_event) +{ + QEvent::Type result; + + switch(keyboard_event) + { + default: + result = QEvent::None; + break; + + case LLQtWebKit::KE_KEY_DOWN: + case LLQtWebKit::KE_KEY_REPEAT: + result = QEvent::KeyPress; + break; + + case LLQtWebKit::KE_KEY_UP: + result = QEvent::KeyRelease; + break; + } + + return result; +} + +void LLEmbeddedBrowserWindow::mouseEvent(LLQtWebKit::EMouseEvent mouse_event, int16_t button, int16_t x, int16_t y, LLQtWebKit::EKeyboardModifier modifiers) +{ +#if LLEMBEDDEDBROWSER_DEBUG > 10 + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y; +#endif + + QEvent::Type type = event_from_mouse_event(mouse_event); + Qt::MouseButton qt_button = qt_button_from_button_number(button); + Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); + + if(type == QEvent::MouseMove) + { + // Mouse move events should always use "no button". + qt_button = Qt::NoButton; + } + + // FIXME: should the current button state be updated before or after constructing the event? + switch(type) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + d->mCurrentMouseButtonState |= qt_button; + break; + + case QEvent::MouseButtonRelease: + d->mCurrentMouseButtonState &= ~qt_button; + break; + + default: + break; + } + + QMouseEvent event(type, QPoint(x, y), qt_button, d->mCurrentMouseButtonState, qt_modifiers); + + qt_sendSpontaneousEvent(d->mGraphicsView->viewport(), &event); +} + +void LLEmbeddedBrowserWindow::scrollWheelEvent(int16_t x, int16_t y, int16_t scroll_x, int16_t scroll_y, LLQtWebKit::EKeyboardModifier modifiers) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y; +#endif + + Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); + + if(scroll_y != 0) + { + QWheelEvent event(QPoint(x, y), scroll_y, d->mCurrentMouseButtonState, qt_modifiers, Qt::Vertical); + qApp->sendEvent(d->mGraphicsView->viewport(), &event); + } + + if(scroll_x != 0) + { + QWheelEvent event(QPoint(x, y), scroll_x, d->mCurrentMouseButtonState, qt_modifiers, Qt::Horizontal); + qApp->sendEvent(d->mGraphicsView->viewport(), &event); + } +} + + +// utility methods to set an error message so something else can look at it +void LLEmbeddedBrowserWindow::scrollByLines(int16_t lines) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << lines; +#endif + int currentScrollValue = d->mPage->mainFrame()->scrollBarValue(Qt::Vertical); + d->mPage->mainFrame()->setScrollBarValue(Qt::Vertical, currentScrollValue + lines); +} + +// Send a keyboard event with native event data. +void LLEmbeddedBrowserWindow::keyboardEvent( + LLQtWebKit::EKeyEvent key_event, + uint32_t key_code, + const char *utf8_text, + LLQtWebKit::EKeyboardModifier modifiers, + uint32_t native_scan_code, + uint32_t native_virtual_key, + uint32_t native_modifiers) +{ + QEvent::Type type = event_from_keyboard_event(key_event); + Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); + bool auto_repeat = (key_event == LLQtWebKit::KE_KEY_REPEAT); + QString text = QString::fromUtf8(utf8_text); + + Qt::Key key = Qt::Key_unknown; + + switch (key_code) + { + case LLQtWebKit::KEY_RETURN: key = Qt::Key_Return; break; + case LLQtWebKit::KEY_LEFT: key = Qt::Key_Left; break; + case LLQtWebKit::KEY_RIGHT: key = Qt::Key_Right; break; + case LLQtWebKit::KEY_UP: key = Qt::Key_Up; break; + case LLQtWebKit::KEY_DOWN: key = Qt::Key_Down; break; + case LLQtWebKit::KEY_ESCAPE: key = Qt::Key_Escape; break; + case LLQtWebKit::KEY_BACKSPACE: key = Qt::Key_Backspace; break; + case LLQtWebKit::KEY_DELETE: key = Qt::Key_Delete; break; + case LLQtWebKit::KEY_SHIFT: key = Qt::Key_Shift; break; + case LLQtWebKit::KEY_CONTROL: key = Qt::Key_Control; break; + case LLQtWebKit::KEY_ALT: key = Qt::Key_Alt; break; + case LLQtWebKit::KEY_HOME: key = Qt::Key_Home; break; + case LLQtWebKit::KEY_END: key = Qt::Key_End; break; + case LLQtWebKit::KEY_PAGE_UP: key = Qt::Key_PageUp; break; + case LLQtWebKit::KEY_PAGE_DOWN: key = Qt::Key_PageDown; break; + case LLQtWebKit::KEY_HYPHEN: key = Qt::Key_hyphen; break; + case LLQtWebKit::KEY_EQUALS: key = Qt::Key_Equal; break; + case LLQtWebKit::KEY_INSERT: key = Qt::Key_Insert; break; + case LLQtWebKit::KEY_CAPSLOCK: key = Qt::Key_CapsLock; break; + case LLQtWebKit::KEY_TAB: key = Qt::Key_Tab; break; + case LLQtWebKit::KEY_ADD: key = Qt::Key_Plus; break; + case LLQtWebKit::KEY_SUBTRACT: key = Qt::Key_Minus; break; + case LLQtWebKit::KEY_MULTIPLY: key = Qt::Key_Asterisk; break; + case LLQtWebKit::KEY_DIVIDE: key = Qt::Key_Slash; break; + case LLQtWebKit::KEY_F1: key = Qt::Key_F1; break; + case LLQtWebKit::KEY_F2: key = Qt::Key_F2; break; + case LLQtWebKit::KEY_F3: key = Qt::Key_F3; break; + case LLQtWebKit::KEY_F4: key = Qt::Key_F4; break; + case LLQtWebKit::KEY_F5: key = Qt::Key_F5; break; + case LLQtWebKit::KEY_F6: key = Qt::Key_F6; break; + case LLQtWebKit::KEY_F7: key = Qt::Key_F7; break; + case LLQtWebKit::KEY_F8: key = Qt::Key_F8; break; + case LLQtWebKit::KEY_F9: key = Qt::Key_F9; break; + case LLQtWebKit::KEY_F10: key = Qt::Key_F10; break; + case LLQtWebKit::KEY_F11: key = Qt::Key_F11; break; + case LLQtWebKit::KEY_F12: key = Qt::Key_F12; break; + + case LLQtWebKit::KEY_PAD_UP: key = Qt::Key_Up; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_DOWN: key = Qt::Key_Down; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_LEFT: key = Qt::Key_Left; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_RIGHT: key = Qt::Key_Right; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_HOME: key = Qt::Key_Home; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_END: key = Qt::Key_End; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_PGUP: key = Qt::Key_PageUp; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_PGDN: key = Qt::Key_PageDown; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_CENTER: key = Qt::Key_5; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_INS: key = Qt::Key_Insert; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_DEL: key = Qt::Key_Delete; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_RETURN: key = Qt::Key_Enter; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_ADD: key = Qt::Key_Plus; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_SUBTRACT: key = Qt::Key_Minus; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_MULTIPLY: key = Qt::Key_Asterisk; qt_modifiers |= Qt::KeypadModifier; break; + case LLQtWebKit::KEY_PAD_DIVIDE: key = Qt::Key_Slash; qt_modifiers |= Qt::KeypadModifier; break; + + case LLQtWebKit::KEY_NONE: key = Qt::Key_unknown; break; + + default: + key = (Qt::Key)toupper(key_code); + break; + } + + + QKeyEvent *event = + QKeyEvent::createExtendedKeyEvent( + type, + key, + qt_modifiers, + native_scan_code, + native_virtual_key, + native_modifiers, + text, + auto_repeat, + text.count()); + + qApp->sendEvent(d->mGraphicsScene, event); + + delete event; +} + + +// give focus to the browser so that input keyboard events work +void LLEmbeddedBrowserWindow::focusBrowser(bool focus_browser) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << focus_browser; +#endif + QEvent ev(QEvent::WindowActivate); + qApp->sendEvent(d->mGraphicsScene, &ev); + + QEvent ev2(QEvent::ActivationChange); + qApp->sendEvent(d->mGraphicsScene, &ev2); + + QFocusEvent event(focus_browser ? QEvent::FocusIn : QEvent::FocusOut, Qt::ActiveWindowFocusReason); + qApp->sendEvent(d->mPage, &event); +} + +void LLEmbeddedBrowserWindow::setWindowId(int window_id) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << window_id; +#endif + d->mWindowId = window_id; +} + +int LLEmbeddedBrowserWindow::getWindowId() +{ + return d->mWindowId; +} + +void LLEmbeddedBrowserWindow::proxyWindowOpened(const std::string target, const std::string uuid) +{ + LLWebPageOpenShim *shim = findShim(uuid); + if(!shim) + { + // We don't already have a shim with this uuid -- create one. + shim = new LLWebPageOpenShim(this, d->mPage); + d->mProxyPages.push_back(shim); + +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow::proxyWindowOpened: page list size is " << d->mProxyPages.size(); +#endif + } + + shim->setProxy(target, uuid); +} + +void LLEmbeddedBrowserWindow::proxyWindowClosed(const std::string uuid) +{ + LLWebPageOpenShim *shim = findShim(uuid); + if(shim) + { + deleteShim(shim); + } +} + +std::string LLEmbeddedBrowserWindow::evaluateJavaScript(std::string script) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(script); +#endif + QString q_script = QString::fromStdString(script); + QString result = d->mPage->mainFrame()->evaluateJavaScript(q_script).toString(); + return llToStdString(result); +} + +void LLEmbeddedBrowserWindow::setHostLanguage(const std::string host_language) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(host_language); +#endif + if ( d ) + if ( d->mPage ) + d->mPage->setHostLanguage( host_language ); +} + +void LLEmbeddedBrowserWindow::navigateErrorPage( int http_status_code ) +{ + LLEmbeddedBrowserWindowEvent event(getWindowId()); + event.setIntValue( http_status_code ); + + d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateErrorPage, event); +} + +void LLEmbeddedBrowserWindow::setNoFollowScheme(std::string scheme) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(scheme); +#endif + d->mNoFollowScheme = QString::fromStdString(scheme); + // The scheme part of the url is what is before '://' + d->mNoFollowScheme = d->mNoFollowScheme.mid(0, d->mNoFollowScheme.indexOf("://")); +} + +std::string LLEmbeddedBrowserWindow::getNoFollowScheme() +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; +#endif + return llToStdString(d->mNoFollowScheme); +} + +void LLEmbeddedBrowserWindow::prependHistoryUrl(std::string url) +{ +#ifdef WEBHISTORYPATCH + // *HACK: we only have a URL here, we set a "" title and "current time" as + // last visited time. + d->mPage->history()->prependItem(QString::fromStdString(url), + QString::fromAscii(""), + QDateTime::currentDateTime()); +#else + Q_UNUSED(url); +#endif +} + +void LLEmbeddedBrowserWindow::clearHistory() +{ + d->mPage->history()->clear(); +} + +std::string LLEmbeddedBrowserWindow::dumpHistory() +{ + std::ostringstream oss; + const QList &items = d->mPage->history()->backItems(9999); + oss << "cur: " << d->mPage->history()->currentItemIndex() << ":" + << d->mPage->history()->currentItem().url().toString().toAscii().data() << "\n"; + for (int i=0; i< items.count(); i++) { + oss << items[i].url().toString().toAscii().data() << "\n"; + } + return oss.str(); +} + +void LLEmbeddedBrowserWindow::cookieChanged(const std::string &cookie, const std::string &url, bool dead) +{ + LLEmbeddedBrowserWindowEvent event(getWindowId()); + event.setEventUri(url); + event.setStringValue(cookie); + event.setIntValue((int)dead); + + d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onCookieChanged, event); +} + +QWebPage *LLEmbeddedBrowserWindow::createWindow() +{ + QWebPage *result = NULL; + if(d->mOpeningSelf) + { + // Special case: opening self to set target, etc. +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow::createWindow: opening self to set target name. "; +#endif + result = d->mPage; + d->mOpeningSelf = false; + } + else + { + LLWebPageOpenShim *shim = new LLWebPageOpenShim(this, d->mPage); + d->mProxyPages.push_back(shim); + result = shim; + +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow::createWindow: page list size is " << d->mProxyPages.size(); +#endif + } + + return result; +} + +LLWebPageOpenShim *LLEmbeddedBrowserWindow::findShim(const std::string &uuid) +{ + LLEmbeddedBrowserWindowPrivate::ProxyList::iterator iter; + for(iter = d->mProxyPages.begin(); iter != d->mProxyPages.end(); iter++) + { + if((*iter)->matchesUUID(uuid)) + return *iter; + } + + return NULL; +} + +void LLEmbeddedBrowserWindow::deleteShim(LLWebPageOpenShim *shim) +{ + shim->window = 0; + shim->deleteLater(); + d->mProxyPages.remove(shim); + +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow::deleteShim: page list size is " << d->mProxyPages.size(); +#endif +} + +void LLEmbeddedBrowserWindow::setTarget(const std::string &target) +{ +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow::setTarget: setting target to " << QString::fromStdString(target); +#endif + + d->mOpeningSelf = true; + + std::stringstream s; + s << "window.open(\"\",\"" << target << "\");"; + + evaluateJavaScript(s.str()); +} + +std::string LLEmbeddedBrowserWindow::requestFilePicker() +{ + std::string filename_chosen; + + LLEmbeddedBrowserWindowEvent event(getWindowId()); + event.setEventUri(getCurrentUri()); + event.setStringValue("*.png;*.jpg"); + + // If there's at least one observer registered, call it with the event. + LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); + if(i != d->mEventEmitter.end()) + { + filename_chosen = (*i)->onRequestFilePicker(event); + } + + return filename_chosen; +} + +bool LLEmbeddedBrowserWindow::authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) +{ + bool result = false; + +#ifdef LLEMBEDDEDBROWSER_DEBUG + qDebug() << "LLEmbeddedBrowserWindow::authRequest: requesting auth for url " << QString::fromStdString(in_url) << ", realm " << QString::fromStdString(in_realm); +#endif + + // If there's at least one observer registered, send it the auth request. + LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); + if(i != d->mEventEmitter.end()) + { + result = (*i)->onAuthRequest(in_url, in_realm, out_username, out_password); + } + + return result; +} + +bool LLEmbeddedBrowserWindow::certError(const std::string &in_url, const std::string &in_msg) +{ + bool result = false; + + // If there's at least one observer registered, send it the auth request. + LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); + if(i != d->mEventEmitter.end()) + { + result = (*i)->onCertError(in_url, in_msg); + } + + return result; +} + +void LLEmbeddedBrowserWindow::onQtDebugMessage( const std::string& msg, const std::string& msg_type) +{ + // If there's at least one observer registered, send it the auth request. + LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); + if(i != d->mEventEmitter.end()) + { + (*i)->onQtDebugMessage(msg, msg_type); + } +} + +void LLEmbeddedBrowserWindow::setWhiteListRegex( const std::string& regex ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setWhiteListRegex( regex ); +} + +// Second Life viewer specific functions +void LLEmbeddedBrowserWindow::setSLObjectEnabled( bool enabled ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setSLObjectEnabled( enabled ); +} + +void LLEmbeddedBrowserWindow::setAgentLanguage( const std::string& agent_language ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setAgentLanguage( agent_language ); +} + +void LLEmbeddedBrowserWindow::setAgentRegion( const std::string& agent_region ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setAgentRegion( agent_region ); +} + +void LLEmbeddedBrowserWindow::setAgentLocation( double x, double y, double z ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setAgentLocation( x, y, z ); +} + +void LLEmbeddedBrowserWindow::setAgentGlobalLocation( double x, double y, double z ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setAgentGlobalLocation( x, y, z ); +} + +void LLEmbeddedBrowserWindow::setAgentOrientation( double angle ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setAgentOrientation( angle ); +} + +void LLEmbeddedBrowserWindow::setAgentMaturity( const std::string& agent_maturity ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setAgentMaturity( agent_maturity ); +} + +void LLEmbeddedBrowserWindow::emitLocation() +{ + if ( d ) + if ( d->mPage ) + d->mPage->emitLocation(); +} + +void LLEmbeddedBrowserWindow::emitMaturity() +{ + if ( d ) + if ( d->mPage ) + d->mPage->emitMaturity(); +} + +void LLEmbeddedBrowserWindow::emitLanguage() +{ + if ( d ) + if ( d->mPage ) + d->mPage->emitLanguage(); +} + +void LLEmbeddedBrowserWindow::setPageZoomFactor( double factor ) +{ + if ( d ) + if ( d->mPage ) + d->mPage->setPageZoomFactor( factor ); +} + +LLGraphicsScene::LLGraphicsScene() + : QGraphicsScene() + , window(0) +{ + connect(this, SIGNAL(changed(const QList &)), + this, SLOT(repaintRequestedSlot(const QList &))); +} + +void LLGraphicsScene::repaintRequestedSlot(const QList ®ions) +{ + if (!window) + return; + window->d->mDirty = true; + for (int i = 0; i < regions.count(); ++i) + { + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + event.setRectValue(regions[i].x(), regions[i].y(), regions[i].width(), regions[i].height()); + + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); + } +} + +#include +#include +LLWebView::LLWebView(QGraphicsItem *parent) + : QGraphicsWebView(parent) + , window(0) +{ +} + +bool LLWebView::event(QEvent* event) +{ + if (window && event->type() == QEvent::CursorChange) { + QCursor cursor = this->cursor(); + if (currentShape != cursor.shape()) { + currentShape = cursor.shape(); + LLQtWebKit::ECursor llcursor; + switch(currentShape) + { + case Qt::ArrowCursor: + llcursor = LLQtWebKit::C_ARROW; + break; + case Qt::PointingHandCursor: + llcursor = LLQtWebKit::C_POINTINGHAND; + break; + case Qt::IBeamCursor: + llcursor = LLQtWebKit::C_IBEAM; + break; + case Qt::SplitVCursor: + llcursor = LLQtWebKit::C_SPLITV; + break; + case Qt::SplitHCursor: + llcursor = LLQtWebKit::C_SPLITH; + break; + default: + qWarning() << "Unhandled cursor shape:" << currentShape; + llcursor = LLQtWebKit::C_ARROW; + } + + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + event.setIntValue((int)llcursor); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onCursorChanged, event); + } + + return true; + } + return QGraphicsWebView::event(event); +} + + +std::string llToStdString(const QString &s) +{ + return llToStdString(s.toUtf8()); +} + +std::string llToStdString(const QByteArray &bytes) +{ + return std::string(bytes.constData(), bytes.size()); +} + +std::string llToStdString(const QUrl &url) +{ + return llToStdString(url.toEncoded()); +} diff --git a/indra/llqtwebkit/llembeddedbrowserwindow.h b/indra/llqtwebkit/llembeddedbrowserwindow.h new file mode 100644 index 000000000..0c8080c15 --- /dev/null +++ b/indra/llqtwebkit/llembeddedbrowserwindow.h @@ -0,0 +1,185 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLEMBEDDEDBROWSERWINDOW_H +#define LLEMBEDDEDBROWSERWINDOW_H + +#include +#include +#include +#if defined _MSC_VER && _MSC_VER < 1600 +#include "pstdint.h" +#else +#include // Use the C99 official header +#endif + +#include "llqtwebkit.h" + +class LLEmbeddedBrowser; +class LLWebPageOpenShim; +class QWebPage; + +//////////////////////////////////////////////////////////////////////////////// +// class for a "window" that holds a browser - there can be lots of these +class LLEmbeddedBrowserWindowPrivate; +class LLEmbeddedBrowserWindow +{ +public: + LLEmbeddedBrowserWindow(); + virtual ~LLEmbeddedBrowserWindow(); + + // housekeeping + void setParent(LLEmbeddedBrowser* parent); + bool setSize(int16_t width, int16_t height); + void focusBrowser(bool focus_browser); + void scrollByLines(int16_t lines); + void setWindowId(int window_id); + int getWindowId(); + void proxyWindowOpened(const std::string target, const std::string uuid); + void proxyWindowClosed(const std::string uuid); + + // random accessors + int16_t getPercentComplete(); + std::string& getStatusMsg(); + std::string& getCurrentUri(); + + // memory buffer management + unsigned char* grabWindow(int x, int y, int width, int height); + bool flipWindow(bool flip); + unsigned char* getPageBuffer(); + int16_t getBrowserWidth(); + int16_t getBrowserHeight(); + int16_t getBrowserDepth(); + int32_t getBrowserRowSpan(); + + // set background color that you see in between pages - default is white but sometimes useful to change + void setBackgroundColor(const uint8_t red, const uint8_t green, const uint8_t blue); + + // can turn off updates to a page - e.g. when it's hidden by your windowing system + void setEnabled(bool enabledIn); + + // navigation + bool userAction(LLQtWebKit::EUserAction action); + bool userActionIsEnabled(LLQtWebKit::EUserAction action); + bool navigateTo(const std::string uri); + + // javascript access/control + std::string evaluateJavaScript(std::string script); + + // redirection when you hit an error page + void navigateErrorPage( int http_status_code ); + + // host language setting + void setHostLanguage(const std::string host_language); + + // mouse & keyboard events + void mouseEvent(LLQtWebKit::EMouseEvent mouse_event, int16_t button, int16_t x, int16_t y, LLQtWebKit::EKeyboardModifier modifiers); + void scrollWheelEvent(int16_t x, int16_t y, int16_t scroll_x, int16_t scroll_y, LLQtWebKit::EKeyboardModifier modifiers); + void keyboardEvent( + LLQtWebKit::EKeyEvent key_event, + uint32_t key_code, + const char *utf8_text, + LLQtWebKit::EKeyboardModifier modifiers, + uint32_t native_scan_code, + uint32_t native_virtual_key, + uint32_t native_modifiers); + + // allow consumers of this class and to observe browser events + bool addObserver(LLEmbeddedBrowserWindowObserver* observer); + bool remObserver(LLEmbeddedBrowserWindowObserver* observer); + int getObserverNumber(); + + // accessor/mutator for scheme that browser doesn't follow - e.g. secondlife.com:// + void setNoFollowScheme(std::string scheme); + std::string getNoFollowScheme(); + + // prepend the current history with the given url + void prependHistoryUrl(std::string url); + // clear the URL history + void clearHistory(); + std::string dumpHistory(); + + void cookieChanged(const std::string &cookie, const std::string &url, bool dead); + + QWebPage *createWindow(); + + LLWebPageOpenShim *findShim(const std::string &uuid); + void deleteShim(LLWebPageOpenShim *shim); + void setTarget(const std::string &target); + + std::string requestFilePicker(); + + void showWebInspector(bool enabled); + + bool authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password); + bool certError(const std::string &in_url, const std::string &in_msg); + + void onQtDebugMessage( const std::string& msg, const std::string& msg_type); + + void enableLoadingOverlay(bool enable); + + void setWhiteListRegex( const std::string& regex ); + + void setPageZoomFactor( double factor ); + + // Second Life specific functions + void setSLObjectEnabled( bool enabled ); + void setAgentLanguage( const std::string& agent_language ); + void setAgentRegion( const std::string& agent_region ); + void setAgentLocation( double x, double y, double z ); + void setAgentGlobalLocation( double x, double y, double z ); + void setAgentOrientation( double angle ); + void setAgentMaturity( const std::string& agent_maturity ); + void emitLocation(); + void emitMaturity(); + void emitLanguage(); + +private: + friend class LLWebPage; + friend class LLWebPageOpenShim; + friend class LLGraphicsScene; + friend class LLWebView; + friend class LLEmbeddedBrowserPrivate; + LLEmbeddedBrowserWindowPrivate *d; + bool mEnableLoadingOverlay; + +}; + + +// QString::toStdString converts to ascii, not utf8. Define our own versions that do utf8. + +#ifdef QSTRING_H +std::string llToStdString(const QString &s); +#endif + +#ifdef QBYTEARRAY_H +std::string llToStdString(const QByteArray &bytes); +#endif + +#ifdef QURL_H +std::string llToStdString(const QUrl &url); +#endif + +#endif // LLEMBEDEDDBROWSERWINDOW_H diff --git a/indra/llqtwebkit/llembeddedbrowserwindow_p.h b/indra/llqtwebkit/llembeddedbrowserwindow_p.h new file mode 100644 index 000000000..27b36d947 --- /dev/null +++ b/indra/llqtwebkit/llembeddedbrowserwindow_p.h @@ -0,0 +1,251 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLEMBEDDEDBROWSERWINDOW_P_H +#define LLEMBEDDEDBROWSERWINDOW_P_H + +#include "llwebpage.h" +#include "llwebpageopenshim.h" + +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// manages the process of storing and emitting events that the consumer +// of the embedding class can observe +template< class T > +class LLEmbeddedBrowserWindowEmitter +{ + public: + LLEmbeddedBrowserWindowEmitter() { }; + ~LLEmbeddedBrowserWindowEmitter() { }; + + typedef typename T::EventType EventType; + typedef std::list< T* > ObserverContainer; + typedef typename ObserverContainer::iterator iterator; + typedef void(T::*observerMethod)(const EventType&); + + /////////////////////////////////////////////////////////////////////////////// + // + bool addObserver(T* observer) + { + if (! observer) + return false; + + if (std::find(observers.begin(), observers.end(), observer) != observers.end()) + return false; + + observers.push_back(observer); + + return true; + } + + /////////////////////////////////////////////////////////////////////////////// + // + bool remObserver(T* observer) + { + if (! observer) + return false; + + observers.remove(observer); + + return true; + } + + /////////////////////////////////////////////////////////////////////////////// + // + void update(observerMethod method, const EventType& msg) + { + typename std::list< T* >::iterator iter = observers.begin(); + + while(iter != observers.end()) + { + ((*iter)->*method)(msg); + ++iter; + } + } + + int getObserverNumber() + { + return observers.size(); + } + + iterator begin() + { + return observers.begin(); + } + + iterator end() + { + return observers.end(); + } + + protected: + ObserverContainer observers; +}; + +#include "llqtwebkit.h" +#include "llembeddedbrowserwindow.h" +#include +#include + +class LLGraphicsScene : public QGraphicsScene +{ + Q_OBJECT + +public: + LLGraphicsScene(); + LLEmbeddedBrowserWindow *window; + + void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) { + QGraphicsScene::mouseMoveEvent(mouseEvent); + mouseEvent->setAccepted(true); + mouseEvent->setButtons(Qt::LeftButton); + } + +private slots: + void repaintRequestedSlot(const QList &); + friend class LLEmbeddedBrowserWindow; +}; + + +class LLWebView : public QGraphicsWebView +{ + Q_OBJECT + +public: + LLWebView(QGraphicsItem *parent = 0); + LLEmbeddedBrowserWindow *window; + + static QUrl guessUrlFromString(const QString &string); + + int width() const { return boundingRect().width(); } + int height() const { return boundingRect().height(); } + +protected: + bool event(QEvent *event); + + Qt::CursorShape currentShape; +}; + +class LLEmbeddedBrowserWindowPrivate +{ + public: + LLEmbeddedBrowserWindowPrivate() + : mParent(0) + , mPage(0) + , mView(0) + , mGraphicsScene(0) + , mGraphicsView(0) + , mInspector(0) + , mCurrentMouseButtonState(Qt::NoButton) + , mPercentComplete(0) + , mShowLoadingOverlay(false) + , mTimeLoadStarted(0) + , mStatusText("") + , mTitle("") + , mCurrentUri("") + , mNoFollowScheme("secondlife") + , mWindowId(-1) + , mEnabled(true) + , mFlipBitmap(false) + , mPageBuffer(NULL) + , mDirty(false) + , mOpeningSelf(false) + { + } + + ~LLEmbeddedBrowserWindowPrivate() + { + while(!mProxyPages.empty()) + { + ProxyList::iterator iter = mProxyPages.begin(); + (*iter)->window = 0; + (*iter)->deleteLater(); + } + + if(mGraphicsScene) + { + mGraphicsScene->window = 0; + } + if(mPage) + { + mPage->window = 0; + } + if(mView) + { + mView->deleteLater(); + } + if(mGraphicsScene) + { + mGraphicsScene->deleteLater(); + } + if(mGraphicsView) + { + mGraphicsView->viewport()->setParent(mGraphicsView); + mGraphicsView->deleteLater(); + } + if(mInspector) + { + mInspector->deleteLater(); + } + } + + typedef LLEmbeddedBrowserWindowEmitter< LLEmbeddedBrowserWindowObserver> Emitter; + Emitter mEventEmitter; + QImage mImage; + LLEmbeddedBrowser *mParent; + LLWebPage *mPage; + typedef std::list ProxyList; + ProxyList mProxyPages; + + LLWebView *mView; + QWebInspector* mInspector; + LLGraphicsScene *mGraphicsScene; + QGraphicsView *mGraphicsView; + Qt::MouseButtons mCurrentMouseButtonState; + + int16_t mPercentComplete; + bool mShowLoadingOverlay; + time_t mTimeLoadStarted; + std::string mStatusText; + std::string mTitle; + std::string mCurrentUri; + QString mNoFollowScheme; + int mWindowId; + bool mEnabled; + bool mFlipBitmap; + unsigned char* mPageBuffer; + QColor backgroundColor; + bool mDirty; + bool mOpeningSelf; +}; + + +#endif + diff --git a/indra/llqtwebkit/lljsobject.cpp b/indra/llqtwebkit/lljsobject.cpp new file mode 100644 index 000000000..f5abfa702 --- /dev/null +++ b/indra/llqtwebkit/lljsobject.cpp @@ -0,0 +1,153 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include "lljsobject.h" + +LLJsObject::LLJsObject( QObject* parent ) : + QObject( parent ) +{ + mEnabled = false; + + mAgentLanguage = QString(); + mAgentMaturity = QString(); + mAgentRegion = QString(); + + mAgentLocation[ "x" ] = 0.0; + mAgentLocation[ "y" ] = 0.0; + mAgentLocation[ "z" ] = 0.0; + + mAgentGlobalLocation[ "x" ] = 0.0; + mAgentGlobalLocation[ "y" ] = 0.0; + mAgentGlobalLocation[ "z" ] = 0.0; +} + +void LLJsObject::setSLObjectEnabled( bool enabled ) +{ + mEnabled = enabled; +} + +bool LLJsObject::getSLObjectEnabled() +{ + return mEnabled; +} + +void LLJsObject::setAgentLanguage( const QString& agent_language ) +{ + if ( mEnabled ) + { + mAgentLanguage = agent_language; + } + else + { + mAgentLanguage = QString(); + } +} + +void LLJsObject::setAgentRegion( const QString& agent_region ) +{ + if ( mEnabled ) + { + mAgentRegion = agent_region; + } + else + { + mAgentRegion = QString(); + } +} + +void LLJsObject::setAgentMaturity( const QString& agent_maturity ) +{ + if ( mEnabled ) + { + mAgentMaturity = agent_maturity; + } + else + { + mAgentMaturity = QString(); + } +} + +void LLJsObject::setAgentLocation( const QVariantMap agent_location ) +{ + if ( mEnabled ) + { + mAgentLocation = agent_location; + } + else + { + mAgentLocation[ "x" ] = 0.0; + mAgentLocation[ "y" ] = 0.0; + mAgentLocation[ "z" ] = 0.0; + } +} + +void LLJsObject::setAgentGlobalLocation( const QVariantMap agent_global_location ) +{ + if ( mEnabled ) + { + mAgentGlobalLocation = agent_global_location; + } + else + { + mAgentGlobalLocation[ "x" ] = 0.0; + mAgentGlobalLocation[ "y" ] = 0.0; + mAgentGlobalLocation[ "z" ] = 0.0; + } +} + +void LLJsObject::setAgentOrientation( const double angle ) +{ + if ( mEnabled ) + { + mAgentOrientation = angle; + } + else + { + mAgentOrientation = 0.0; + } +} + +void LLJsObject::emitLocation() +{ + QVariantMap agent_location; + + agent_location[ "region" ] = mAgentRegion; + agent_location[ "location" ] = mAgentLocation; + agent_location[ "orientation" ] = mAgentOrientation; + agent_location[ "globalLocation" ] = mAgentGlobalLocation; + + emit getLocation( agent_location ); +} + +void LLJsObject::emitMaturity() +{ + emit getMaturity( mAgentMaturity ); +} + +void LLJsObject::emitLanguage() +{ + emit getLanguage( mAgentLanguage ); +} diff --git a/indra/llqtwebkit/lljsobject.h b/indra/llqtwebkit/lljsobject.h new file mode 100644 index 000000000..806a8a8a1 --- /dev/null +++ b/indra/llqtwebkit/lljsobject.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLJSOBJECT_H +#define LLJSOBJECT_H + +#include +#include +#include + +class LLJsObject : + public QObject +{ + Q_OBJECT + + public: + LLJsObject( QObject* parent = 0 ); + + void setSLObjectEnabled( bool enabled ); + bool getSLObjectEnabled(); + + void setAgentLanguage( const QString& agent_language ); + void setAgentRegion( const QString& agent_region ); + void setAgentMaturity( const QString& agent_maturity ); + void setAgentLocation( const QVariantMap agent_location ); + void setAgentGlobalLocation( const QVariantMap agent_global_location ); + void setAgentOrientation( const double angle ); + + void emitLocation(); + void emitMaturity(); + void emitLanguage(); + + signals: + void getLocation( const QVariantMap agent_location ); + void getMaturity( const QString agent_maturity ); + void getLanguage( const QString agent_language ); + + private: + bool mEnabled; + + QString mAgentLanguage; + QString mAgentMaturity; + QString mAgentRegion; + QVariantMap mAgentLocation; + QVariantMap mAgentGlobalLocation; + double mAgentOrientation; +}; + +#endif // LLJSOBJECT_H diff --git a/indra/llqtwebkit/llnetworkaccessmanager.cpp b/indra/llqtwebkit/llnetworkaccessmanager.cpp new file mode 100644 index 000000000..2a51f1340 --- /dev/null +++ b/indra/llqtwebkit/llnetworkaccessmanager.cpp @@ -0,0 +1,247 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include "llnetworkaccessmanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "llembeddedbrowserwindow.h" +#include "llembeddedbrowser_p.h" + +#include "ui_passworddialog.h" + + +LLNetworkAccessManager::LLNetworkAccessManager(LLEmbeddedBrowserPrivate* browser,QObject* parent) + : QNetworkAccessManager(parent) + , mBrowser(browser) +{ + connect(this, SIGNAL(finished(QNetworkReply*)), + this, SLOT(finishLoading(QNetworkReply*))); + connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), + this, SLOT(authenticationRequiredSlot(QNetworkReply*, QAuthenticator*))); + connect(this, SIGNAL(sslErrors( QNetworkReply *, const QList &)), + this, SLOT(sslErrorsSlot( QNetworkReply *, const QList & ))); +} + +QNetworkReply *LLNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, + QIODevice *outgoingData) +{ + + // Create a local copy of the request we can modify. + QNetworkRequest mutable_request(request); + + // Set an Accept-Language header in the request, based on what the host has set through setHostLanguage. + mutable_request.setRawHeader(QByteArray("Accept-Language"), QByteArray(mBrowser->mHostLanguage.c_str())); + + // this is undefine'd in 4.7.1 and leads to caching issues - setting it here explicitly + mutable_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork); + + if(op == GetOperation) + { + // GET requests should not have a Content-Type header, but it seems somebody somewhere is adding one. + // This removes it. + mutable_request.setRawHeader("Content-Type", QByteArray()); + } + +// qDebug() << "headers for request:" << mutable_request.rawHeaderList(); + + // and pass this through to the parent implementation + return QNetworkAccessManager::createRequest(op, mutable_request, outgoingData); +} + +void LLNetworkAccessManager::sslErrorsSlot(QNetworkReply* reply, const QList& errors) +{ + // Enabling this can help diagnose certificate verification issues. + const bool ssl_debugging_on = false; + + // flag that indicates if the error that brought us here is one we care about or not + bool valid_ssl_error = false; + + foreach( const QSslError &error, errors ) + { + if ( ssl_debugging_on ) + { + qDebug() << "SSL error details are (" << (int)(error.error()) << ") - " << error.error(); + } + + // SSL "error" codes we don't care about - if we get one of these, we want to continue + if ( error.error() != QSslError::NoError + // many more in src/network/ssl/qsslerror.h + ) + { + if ( ssl_debugging_on ) + { + qDebug() << "Found valid SSL error - will not ignore"; + } + + valid_ssl_error = true; + } + else + { + if ( ssl_debugging_on ) + { + qDebug() << "Found invalid SSL error - will ignore and continue"; + } + } + } + + if ( ssl_debugging_on ) + { + qDebug() << "LLNetworkAccessManager" << __FUNCTION__ << "errors: " << errors + << ", peer certificate chain: "; + + QSslCertificate cert; + foreach(cert, reply->sslConfiguration().peerCertificateChain()) + { + qDebug() << " cert: " << cert + << ", issuer = " << cert.issuerInfo(QSslCertificate::CommonName) + << ", subject = " << cert.subjectInfo(QSslCertificate::CommonName); + } + } + + if ( valid_ssl_error ) + { + std::string url = llToStdString(reply->url()); + QString err_msg=""; + foreach( const QSslError &error, errors ) + { + err_msg+=error.errorString(); + err_msg+="\n"; + + QSslCertificate cert = error.certificate(); + + QString issuer_info=""; + issuer_info+="C="; + issuer_info+=cert.issuerInfo(QSslCertificate::CountryName); + issuer_info+=", ST="; + issuer_info+=cert.issuerInfo(QSslCertificate::StateOrProvinceName); + issuer_info+=", L="; + issuer_info+=cert.issuerInfo(QSslCertificate::LocalityName); + issuer_info+=", O="; + issuer_info+=cert.issuerInfo(QSslCertificate::Organization); + issuer_info+=", OU="; + issuer_info+=cert.issuerInfo(QSslCertificate::OrganizationalUnitName); + issuer_info+=", CN="; + issuer_info+=cert.issuerInfo(QSslCertificate::CommonName); + err_msg+=issuer_info; + err_msg+="\n"; + + QString subject_info=""; + subject_info+="C="; + subject_info+=cert.subjectInfo(QSslCertificate::CountryName); + subject_info+=", ST="; + subject_info+=cert.subjectInfo(QSslCertificate::StateOrProvinceName); + subject_info+=", L="; + subject_info+=cert.subjectInfo(QSslCertificate::LocalityName); + subject_info+=", O="; + subject_info+=cert.subjectInfo(QSslCertificate::Organization); + subject_info+=", OU="; + subject_info+=cert.subjectInfo(QSslCertificate::OrganizationalUnitName); + subject_info+=", CN="; + subject_info+=cert.subjectInfo(QSslCertificate::CommonName); + err_msg+=subject_info; + err_msg+="\n"; + + err_msg+="Not valid before: "; + err_msg+=cert.effectiveDate().toString(); + err_msg+="\n"; + err_msg+="Not valid after: "; + err_msg+=cert.expiryDate().toString(); + err_msg+="\n"; + err_msg+="----------\n"; + } + + if(mBrowser->certError(url, llToStdString(err_msg))) + { + // signal we should ignore and continue processing + reply->ignoreSslErrors(); + } + else + { + // The user canceled, don't return yet so we can test ignore variable + } + } + + // we the SSL error is invalid (in our opinion) or we explicitly ignore all SSL errors + if ( valid_ssl_error == false || ( mBrowser && mBrowser->mIgnoreSSLCertErrors ) ) + { + // signal we should ignore and continue processing + reply->ignoreSslErrors(); + }; +} + +void LLNetworkAccessManager::finishLoading(QNetworkReply* reply) +{ + QVariant val = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ); + int http_status_code = val.toInt(); + if ( http_status_code >=400 && http_status_code <=499 ) + { + if (mBrowser) + { + std::string current_url = llToStdString(reply->url()); + foreach (LLEmbeddedBrowserWindow *window, mBrowser->windows) + { + if (window->getCurrentUri() == current_url) + { + window->navigateErrorPage( http_status_code ); + } + } + } + } + + // tests if navigation request resulted in a cache hit - useful for testing so leaving here for the moment. + //QVariant from_cache = reply->attribute( QNetworkRequest::SourceIsFromCacheAttribute ); + //QString url = QString(reply->url().toEncoded()); + //qDebug() << url << " --- from cache?" << fromCache.toBool() << "\n"; +} + +void LLNetworkAccessManager:: authenticationRequiredSlot(QNetworkReply *reply, QAuthenticator *authenticator) +{ + std::string username; + std::string password; + std::string url = llToStdString(reply->url()); + std::string realm = llToStdString(authenticator->realm()); + + if(mBrowser->authRequest(url, realm, username, password)) + { + // Got credentials to try, attempt auth with them. + authenticator->setUser(QString::fromStdString(username)); + authenticator->setPassword(QString::fromStdString(password)); + } + else + { + // The user cancelled, don't attempt auth. + } +} + diff --git a/indra/llqtwebkit/llnetworkaccessmanager.h b/indra/llqtwebkit/llnetworkaccessmanager.h new file mode 100644 index 000000000..478b679aa --- /dev/null +++ b/indra/llqtwebkit/llnetworkaccessmanager.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLNETWORKACCESSMANAGER_H +#define LLNETWORKACCESSMANAGER_H + +#include +#include + +#include "ui_passworddialog.h" + +class QGraphicsProxyWidget; + +class LLEmbeddedBrowserPrivate; +class LLNetworkAccessManager: public QNetworkAccessManager +{ + Q_OBJECT +public: + LLNetworkAccessManager(LLEmbeddedBrowserPrivate* browser, QObject* parent = 0); + +protected: + virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, + QIODevice *outgoingData = 0); +private slots: + void finishLoading(QNetworkReply* reply); + void authenticationRequiredSlot(QNetworkReply *reply, QAuthenticator *authenticator); + void sslErrorsSlot(QNetworkReply* reply, const QList& errors); + +private: + LLEmbeddedBrowserPrivate* mBrowser; + +}; + +#endif // LLNETWORKACCESSMANAGER_H + diff --git a/indra/llqtwebkit/llqtwebkit.cpp b/indra/llqtwebkit/llqtwebkit.cpp new file mode 100644 index 000000000..2be066d11 --- /dev/null +++ b/indra/llqtwebkit/llqtwebkit.cpp @@ -0,0 +1,820 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include +#include +#include + +#include "llqtwebkit.h" + +#include "llembeddedbrowser.h" +#include "llembeddedbrowserwindow.h" + +LLQtWebKit* LLQtWebKit::sInstance = 0; + +//////////////////////////////////////////////////////////////////////////////// +// +LLQtWebKit::LLQtWebKit() : + mMaxBrowserWindows(16) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLQtWebKit* LLQtWebKit::getInstance() +{ + if (! sInstance) + { + sInstance = new LLQtWebKit; + } + + return sInstance; +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLQtWebKit::~LLQtWebKit() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::init(std::string application_directory, + std::string component_directory, + std::string profile_directory, + void* native_window_handle) +{ + return LLEmbeddedBrowser::getInstance()->init(application_directory, + component_directory, + profile_directory, + native_window_handle); +} + +//////////////////////////////////////////////////////////////////////////////// +// +int LLQtWebKit::getLastError() +{ + return LLEmbeddedBrowser::getInstance()->getLastError(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::reset() +{ + mBrowserWindowMap.clear(); + return LLEmbeddedBrowser::getInstance()->reset(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::clearCache() +{ + return LLEmbeddedBrowser::getInstance()->clearCache(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLQtWebKit::getVersion() +{ + const int majorVersion = 2; + const int minorVersion = 2; + + // number of hours since "time began" for this library - used to identify builds of same version + const int magicNumber = static_cast< int >((time(NULL) / 3600L) - (321190L)); + + // return as a string for now - don't think we need to expose actual version numbers + std::ostringstream codec; + codec << std::setw(1) << std::setfill('0'); + codec << majorVersion << "."; + codec << std::setw(2) << std::setfill('0'); + codec << minorVersion << "."; + codec << std::setw(5) << std::setfill('0'); + codec << magicNumber; + codec << " (QtWebKit version "; + codec << LLEmbeddedBrowser::getInstance()->getGREVersion(); + codec << ")"; + + return codec.str(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::setBrowserAgentId(std::string id) +{ + LLEmbeddedBrowser::getInstance()->setBrowserAgentId(id); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::enableProxy(bool enabled, std::string host_name, int port) +{ + return LLEmbeddedBrowser::getInstance()->enableProxy(enabled, host_name, port); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::setHostLanguage(const std::string& host_language ) +{ + LLEmbeddedBrowser::getInstance()->setHostLanguage(host_language); +} + +//////////////////////////////////////////////////////////////////////////////// +// +int LLQtWebKit::createBrowserWindow(int width, int height, const std::string target) +{ + LLEmbeddedBrowserWindow* browser_window = LLEmbeddedBrowser::getInstance()->createBrowserWindow(width, height, target); + + if (browser_window) + { + // arbitrary limit so we don't exhaust system resources + int id(0); + while (++id < mMaxBrowserWindows) + { + std::pair< BrowserWindowMapIter, bool > result = mBrowserWindowMap.insert(std::make_pair(id, browser_window)); + + // find first place the insert succeeds and use that index as the id + if (result.second) + { + browser_window->setWindowId(id); + return id; + } + } + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::proxyWindowOpened(int browser_window_id, const std::string target, const std::string uuid) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->proxyWindowOpened(target, uuid); + } +} +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::proxyWindowClosed(int browser_window_id, const std::string uuid) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->proxyWindowClosed(uuid); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::destroyBrowserWindow(int browser_window_id) +{ + // don't use the utility method here since we need the iteratorator to remove the entry from the map + BrowserWindowMapIter iterator = mBrowserWindowMap.find(browser_window_id); + LLEmbeddedBrowserWindow* browser_window = (*iterator).second; + + if (browser_window) + { + LLEmbeddedBrowser::getInstance()->destroyBrowserWindow(browser_window); + } + + mBrowserWindowMap.erase(iterator); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::setBackgroundColor(int browser_window_id, const int red, const int green, const int blue) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->setBackgroundColor(red, green, blue); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::setEnabled(int browser_window_id, bool enabled) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->setEnabled(enabled); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::setSize(int browser_window_id, int width, int height) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->setSize(width, height); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::scrollByLines(int browser_window_id, int lines) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->scrollByLines(lines); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::addObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->addObserver(subject); + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::remObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->remObserver(subject); + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::navigateTo(int browser_window_id, const std::string uri) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->navigateTo(uri) ? true : false; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::userAction(int browser_window_id, EUserAction action) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->userAction(action); + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::userActionIsEnabled(int browser_window_id, EUserAction action) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->userActionIsEnabled(action); + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// +const unsigned char* LLQtWebKit::grabBrowserWindow(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->grabWindow(0, 0, browser_window->getBrowserWidth(), browser_window->getBrowserHeight()); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +const unsigned char* LLQtWebKit::getBrowserWindowPixels(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->getPageBuffer(); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::flipWindow(int browser_window_id, bool flip) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->flipWindow(flip); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +int LLQtWebKit::getBrowserWidth(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->getBrowserWidth(); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +int LLQtWebKit::getBrowserHeight(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->getBrowserHeight(); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +int LLQtWebKit::getBrowserDepth(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->getBrowserDepth(); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +int LLQtWebKit::getBrowserRowSpan(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->getBrowserRowSpan(); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::mouseEvent(int browser_window_id, EMouseEvent mouse_event, int button, int x, int y, EKeyboardModifier modifiers) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->mouseEvent(mouse_event, button, x, y, modifiers); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::scrollWheelEvent(int browser_window_id, int x, int y, int scroll_x, int scroll_y, EKeyboardModifier modifiers) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->scrollWheelEvent(x, y, scroll_x, scroll_y, modifiers); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::keyboardEvent( + int browser_window_id, + EKeyEvent key_event, + uint32_t key_code, + const char *utf8_text, + EKeyboardModifier modifiers, + uint32_t native_scan_code, + uint32_t native_virtual_key, + uint32_t native_modifiers) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->keyboardEvent(key_event, key_code, utf8_text, modifiers, native_scan_code, native_virtual_key, native_modifiers); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::focusBrowser(int browser_window_id, bool focus_browser) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->focusBrowser(focus_browser); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::setNoFollowScheme(int browser_window_id, std::string scheme) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->setNoFollowScheme(scheme); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLQtWebKit::getNoFollowScheme(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->getNoFollowScheme(); + } + + return (""); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::pump(int max_milliseconds) +{ + LLEmbeddedBrowser::getInstance()->pump(max_milliseconds); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::enableCookies(bool enabled) +{ + LLEmbeddedBrowser::getInstance()->enableCookies( enabled ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::clearAllCookies() +{ + return LLEmbeddedBrowser::getInstance()->clearAllCookies(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::setCookies(const std::string &cookies) +{ + return LLEmbeddedBrowser::getInstance()->setCookies(cookies); +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLQtWebKit::getAllCookies() +{ + return LLEmbeddedBrowser::getInstance()->getAllCookies(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::enablePlugins(bool enabled) +{ + LLEmbeddedBrowser::getInstance()->enablePlugins(enabled); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::enableJavaScript(bool enabled) +{ + LLEmbeddedBrowser::getInstance()->enableJavaScript(enabled); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::showWebInspector(bool show) +{ + return LLEmbeddedBrowser::getInstance()->showWebInspector(show); +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLQtWebKit::evaluateJavaScript(int browser_window_id, const std::string script) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->evaluateJavaScript(script); + } + + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::prependHistoryUrl(int browser_window_id, std::string url) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->prependHistoryUrl(url); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::clearHistory(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->clearHistory(); + } +} + +std::string LLQtWebKit::dumpHistory(int browser_window_id) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + return browser_window->dumpHistory(); + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::setCAFile(const std::string &ca_file) +{ + return LLEmbeddedBrowser::getInstance()->setCAFile(ca_file); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::addCAFile(const std::string &ca_file) +{ + return LLEmbeddedBrowser::getInstance()->addCAFile(ca_file); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLQtWebKit::setIgnoreSSLCertErrors(bool ignore) +{ + LLEmbeddedBrowser::getInstance()->setIgnoreSSLCertErrors(ignore); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLQtWebKit::getIgnoreSSLCertErrors() +{ + return LLEmbeddedBrowser::getInstance()-> getIgnoreSSLCertErrors(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +const std::vector< std::string > LLQtWebKit::getInstalledCertsList() +{ + return LLEmbeddedBrowser::getInstance()->getInstalledCertsList(); +} + +//////////////////////////////////////////////////////////////////////////////// +// utility method to get an LLEmbeddedBrowserWindow* from a window id (int) +LLEmbeddedBrowserWindow* LLQtWebKit::getBrowserWindowFromWindowId(int browser_window_id) +{ + BrowserWindowMapIter iterator = mBrowserWindowMap.find(browser_window_id); + + if (iterator != mBrowserWindowMap.end()) + return (*iterator).second; + else + return 0; +} + +LLEmbeddedBrowserWindowObserver::~LLEmbeddedBrowserWindowObserver() +{ +} + +void LLEmbeddedBrowserWindowObserver::onCursorChanged(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onPageChanged(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onNavigateBegin(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onNavigateComplete(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onUpdateProgress(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onStatusTextChange(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onTitleChange(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onLocationChange(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onNavigateErrorPage(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onClickLinkHref(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onClickLinkNoFollow(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onCookieChanged(const EventType&) +{ +} + +std::string LLEmbeddedBrowserWindowObserver::onRequestFilePicker(const EventType&) +{ + return std::string(); +} + +void LLEmbeddedBrowserWindowObserver::onWindowCloseRequested(const EventType&) +{ +} + +void LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested(const EventType&) +{ +} + +bool LLEmbeddedBrowserWindowObserver::onAuthRequest(const std::string &, const std::string &, std::string &, std::string &) +{ + return false; +} + +bool LLEmbeddedBrowserWindowObserver::onCertError(const std::string &, const std::string &) +{ + return false; // cancel and abort after cert error +} + +void LLEmbeddedBrowserWindowObserver::onQtDebugMessage( const std::string &, const std::string &) +{ +} + +void LLEmbeddedBrowserWindowObserver::onLinkHovered(const EventType&) +{ +} + +// set the regex used to determine if a page is trusted or not +void LLQtWebKit::setWhiteListRegex( int browser_window_id, const std::string& regex ) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->setWhiteListRegex(regex); + } +} + +// Second Life viewer specific functions +void LLQtWebKit::setSLObjectEnabled( bool enabled ) +{ + LLEmbeddedBrowser::getInstance()->setSLObjectEnabled( enabled ); +} + +void LLQtWebKit::setAgentLanguage( const std::string& agent_language ) +{ + LLEmbeddedBrowser::getInstance()->setAgentLanguage( agent_language ); +} + +void LLQtWebKit::setAgentRegion( const std::string& agent_region ) +{ + LLEmbeddedBrowser::getInstance()->setAgentRegion( agent_region ); +} + +void LLQtWebKit::setAgentLocation( double x, double y, double z ) +{ + LLEmbeddedBrowser::getInstance()->setAgentLocation( x, y, z ); +} + +void LLQtWebKit::setAgentGlobalLocation( double x, double y, double z ) +{ + LLEmbeddedBrowser::getInstance()->setAgentGlobalLocation( x, y, z ); +} + +void LLQtWebKit::setAgentOrientation( double angle ) +{ + LLEmbeddedBrowser::getInstance()->setAgentOrientation( angle ); +} + + +void LLQtWebKit::setAgentMaturity( const std::string& agent_maturity ) +{ + LLEmbeddedBrowser::getInstance()->setAgentMaturity( agent_maturity ); +} + +void LLQtWebKit::emitLocation() +{ + LLEmbeddedBrowser::getInstance()->emitLocation(); +} + +void LLQtWebKit::emitMaturity() +{ + LLEmbeddedBrowser::getInstance()->emitMaturity(); +} + +void LLQtWebKit::emitLanguage() +{ + LLEmbeddedBrowser::getInstance()->emitLanguage(); +} + +void LLQtWebKit::enableQtMessageHandler( bool enable ) +{ + LLEmbeddedBrowser::getInstance()->enableQtMessageHandler( enable ); +} + +void LLQtWebKit::enableLoadingOverlay( int browser_window_id, bool enable) +{ + LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); + if (browser_window) + { + browser_window->enableLoadingOverlay( enable ); + } +} + +void LLQtWebKit::setPageZoomFactor( double factor ) +{ + LLEmbeddedBrowser::getInstance()->setPageZoomFactor( factor ); +} diff --git a/indra/llqtwebkit/llqtwebkit.h b/indra/llqtwebkit/llqtwebkit.h new file mode 100644 index 000000000..8e7ebd390 --- /dev/null +++ b/indra/llqtwebkit/llqtwebkit.h @@ -0,0 +1,470 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLQTWEBKIT_H +#define LLQTWEBKIT_H + +#if defined _MSC_VER && _MSC_VER < 1600 +// no pstdint.h in the client where this header is used +typedef unsigned long uint32_t; +#else +#include // Use the C99 official header +#endif + +#include +#include +#include + +class LLEmbeddedBrowser; +class LLEmbeddedBrowserWindow; + +// Use this to conditionalize code that depends on particular changes to the llqtwebkit API. +// This can be useful for times when we're waiting for a rebuild on one platform or another. +// When you bump this number, please note what the changes were in a comment below the #define, +// and keep the existing comments as history. +#define LLQTWEBKIT_API_VERSION 16 +// version 16: + // Added LLQtWebKit::enableLoadingOverlay() +// version 15: + // Added LLQtWebKit::setPageZoomFactor() +// version 14: + // Added LLEmbeddedBrowserWindowObserver::onQtDebugMessage +// version 13: + // Added LLEmbeddedBrowserWindowObserver::onCertError +// version 12: + // Pass over value to indicate if host for current URL is trusted as per whitelist regex or not +// version 11: + // Added initial support for url/host whitelist via a regex +// version 10: + // Added initial support for creating and displaying the Qt Web Inspector +// version 9: + // Added initial support for exposing certain Second Life viewer/agent variables to JavaScript +// version 8: + // Removed calls to set/clear 404 redirects and made the API now emit an event that the + // consumer can catch and decide what to do when an HTTP status code after navigate is 400-499 +// version 7: + // Added LLEmbeddedBrowserWindowEvent::setNavigationType() && LLEmbeddedBrowserWindowEvent::getNavigationType() + // Used to pass (and retrieve) the type of navigation event that caused a link to be activated. +// version 6: + // Added LLQtWebKit::addCAFile() +// version 5: + // Added LLEmbeddedBrowserWindowObserver::onLinkHovered +// version 4: + // Added LLEmbeddedBrowserWindowObserver::onAuthRequest +// version 3: + // Added setIgnoreSSLCertErrors and getIgnoreSSLCertErrors +// version 2: + // Changed the usage of the event parameters in onClickLinkHref and onClickLinkNoFollow events slightly. + // The clicked URI for both should now be retrieved with getEventUri() instead of getStringValue(). + // The "target" string in onClickLinkHref is now retrieved with getStringValue() instead of getStringValue2(). + // The contents of getStringValue2() in the onClickLinkHref event is now a unique ID for the window proxy the click targets. + // Removed the "link target type" concept, since it doesn't really belong here. + // Removed most of the construtor variants in LLEmbeddedBrowserWindowEvent and added setters in their place. + // Removed setCaretColor, since it's done nothing for some time now. + // Added LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested + // Added +// version 1: + // Added the LLQTWEBKIT_API_VERSION define. + // Added LLEmbeddedBrowserWindowObserver::onWindowCloseRequested + +//////////////////////////////////////////////////////////////////////////////// +// data class that is passed with an event +class LLEmbeddedBrowserWindowEvent +{ + public: + LLEmbeddedBrowserWindowEvent(int window_id) : + mEventWindowId(window_id) + { + }; + + virtual ~LLEmbeddedBrowserWindowEvent() {} + + void setEventUri(const std::string &uri) { mEventUri = uri; } + void setNavigationType(const std::string &type) { mNavigationType = type; } + void setTrustedHost(const bool trusted) { mTrustedHost = trusted; } + void setIntValue(int val) { mIntVal = val; } + void setStringValue(const std::string &val) { mStringVal = val; } + void setStringValue2(const std::string &val) { mStringVal2 = val; } + void setRectValue(int x, int y, int width, int height) + { + mXVal = x; + mYVal = y; + mWidthVal = width; + mHeightVal = height; + } + + int getEventWindowId() const { return mEventWindowId; } + std::string getEventUri() const { return mEventUri; } + std::string getNavigationType() const { return mNavigationType; } + bool getTrustedHost() const { return mTrustedHost; } + int getIntValue() const { return mIntVal; }; + std::string getStringValue() const { return mStringVal; } + std::string getStringValue2() const { return mStringVal2; } + void getRectValue(int& x, int& y, int& width, int& height) const + { + x = mXVal; + y = mYVal; + width = mWidthVal; + height = mHeightVal; + }; + + private: + int mEventWindowId; + std::string mEventUri; + std::string mNavigationType; + bool mTrustedHost; + int mIntVal; + std::string mStringVal; + std::string mStringVal2; + int mXVal; + int mYVal; + int mWidthVal; + int mHeightVal; +}; + +//////////////////////////////////////////////////////////////////////////////// +// derrive from this class and override these methods to observe these events +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +class LLEmbeddedBrowserWindowObserver +{ + public: + virtual ~LLEmbeddedBrowserWindowObserver(); + typedef LLEmbeddedBrowserWindowEvent EventType; + + virtual void onCursorChanged(const EventType& event); + virtual void onPageChanged(const EventType& event); + virtual void onNavigateBegin(const EventType& event); + virtual void onNavigateComplete(const EventType& event); + virtual void onNavigateErrorPage(const EventType& event); + virtual void onUpdateProgress(const EventType& event); + virtual void onStatusTextChange(const EventType& event); + virtual void onTitleChange(const EventType& event); + virtual void onLocationChange(const EventType& event); + virtual void onClickLinkHref(const EventType& event); + virtual void onClickLinkNoFollow(const EventType& event); + virtual void onCookieChanged(const EventType& event); + // mStringVal will be the cookie in RFC 2109 string format + // mEventUri will be the url that caused the cookie change + // mIntVal will be true if the cookie is dead (i.e. being deleted), false otherwise + virtual std::string onRequestFilePicker(const EventType& event); + virtual void onWindowCloseRequested(const EventType& event); + virtual void onWindowGeometryChangeRequested(const EventType& event); + + // This should return true to attempt auth, or false to cancel. + virtual bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password); + + // This should return true to continue after cert error, or false to cancel and abort. + virtual bool onCertError(const std::string &in_url, const std::string &in_msg); + + virtual void onLinkHovered(const EventType& event); + // mEventURI will be the link + // mStringVal will be the title + // mStringVal2 will be the text + + // catch qDebug() messages from Qt and pipe them back to host application + virtual void onQtDebugMessage( const std::string& msg, const std::string& msg_type); +}; +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +//////////////////////////////////////////////////////////////////////////////// +// main library class + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +class LLQtWebKit +{ + public: + typedef enum e_cursor + { + C_ARROW, + C_IBEAM, + C_SPLITV, + C_SPLITH, + C_POINTINGHAND + } ECursor; + + typedef enum e_user_action + { + UA_EDIT_CUT, + UA_EDIT_COPY, + UA_EDIT_PASTE, + UA_NAVIGATE_STOP, + UA_NAVIGATE_BACK, + UA_NAVIGATE_FORWARD, + UA_NAVIGATE_RELOAD + } EUserAction; + + typedef enum e_key_event + { + KE_KEY_DOWN, + KE_KEY_REPEAT, + KE_KEY_UP + }EKeyEvent; + + typedef enum e_mouse_event + { + ME_MOUSE_MOVE, + ME_MOUSE_DOWN, + ME_MOUSE_UP, + ME_MOUSE_DOUBLE_CLICK + }EMouseEvent; + + typedef enum e_mouse_button + { + MB_MOUSE_BUTTON_LEFT, + MB_MOUSE_BUTTON_RIGHT, + MB_MOUSE_BUTTON_MIDDLE, + MB_MOUSE_BUTTON_EXTRA_1, + MB_MOUSE_BUTTON_EXTRA_2, + }EMouseButton; + + typedef enum e_keyboard_modifier + { + KM_MODIFIER_NONE = 0x00, + KM_MODIFIER_SHIFT = 0x01, + KM_MODIFIER_CONTROL = 0x02, + KM_MODIFIER_ALT = 0x04, + KM_MODIFIER_META = 0x08 + }EKeyboardModifier; + + virtual ~LLQtWebKit(); + + // singleton access + static LLQtWebKit* getInstance(); + + // housekeeping + bool init(std::string application_directory, + std::string component_directory, + std::string profile_directory, + void* native_window_handle); + bool reset(); + bool clearCache(); + int getLastError(); + std::string getVersion(); + void setBrowserAgentId(std::string id); + bool enableProxy(bool enabled, std::string host_name, int port); + + void enableCookies(bool enabled); + bool clearAllCookies(); + + // The following two functions accept and return cookies in the same format that's used for the Set-Cookie: HTTP header + // as defined in RFC 2109 ( http://www.ietf.org/rfc/rfc2109.txt ). The string should not contain the literal "Set-Cookie:", + // just the cookie itself. + // Multiple cookies within the string are separated by a newline character ('\n') + void setCookies(const std::string &cookies); + std::string getAllCookies(); + + void enablePlugins(bool enabled); + void enableJavaScript(bool enabled); + + // Web inspector - Firebug-esque debugger + bool showWebInspector(bool show); + + // updates value of 'hostLanguage' in JavaScript 'Navigator' obect that + // embedded pages can query to see what language the host app is set to + void setHostLanguage(const std::string& host_language); + + // browser window - creation/deletion, mutation etc. + int createBrowserWindow(int width, int height, const std::string target = std::string("")); + void proxyWindowOpened(int browser_window_id, const std::string target, const std::string uuid); + void proxyWindowClosed(int browser_window_id, const std::string uuid); + bool destroyBrowserWindow(int browser_window_id); + bool setSize(int browser_window_id, int width, int height); + bool scrollByLines(int browser_window_id, int lines); + bool setBackgroundColor(int browser_window_id, const int red, const int green, const int blue); + bool setEnabled(int browser_window_id, bool enabled); + + // add/remove yourself as an observer on browser events - see LLEmbeddedBrowserWindowObserver declaration + bool addObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject); + bool remObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject); + + // navigation - self explanatory + bool navigateTo(int browser_window_id, const std::string uri); + bool userAction(int browser_window_id, EUserAction action); + bool userActionIsEnabled(int browser_window_id, EUserAction action); + + // javascript access/control + std::string evaluateJavaScript(int browser_window_id, const std::string script); + + // set/clear URL to redirect to when a 404 page is reached + bool set404RedirectUrl(int browser_window_in, std::string redirect_url); + bool clr404RedirectUrl(int browser_window_in); + + // access to rendered bitmap data + const unsigned char* grabBrowserWindow(int browser_window_id); // renders page to memory and returns pixels + const unsigned char* getBrowserWindowPixels(int browser_window_id); // just returns pixels - no render + bool flipWindow(int browser_window_id, bool flip); // optionally flip window (pixels) you get back + int getBrowserWidth(int browser_window_id); // current browser width (can vary slightly after page is rendered) + int getBrowserHeight(int browser_window_id); // current height + int getBrowserDepth(int browser_window_id); // depth in bytes + int getBrowserRowSpan(int browser_window_id); // width in pixels * depth in bytes + + // mouse/keyboard interaction + bool mouseEvent(int browser_window_id, EMouseEvent mouse_event, int button, int x, int y, EKeyboardModifier modifiers); // send a mouse event to a browser window at given XY in browser space + bool scrollWheelEvent(int browser_window_id, int x, int y, int scroll_x, int scroll_y, EKeyboardModifier modifiers); + bool keyboardEvent( + int browser_window_id, + EKeyEvent key_event, + uint32_t key_code, + const char *utf8_text, + EKeyboardModifier modifiers, + uint32_t native_scan_code = 0, + uint32_t native_virtual_key = 0, + uint32_t native_modifiers = 0); + + bool focusBrowser(int browser_window_id, bool focus_browser); // set/remove focus to given browser window + + // accessor/mutator for scheme that browser doesn't follow - e.g. secondlife.com:// + void setNoFollowScheme(int browser_window_id, std::string scheme); + std::string getNoFollowScheme(int browser_window_id); + + void pump(int max_milliseconds); + + void prependHistoryUrl(int browser_window_id, std::string url); + void clearHistory(int browser_window_id); + std::string dumpHistory(int browser_window_id); + + // Specify a path to a .pem file containing a list of CA certificates the browser should trust. + // NOTE that this will replace the default list of root certs (not add to it). + // If the file isn't found or doesn't contain any certs in the correct format, this call will have no effect and will return false. + // NOTE: Using this function causes strange cert verification issues on the Mac. + // Using addCAFile() instead seems to work better. + bool setCAFile(const std::string &ca_file); + + // This behaves similarly, but instead of replacing the entire list it appends additional trusted root certs to the current list. + bool addCAFile(const std::string &ca_file); + + // Set a flag causing all SSL cert errors to be ignored. + // NOTE: this should only be used for testing, as it negates the security model of https. + void setIgnoreSSLCertErrors(bool ignore); + bool getIgnoreSSLCertErrors(); + + const std::vector< std::string > getInstalledCertsList(); + + void enableQtMessageHandler( bool enable ); + + void enableLoadingOverlay( int browser_window_id, bool enable); + + // Copied from indra_constants.h. + // The key_code argument to keyboardEvent should either be one of these or a 7-bit ascii character. + enum keyCodes + { + // Leading zeroes ensure that these won't sign-extend when assigned to a larger type. + KEY_RETURN = 0x0081, + KEY_LEFT = 0x0082, + KEY_RIGHT = 0x0083, + KEY_UP = 0x0084, + KEY_DOWN = 0x0085, + KEY_ESCAPE = 0x0086, + KEY_BACKSPACE = 0x0087, + KEY_DELETE = 0x0088, + KEY_SHIFT = 0x0089, + KEY_CONTROL = 0x008A, + KEY_ALT = 0x008B, + KEY_HOME = 0x008C, + KEY_END = 0x008D, + KEY_PAGE_UP = 0x008E, + KEY_PAGE_DOWN = 0x008F, + KEY_HYPHEN = 0x0090, + KEY_EQUALS = 0x0091, + KEY_INSERT = 0x0092, + KEY_CAPSLOCK = 0x0093, + KEY_TAB = 0x0094, + KEY_ADD = 0x0095, + KEY_SUBTRACT = 0x0096, + KEY_MULTIPLY = 0x0097, + KEY_DIVIDE = 0x0098, + KEY_F1 = 0x00A1, + KEY_F2 = 0x00A2, + KEY_F3 = 0x00A3, + KEY_F4 = 0x00A4, + KEY_F5 = 0x00A5, + KEY_F6 = 0x00A6, + KEY_F7 = 0x00A7, + KEY_F8 = 0x00A8, + KEY_F9 = 0x00A9, + KEY_F10 = 0x00AA, + KEY_F11 = 0x00AB, + KEY_F12 = 0x00AC, + + KEY_PAD_UP = 0x00C0, + KEY_PAD_DOWN = 0x00C1, + KEY_PAD_LEFT = 0x00C2, + KEY_PAD_RIGHT = 0x00C3, + KEY_PAD_HOME = 0x00C4, + KEY_PAD_END = 0x00C5, + KEY_PAD_PGUP = 0x00C6, + KEY_PAD_PGDN = 0x00C7, + KEY_PAD_CENTER = 0x00C8, // the 5 in the middle + KEY_PAD_INS = 0x00C9, + KEY_PAD_DEL = 0x00CA, + KEY_PAD_RETURN = 0x00CB, + KEY_PAD_ADD = 0x00CC, + KEY_PAD_SUBTRACT = 0x00CD, + KEY_PAD_MULTIPLY = 0x00CE, + KEY_PAD_DIVIDE = 0x00CF, + + KEY_NONE = 0x00FF // not sent from keyboard. For internal use only. + }; + + // set the regex used to determine if a page is trusted or not + void setWhiteListRegex( int browser_window_id, const std::string& regex ); + + // Second Life specific functions + // (Note, this is a departure from the generic nature of this library) + void setSLObjectEnabled( bool enabled ); // enable or disaable feature + void setAgentLanguage( const std::string& agent_language ); // viewer language selected by agent + void setAgentRegion( const std::string& agent_region ); // name of region where agent is located + void setAgentLocation( double x, double y, double z ); // agent's x,y,z location within a region + void setAgentGlobalLocation( double x, double y, double z ); // agent's x,y,z location within the current grid + void setAgentOrientation( double angle ); // direction (0..359) agent is facing + void setAgentMaturity( const std::string& agent_maturity ); // selected maturity level of agent + void emitLocation(); + void emitMaturity(); + void emitLanguage(); + + // set the zoom factor for web pages ( can be less than 0.0) + void setPageZoomFactor( double factor ); + + private: + LLQtWebKit(); + LLEmbeddedBrowserWindow* getBrowserWindowFromWindowId(int browser_window_id); + static LLQtWebKit* sInstance; + const int mMaxBrowserWindows; + typedef std::map< int, LLEmbeddedBrowserWindow* > BrowserWindowMap; + typedef std::map< int, LLEmbeddedBrowserWindow* >::iterator BrowserWindowMapIter; + BrowserWindowMap mBrowserWindowMap; +}; + +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#endif // LLQTWEBKIT_H diff --git a/indra/llqtwebkit/llqtwebkit.pri b/indra/llqtwebkit/llqtwebkit.pri new file mode 100644 index 000000000..4f85aa423 --- /dev/null +++ b/indra/llqtwebkit/llqtwebkit.pri @@ -0,0 +1,47 @@ +DEPENDPATH += $$PWD +INCLUDEPATH += $$PWD + +!mac { +unix { + DEFINES += LL_LINUX +} +} + +mac { + DEFINES += LL_OSX +} + +win32{ + DEFINES += _WINDOWS +} + +# Input +HEADERS += llembeddedbrowser.h \ + llembeddedbrowser_p.h \ + llembeddedbrowserwindow.h \ + llembeddedbrowserwindow_p.h \ + llnetworkaccessmanager.h \ + llqtwebkit.h \ + llwebpage.h \ + llwebpageopenshim.h \ + llstyle.h \ + lljsobject.h + +SOURCES += llembeddedbrowser.cpp \ + llembeddedbrowserwindow.cpp \ + llnetworkaccessmanager.cpp \ + llqtwebkit.cpp \ + llwebpage.cpp \ + llwebpageopenshim.cpp \ + llstyle.cpp \ + lljsobject.cpp + +FORMS += passworddialog.ui + +RCC_DIR = .rcc +UI_DIR = .ui +MOC_DIR = .moc +OBJECTS_DIR = .obj + +include(static.pri) +include(qtwebkit_cookiejar/src/src.pri) diff --git a/indra/llqtwebkit/llqtwebkit.pro b/indra/llqtwebkit/llqtwebkit.pro new file mode 100644 index 000000000..b6ff077bd --- /dev/null +++ b/indra/llqtwebkit/llqtwebkit.pro @@ -0,0 +1,18 @@ +TEMPLATE = lib +CONFIG += static staticlib # we always build as static lib whether Qt is static or not +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +include(llqtwebkit.pri) + +QT += webkit opengl network gui + +win32:CONFIG(debug,debug|release) { + TARGET = llqtwebkitd +} + +RCC_DIR = $$PWD/.rcc +UI_DIR = $$PWD/.ui +MOC_DIR = $$PWD/.moc +OBJECTS_DIR = $$PWD/.obj diff --git a/indra/llqtwebkit/llstyle.cpp b/indra/llqtwebkit/llstyle.cpp new file mode 100644 index 000000000..ecd2b3eb8 --- /dev/null +++ b/indra/llqtwebkit/llstyle.cpp @@ -0,0 +1,79 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include "llstyle.h" + +#include "llembeddedbrowserwindow_p.h" +#include +#include +#include + +LLStyle::LLStyle() + : QPlastiqueStyle() +{ +} + +void LLStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ +#ifdef Q_WS_MAC + if (control == QStyle::CC_ScrollBar) { + QStyleOptionSlider* opt = (QStyleOptionSlider*)option; + const QPoint topLeft = opt->rect.topLeft(); + painter->translate(topLeft); + opt->rect.moveTo(QPoint(0, 0)); + painter->fillRect(opt->rect, opt->palette.background()); + } +#endif + QPlastiqueStyle::drawComplexControl(control, option, painter, widget); +} + +void LLStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + switch(element) + { + case CE_ScrollBarAddLine: + case CE_ScrollBarSubLine: + // This fixes the "scrollbar arrows pointing the wrong way" bug. + if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) + { + // Make the State_Horizontal bit in the option's state field match its orientation field. + QStyleOptionSlider localOption(*scrollBar); + if(localOption.orientation == Qt::Horizontal) + { + localOption.state |= State_Horizontal; + } + else + { + localOption.state &= ~State_Horizontal; + } + QPlastiqueStyle::drawControl(element, &localOption, painter, widget); + return; + } + + break; + } + + QPlastiqueStyle::drawControl(element, option, painter, widget); +} diff --git a/indra/llqtwebkit/llstyle.h b/indra/llqtwebkit/llstyle.h new file mode 100644 index 000000000..77c09b3bb --- /dev/null +++ b/indra/llqtwebkit/llstyle.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLSTYLE_H +#define LLSTYLE_H + +#include + +class LLStyle : public QPlastiqueStyle +{ + +public: + explicit LLStyle(); + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const; + void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const; + +}; + +#endif + diff --git a/indra/llqtwebkit/llwebpage.cpp b/indra/llqtwebkit/llwebpage.cpp new file mode 100644 index 000000000..113c0c186 --- /dev/null +++ b/indra/llqtwebkit/llwebpage.cpp @@ -0,0 +1,536 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include "llwebpage.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "llqtwebkit.h" +#include "llembeddedbrowser.h" +#include "llembeddedbrowserwindow.h" +#include "llembeddedbrowserwindow_p.h" +#include "lljsobject.h" + +LLWebPage::LLWebPage(QObject *parent) + : QWebPage(parent) + , window(0) + , mHostLanguage( "en" ) + , mWhiteListRegex( "" ) +{ + mJsObject = new LLJsObject( parent ); + + connect(this, SIGNAL(loadProgress(int)), + this, SLOT(loadProgressSlot(int))); + connect(this, SIGNAL(linkHovered(const QString &, const QString &, const QString &)), + this, SLOT(linkHoveredSlot(const QString &, const QString &, const QString &))); + connect(this, SIGNAL(statusBarMessage(const QString &)), + this, SLOT(statusBarMessageSlot(const QString &))); + connect(mainFrame(), SIGNAL(urlChanged(const QUrl&)), + this, SLOT(urlChangedSlot(const QUrl&))); + connect(this, SIGNAL(loadStarted()), + this, SLOT(loadStarted())); + connect(this, SIGNAL(loadFinished(bool)), + this, SLOT(loadFinished(bool))); + connect(this, SIGNAL(windowCloseRequested()), + this, SLOT(windowCloseRequested())); + connect(this, SIGNAL(geometryChangeRequested(const QRect&)), + this, SLOT(geometryChangeRequested(const QRect&))); + connect(mainFrame(), SIGNAL(titleChanged(const QString&)), + this, SLOT(titleChangedSlot(const QString&))); + connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), + this, SLOT(extendNavigatorObject())); +} + +LLWebPage::~LLWebPage() +{ + delete mJsObject; +} + +void LLWebPage::loadProgressSlot(int progress) +{ + if (!window) + return; + window->d->mPercentComplete = progress; + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + event.setIntValue(progress); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onUpdateProgress, event); + + if ( progress >= 100 ) + window->d->mShowLoadingOverlay = false; + + window->d->mDirty = true; + window->grabWindow(0,0,webView->boundingRect().width(),webView->boundingRect().height()); + + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); +} + +void LLWebPage::linkHoveredSlot(const QString &link, const QString &title, const QString &textContent) +{ + if (!window) + return; + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(llToStdString(link)); + event.setStringValue(llToStdString(title)); + event.setStringValue2(llToStdString(textContent)); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onLinkHovered, event); +} + +void LLWebPage::statusBarMessageSlot(const QString& text) +{ + if (!window) + return; + window->d->mStatusText = llToStdString(text); + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + event.setStringValue(window->d->mStatusText); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onStatusTextChange, event); +} + +void LLWebPage::titleChangedSlot(const QString& text) +{ + if (!window) + return; + window->d->mTitle = llToStdString(text); + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + event.setStringValue(window->d->mTitle); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onTitleChange, event); +} + +// set the regex used to determine if a page is trusted or not +void LLWebPage::setWhiteListRegex( const std::string& regex ) +{ + mWhiteListRegex = regex; +} + +void LLWebPage::configureTrustedPage( bool is_trusted ) +{ + // action happens in browser window parent + LLEmbeddedBrowser* parent_browser = 0; + if ( window && window->d && window->d->mParent ) + { + parent_browser = window->d->mParent; + if ( parent_browser ) + { + if ( is_trusted ) + { + //qDebug() << "Whitelist passed - turning on"; + + // trusted so turn everything on + parent_browser->enableJavaScriptTransient( true ); + parent_browser->enableCookiesTransient( true ); + parent_browser->enablePluginsTransient( true ); + } + else + { + //qDebug() << "Whitelist failed - reverting to default state"; + + // restore default state set by client + parent_browser->enableJavaScript( parent_browser->isJavaScriptEnabled() ); + parent_browser->enableCookies( parent_browser->areCookiesEnabled() ); + parent_browser->enablePlugins( parent_browser->arePluginsEnabled() ); + } + } + } +} + +bool LLWebPage::checkRegex( const QUrl& url ) +{ + QRegExp reg_exp( QString::fromStdString( mWhiteListRegex ) ); + reg_exp.setCaseSensitivity( Qt::CaseInsensitive ); + reg_exp.setMinimal( true ); + + if ( reg_exp.exactMatch( url.host() ) ) + { + return true; + } + else + { + return false; + } +} + +void LLWebPage::checkWhiteList( const QUrl& url ) +{ + if ( mWhiteListRegex.length() ) + { + if ( checkRegex( url ) ) + { + configureTrustedPage( true ); // page is "trusted" - go ahead and configure it as such + } + else + { + configureTrustedPage( false ); // page is "NOT trusted" - go ahead and configure it as such + } + } + else + // no regex specified, don't do anything (i.e. don't change trust state) + { + } +} + +void LLWebPage::urlChangedSlot(const QUrl& url) +{ + if (!window) + return; + + checkWhiteList( url ); + + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onLocationChange, event); +} + +bool LLWebPage::event(QEvent *event) +{ + bool result = QWebPage::event(event); + + if (event->type() == QEvent::GraphicsSceneMousePress) + currentPoint = ((QGraphicsSceneMouseEvent*)event)->pos().toPoint(); + else if(event->type() == QEvent::GraphicsSceneMouseRelease) + currentPoint = QPoint(); + + return result; +} + +bool LLWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type) +{ + Q_UNUSED( frame ); + + if (!window) + return false; + + if (request.url().scheme() == window->d->mNoFollowScheme) + { + QString encodedUrl = request.url().toEncoded(); + // QUrl is turning foo:///home/bar into foo:/home/bar for some reason while Firefox does not + // http://bugs.webkit.org/show_bug.cgi?id=24695 + if (!encodedUrl.startsWith(window->d->mNoFollowScheme + "://")) { + encodedUrl = encodedUrl.mid(window->d->mNoFollowScheme.length() + 1); + encodedUrl = window->d->mNoFollowScheme + "://" + encodedUrl; + } + std::string rawUri = llToStdString(encodedUrl); + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(rawUri); + + // pass over the navigation type as per this page: http://apidocs.meego.com/1.1/core/html/qt4/qwebpage.html#NavigationType-enum + // pass as strings because telling everyone who needs to know about enums is too invasive. + std::string nav_type("unknown"); + if (type == QWebPage::NavigationTypeLinkClicked) nav_type="clicked"; + else + if (type == QWebPage::NavigationTypeFormSubmitted) nav_type="form_submited"; + else + if (type == QWebPage::NavigationTypeBackOrForward) nav_type="back_forward"; + else + if (type == QWebPage::NavigationTypeReload) nav_type="reloaded"; + else + if (type == QWebPage::NavigationTypeFormResubmitted) nav_type="form_resubmited"; + event.setNavigationType(nav_type); + + if ( mWhiteListRegex.length() ) + { + if ( frame ) + { + if ( checkRegex( frame->url() ) ) + { + event.setTrustedHost( true ); + } + else + { + event.setTrustedHost( false ); + } + } + else + // no frame - no trust (TODO: when can this happen?) + { + event.setTrustedHost( false ); + } + } + else + // no regex is like switching it off and indicating everything is trusted + { + event.setTrustedHost( true ); + } + + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onClickLinkNoFollow, event); + + //qDebug() << "LLWebPage::acceptNavigationRequest: sending onClickLinkNoFollow, NavigationType is " << type << ", url is " << QString::fromStdString(rawUri) ; + return false; + } + + + return true; +} + + +void LLWebPage::loadStarted() +{ + if (!window) + return; + + QUrl url( QString::fromStdString( window->getCurrentUri() ) ); + checkWhiteList( url ); + + window->d->mShowLoadingOverlay = true; + + window->d->mTimeLoadStarted=time(NULL); + + window->d->mDirty = true; + window->grabWindow(0,0,webView->boundingRect().width(),webView->boundingRect().height()); + + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateBegin, event); +} + +void LLWebPage::loadFinished(bool) +{ + if (!window) + return; + + window->d->mShowLoadingOverlay = false; + + window->d->mDirty = true; + window->grabWindow(0,0,webView->boundingRect().width(),webView->boundingRect().height()); + + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setEventUri(window->getCurrentUri()); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); + + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateComplete, event); +} + +void LLWebPage::windowCloseRequested() +{ + if (!window) + return; + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowCloseRequested, event); +} + +void LLWebPage::geometryChangeRequested(const QRect& geom) +{ + if (!window) + return; + + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + // empty UUID indicates this is targeting the main window +// event.setStringValue(window->getUUID()); + event.setRectValue(geom.x(), geom.y(), geom.width(), geom.height()); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested, event); +} + +QString LLWebPage::chooseFile(QWebFrame* parentFrame, const QString& suggestedFile) +{ + Q_UNUSED(parentFrame); + Q_UNUSED(suggestedFile); + + return QString::fromStdString( window->requestFilePicker() ); +} + +void LLWebPage::javaScriptAlert(QWebFrame* frame, const QString& msg) +{ + Q_UNUSED(frame); + QMessageBox *msgBox = new QMessageBox; + msgBox->setWindowTitle(tr("JavaScript Alert - %1").arg(mainFrame()->url().host())); + msgBox->setText(msg); + msgBox->addButton(QMessageBox::Ok); + + QGraphicsProxyWidget *proxy = webView->scene()->addWidget(msgBox); + proxy->setWindowFlags(Qt::Window); // this makes the item a panel (and will make it get a window 'frame') + proxy->setPanelModality(QGraphicsItem::SceneModal); + proxy->setPos((webView->boundingRect().width() - msgBox->sizeHint().width())/2, + (webView->boundingRect().height() - msgBox->sizeHint().height())/2); + proxy->setActive(true); // make it the active item + + connect(msgBox, SIGNAL(finished(int)), proxy, SLOT(deleteLater())); + msgBox->show(); + + webView->scene()->setFocusItem(proxy); +} + +bool LLWebPage::javaScriptConfirm(QWebFrame* frame, const QString& msg) +{ + Q_UNUSED(frame); + Q_UNUSED(msg); + qWarning() << "LLWebPage::" << __FUNCTION__ << "not implemented" << msg << "returning true"; + return true; +} + +bool LLWebPage::javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result) +{ + Q_UNUSED(frame); + Q_UNUSED(msg); + Q_UNUSED(defaultValue); + Q_UNUSED(result); + qWarning() << "LLWebPage::" << __FUNCTION__ << "not implemented" << msg << defaultValue << "returning false"; + return false; +} + +void LLWebPage::extendNavigatorObject() +{ + // legacy - will go away in the future + QString q_host_language = QString::fromStdString( mHostLanguage ); + mainFrame()->evaluateJavaScript(QString("navigator.hostLanguage=\"%1\"").arg( q_host_language )); + + // the new way + if ( mJsObject ) + { + bool enabled = mJsObject->getSLObjectEnabled(); + if ( enabled ) + { + mainFrame()->addToJavaScriptWindowObject("slviewer", mJsObject ); + }; + }; +} + +QWebPage *LLWebPage::createWindow(WebWindowType type) +{ + Q_UNUSED(type); + QWebPage *result = NULL; + + if(window) + { + result = window->createWindow(); + } + + return result; +} + +void LLWebPage::setHostLanguage(const std::string& host_language) +{ + mHostLanguage = host_language; +} + +bool LLWebPage::supportsExtension(QWebPage::Extension extension) const +{ + if (extension == QWebPage::ErrorPageExtension) + return true; + return false; +} + +bool LLWebPage::extension(Extension, const ExtensionOption* option, ExtensionReturn* output) +{ + const QWebPage::ErrorPageExtensionOption* info = static_cast(option); + QWebPage::ErrorPageExtensionReturn* errorPage = static_cast(output); + + errorPage->content = QString("Failed loading page

%1

") + .arg(info->errorString).toUtf8(); + + return true; +} + +// Second Life viewer specific functions +void LLWebPage::setSLObjectEnabled( bool enabled ) +{ + if ( mJsObject ) + mJsObject->setSLObjectEnabled( enabled ); +} + +void LLWebPage::setAgentLanguage( const std::string& agent_language ) +{ + if ( mJsObject ) + mJsObject->setAgentLanguage( QString::fromStdString( agent_language ) ); +} + +void LLWebPage::setAgentRegion( const std::string& agent_region ) +{ + if ( mJsObject ) + mJsObject->setAgentRegion( QString::fromStdString( agent_region ) ); +} + +void LLWebPage::setAgentLocation( double x, double y, double z ) +{ + if ( mJsObject ) + { + QVariantMap location; + location["x"] = x; + location["y"] = y; + location["z"] = z; + mJsObject->setAgentLocation( location ); + } +} + +void LLWebPage::setAgentGlobalLocation( double x, double y, double z ) +{ + if ( mJsObject ) + { + QVariantMap global_location; + global_location["x"] = x; + global_location["y"] = y; + global_location["z"] = z; + mJsObject->setAgentGlobalLocation( global_location ); + } +} + +void LLWebPage::setAgentOrientation( double angle ) +{ + if ( mJsObject ) + { + mJsObject->setAgentOrientation( angle ); + } +} + +void LLWebPage::setAgentMaturity( const std::string& agent_maturity ) +{ + if ( mJsObject ) + mJsObject->setAgentMaturity( QString::fromStdString( agent_maturity ) ); +} + +void LLWebPage::emitLocation() +{ + if ( mJsObject ) + mJsObject->emitLocation(); +} + +void LLWebPage::emitMaturity() +{ + if ( mJsObject ) + mJsObject->emitMaturity(); +} + +void LLWebPage::emitLanguage() +{ + if ( mJsObject ) + mJsObject->emitLanguage(); +} + +void LLWebPage::setPageZoomFactor( double factor ) +{ + if ( webView ) + { + webView->setZoomFactor( factor ); + } +} \ No newline at end of file diff --git a/indra/llqtwebkit/llwebpage.h b/indra/llqtwebkit/llwebpage.h new file mode 100644 index 000000000..1a882254f --- /dev/null +++ b/indra/llqtwebkit/llwebpage.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLWEBPAGE_H +#define LLWEBPAGE_H + +class QGraphicsWebView; +#include +#include "llqtwebkit.h" + +class LLEmbeddedBrowserWindow; +class LLJsObject; + +class LLWebPage : public QWebPage +{ + Q_OBJECT + + public: + LLWebPage(QObject *parent = 0); + ~LLWebPage(); + + LLEmbeddedBrowserWindow *window; + bool event(QEvent *event); + + QGraphicsWebView *webView; + + void setHostLanguage(const std::string& host_language); + virtual bool supportsExtension(QWebPage::Extension extension) const; + virtual bool extension(Extension extension, const ExtensionOption* option, ExtensionReturn* output); + + // set the regex used to determine if a page is trusted or not + void setWhiteListRegex( const std::string& regex ); + + // check the whitelist and update browser config as appropriate + void checkWhiteList( const QUrl& url ); + + // code to change settings if page is known to be trusted goes here + void configureTrustedPage( bool is_trusted ); + + // Second Life specific functions + void setAgentRegion( const std::string& agent_region ); + void setAgentLocation( double x, double y, double z ); + void setAgentGlobalLocation( double x, double y, double z ); + void setAgentOrientation( double angle ); + void setSLObjectEnabled( bool enabled ); + void setAgentLanguage( const std::string& agent_language ); + void setAgentMaturity( const std::string& agent_maturity ); + void emitLocation(); + void emitMaturity(); + void emitLanguage(); + + void setPageZoomFactor( double factor ); + + protected: + bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type); + + public slots: + void loadProgressSlot(int progress); + void linkHoveredSlot(const QString &link, const QString &title, const QString &textContent); + void statusBarMessageSlot(const QString &); + void titleChangedSlot(const QString &); + void urlChangedSlot(const QUrl& url); + void loadStarted(); + void loadFinished(bool ok); + void windowCloseRequested(); + void geometryChangeRequested(const QRect& geom); + + private slots: + void extendNavigatorObject(); + + protected: + QString chooseFile(QWebFrame* parentFrame, const QString& suggestedFile); + void javaScriptAlert(QWebFrame* frame, const QString& msg); + bool javaScriptConfirm(QWebFrame* frame, const QString& msg); + bool javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result); + QWebPage *createWindow(WebWindowType type); + + private: + bool checkRegex( const QUrl& url ); + QPoint currentPoint; + std::string mHostLanguage; + std::string mWhiteListRegex; + LLJsObject* mJsObject; +}; + +#endif diff --git a/indra/llqtwebkit/llwebpageopenshim.cpp b/indra/llqtwebkit/llwebpageopenshim.cpp new file mode 100644 index 000000000..af9627907 --- /dev/null +++ b/indra/llqtwebkit/llwebpageopenshim.cpp @@ -0,0 +1,176 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include "llwebpageopenshim.h" + +#include +#include +#include +#include + +#include "llqtwebkit.h" +#include "llembeddedbrowserwindow.h" +#include "llembeddedbrowserwindow_p.h" + +LLWebPageOpenShim::LLWebPageOpenShim(LLEmbeddedBrowserWindow *in_window, QObject *parent) + : QWebPage(parent) + , window(in_window) + , mOpeningSelf(false) + , mGeometryChangeRequested(false) + , mHasSentUUID(false) +{ +// qDebug() << "LLWebPageOpenShim created"; + + connect(this, SIGNAL(windowCloseRequested()), + this, SLOT(windowCloseRequested())); + connect(this, SIGNAL(geometryChangeRequested(const QRect&)), + this, SLOT(geometryChangeRequested(const QRect&))); + + // Create a unique UUID for this proxy + mUUID = llToStdString(QUuid::createUuid().toString()); + + // mTarget starts out as the empty string, which is what we want. +} + +LLWebPageOpenShim::~LLWebPageOpenShim() +{ +// qDebug() << "LLWebPageOpenShim destroyed"; +} + +void LLWebPageOpenShim::windowCloseRequested() +{ +// qDebug() << "LLWebPageOpenShim::windowCloseRequested"; + if(window) + { + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setStringValue(mUUID); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowCloseRequested, event); + } +} + +void LLWebPageOpenShim::geometryChangeRequested(const QRect& geom) +{ +// qDebug() << "LLWebPageOpenShim::geometryChangeRequested: " << geom ; + + // This seems to happen before acceptNavigationRequest is called. If this is the case, delay sending the message until afterwards. + + if(window && mHasSentUUID) + { + LLEmbeddedBrowserWindowEvent event(window->getWindowId()); + event.setStringValue(mUUID); + event.setRectValue(geom.x(), geom.y(), geom.width(), geom.height()); + window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested, event); + } + else + { + mGeometry = geom; + mGeometryChangeRequested = true; + } + +} + +bool LLWebPageOpenShim::matchesTarget(const std::string target) +{ + return (target == mTarget); +} + +bool LLWebPageOpenShim::matchesUUID(const std::string uuid) +{ + return (uuid == mUUID); +} + +void LLWebPageOpenShim::setProxy(const std::string &target, const std::string &uuid) +{ + mTarget = target; + mUUID = uuid; + + mHasSentUUID = false; + + mOpeningSelf = true; + + mainFrame()->evaluateJavaScript(QString("window.open("", \"%1\");").arg( QString::fromStdString(target) )); +} + +bool LLWebPageOpenShim::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type) +{ + Q_UNUSED(type); + if (!window) + { + return false; + } + + if(mOpeningSelf) + { + qDebug() << "LLWebPageOpenShim::acceptNavigationRequest: reopening self to set target name."; + return true; + } + +#if 0 + qDebug() << "LLWebPageOpenShim::acceptNavigationRequest called, NavigationType is " << type + << ", web frame is " << frame + << ", frame->page is " << frame->page() + << ", url is " << request.url() + << ", frame name is " << frame->frameName() + ; +#endif + + if (request.url().scheme() == QString("file")) + { + // For some reason, I'm seeing a spurious call to this function with a file:/// URL that points to the current working directory. + // Ignoring file:/// URLs here isn't a perfect solution (since it could potentially break content in local HTML files), + // but it's the best I could come up with for now. + + return false; + } + + // The name of the incoming frame has been set to the link target that was used when opening this window. + std::string click_href = llToStdString(request.url()); + mTarget = llToStdString(frame->frameName()); + + // build event based on the data we have and emit it + LLEmbeddedBrowserWindowEvent event( window->getWindowId()); + event.setEventUri(click_href); + event.setStringValue(mTarget); + event.setStringValue2(mUUID); + + window->d->mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkHref, event ); + + mHasSentUUID = true; + + if(mGeometryChangeRequested) + { + geometryChangeRequested(mGeometry); + mGeometryChangeRequested = false; + } + + return false; +} + +QWebPage *LLWebPageOpenShim::createWindow(WebWindowType type) +{ + Q_UNUSED(type); + + return this; +} diff --git a/indra/llqtwebkit/llwebpageopenshim.h b/indra/llqtwebkit/llwebpageopenshim.h new file mode 100644 index 000000000..322f832ce --- /dev/null +++ b/indra/llqtwebkit/llwebpageopenshim.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef LLWEBPAGEOPENSHIM_H +#define LLWEBPAGEOPENSHIM_H + +#include + +class LLEmbeddedBrowserWindow; +class LLWebPageOpenShim : public QWebPage +{ + Q_OBJECT + + public: + LLWebPageOpenShim(LLEmbeddedBrowserWindow *in_window, QObject *parent = 0); + ~LLWebPageOpenShim(); + LLEmbeddedBrowserWindow *window; + bool matchesTarget(const std::string target); + bool matchesUUID(const std::string uuid); + void setProxy(const std::string &target, const std::string &uuid); + + public slots: + void windowCloseRequested(); + void geometryChangeRequested(const QRect& geom); + + protected: + bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type); + QWebPage *createWindow(WebWindowType type); + + private: + std::string mUUID; + std::string mTarget; + bool mOpeningSelf; + bool mGeometryChangeRequested; + bool mHasSentUUID; + QRect mGeometry; + +}; + +#endif + diff --git a/indra/llqtwebkit/passworddialog.ui b/indra/llqtwebkit/passworddialog.ui new file mode 100644 index 000000000..033514eff --- /dev/null +++ b/indra/llqtwebkit/passworddialog.ui @@ -0,0 +1,137 @@ + + + PasswordDialog + + + + 0 + 0 + 394 + 183 + + + + Dialog + + + + + + Qt::Vertical + + + + 20 + 12 + + + + + + + + + + + true + + + + + + + + 32 + 32 + + + + icon + + + + + + + Qt::Vertical + + + + 20 + 13 + + + + + + + + User name: + + + + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + PasswordDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PasswordDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/indra/llqtwebkit/pstdint.h b/indra/llqtwebkit/pstdint.h new file mode 100644 index 000000000..b36f63db3 --- /dev/null +++ b/indra/llqtwebkit/pstdint.h @@ -0,0 +1,728 @@ +/* A portable stdint.h + **************************************************************************** + * BSD License: + **************************************************************************** + * + * Copyright (c) 2005-2007 Paul Hsieh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************** + * + * Version 0.1.10 + * + * The ANSI C standard committee, for the C99 standard, specified the + * inclusion of a new standard include file called stdint.h. This is + * a very useful and long desired include file which contains several + * very precise definitions for integer scalar types that is + * critically important for making portable several classes of + * applications including cryptography, hashing, variable length + * integer libraries and so on. But for most developers its likely + * useful just for programming sanity. + * + * The problem is that most compiler vendors have decided not to + * implement the C99 standard, and the next C++ language standard + * (which has a lot more mindshare these days) will be a long time in + * coming and its unknown whether or not it will include stdint.h or + * how much adoption it will have. Either way, it will be a long time + * before all compilers come with a stdint.h and it also does nothing + * for the extremely large number of compilers available today which + * do not include this file, or anything comparable to it. + * + * So that's what this file is all about. Its an attempt to build a + * single universal include file that works on as many platforms as + * possible to deliver what stdint.h is supposed to. A few things + * that should be noted about this file: + * + * 1) It is not guaranteed to be portable and/or present an identical + * interface on all platforms. The extreme variability of the + * ANSI C standard makes this an impossibility right from the + * very get go. Its really only meant to be useful for the vast + * majority of platforms that possess the capability of + * implementing usefully and precisely defined, standard sized + * integer scalars. Systems which are not intrinsically 2s + * complement may produce invalid constants. + * + * 2) There is an unavoidable use of non-reserved symbols. + * + * 3) Other standard include files are invoked. + * + * 4) This file may come in conflict with future platforms that do + * include stdint.h. The hope is that one or the other can be + * used with no real difference. + * + * 5) In the current verison, if your platform can't represent + * int32_t, int16_t and int8_t, it just dumps out with a compiler + * error. + * + * 6) 64 bit integers may or may not be defined. Test for their + * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX. + * Note that this is different from the C99 specification which + * requires the existence of 64 bit support in the compiler. If + * this is not defined for your platform, yet it is capable of + * dealing with 64 bits then it is because this file has not yet + * been extended to cover all of your system's capabilities. + * + * 7) (u)intptr_t may or may not be defined. Test for its presence + * with the test: #ifdef PTRDIFF_MAX. If this is not defined + * for your platform, then it is because this file has not yet + * been extended to cover all of your system's capabilities, not + * because its optional. + * + * 8) The following might not been defined even if your platform is + * capable of defining it: + * + * WCHAR_MIN + * WCHAR_MAX + * (u)int64_t + * PTRDIFF_MIN + * PTRDIFF_MAX + * (u)intptr_t + * + * 9) The following have not been defined: + * + * WINT_MIN + * WINT_MAX + * + * 10) The criteria for defining (u)int_least(*)_t isn't clear, + * except for systems which don't have a type that precisely + * defined 8, 16, or 32 bit types (which this include file does + * not support anyways). Default definitions have been given. + * + * 11) The criteria for defining (u)int_fast(*)_t isn't something I + * would trust to any particular compiler vendor or the ANSI C + * committee. It is well known that "compatible systems" are + * commonly created that have very different performance + * characteristics from the systems they are compatible with, + * especially those whose vendors make both the compiler and the + * system. Default definitions have been given, but its strongly + * recommended that users never use these definitions for any + * reason (they do *NOT* deliver any serious guarantee of + * improved performance -- not in this file, nor any vendor's + * stdint.h). + * + * 12) The following macros: + * + * PRINTF_INTMAX_MODIFIER + * PRINTF_INT64_MODIFIER + * PRINTF_INT32_MODIFIER + * PRINTF_INT16_MODIFIER + * PRINTF_LEAST64_MODIFIER + * PRINTF_LEAST32_MODIFIER + * PRINTF_LEAST16_MODIFIER + * PRINTF_INTPTR_MODIFIER + * + * are strings which have been defined as the modifiers required + * for the "d", "u" and "x" printf formats to correctly output + * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t, + * (u)least32_t, (u)least16_t and (u)intptr_t types respectively. + * PRINTF_INTPTR_MODIFIER is not defined for some systems which + * provide their own stdint.h. PRINTF_INT64_MODIFIER is not + * defined if INT64_MAX is not defined. These are an extension + * beyond what C99 specifies must be in stdint.h. + * + * In addition, the following macros are defined: + * + * PRINTF_INTMAX_HEX_WIDTH + * PRINTF_INT64_HEX_WIDTH + * PRINTF_INT32_HEX_WIDTH + * PRINTF_INT16_HEX_WIDTH + * PRINTF_INT8_HEX_WIDTH + * PRINTF_INTMAX_DEC_WIDTH + * PRINTF_INT64_DEC_WIDTH + * PRINTF_INT32_DEC_WIDTH + * PRINTF_INT16_DEC_WIDTH + * PRINTF_INT8_DEC_WIDTH + * + * Which specifies the maximum number of characters required to + * print the number of that type in either hexadecimal or decimal. + * These are an extension beyond what C99 specifies must be in + * stdint.h. + * + * Compilers tested (all with 0 warnings at their highest respective + * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32 + * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio + * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3 + * + * This file should be considered a work in progress. Suggestions for + * improvements, especially those which increase coverage are strongly + * encouraged. + * + * Acknowledgements + * + * The following people have made significant contributions to the + * development and testing of this file: + * + * Chris Howie + * John Steele Scott + * Dave Thorup + * + */ + +#include +#include +#include + +/* + * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and + * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. + */ + +#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED) +#include +#define _PSTDINT_H_INCLUDED +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER +# endif +# ifndef PRINTF_INT64_HEX_WIDTH +# define PRINTF_INT64_HEX_WIDTH "16" +# endif +# ifndef PRINTF_INT32_HEX_WIDTH +# define PRINTF_INT32_HEX_WIDTH "8" +# endif +# ifndef PRINTF_INT16_HEX_WIDTH +# define PRINTF_INT16_HEX_WIDTH "4" +# endif +# ifndef PRINTF_INT8_HEX_WIDTH +# define PRINTF_INT8_HEX_WIDTH "2" +# endif +# ifndef PRINTF_INT64_DEC_WIDTH +# define PRINTF_INT64_DEC_WIDTH "20" +# endif +# ifndef PRINTF_INT32_DEC_WIDTH +# define PRINTF_INT32_DEC_WIDTH "10" +# endif +# ifndef PRINTF_INT16_DEC_WIDTH +# define PRINTF_INT16_DEC_WIDTH "5" +# endif +# ifndef PRINTF_INT8_DEC_WIDTH +# define PRINTF_INT8_DEC_WIDTH "3" +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH +# endif + +/* + * Something really weird is going on with Open Watcom. Just pull some of + * these duplicated definitions from Open Watcom's stdint.h file for now. + */ + +# if defined (__WATCOMC__) && __WATCOMC__ >= 1250 +# if !defined (INT64_C) +# define INT64_C(x) (x + (INT64_MAX - INT64_MAX)) +# endif +# if !defined (UINT64_C) +# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) +# endif +# if !defined (INT32_C) +# define INT32_C(x) (x + (INT32_MAX - INT32_MAX)) +# endif +# if !defined (UINT32_C) +# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX)) +# endif +# if !defined (INT16_C) +# define INT16_C(x) (x) +# endif +# if !defined (UINT16_C) +# define UINT16_C(x) (x) +# endif +# if !defined (INT8_C) +# define INT8_C(x) (x) +# endif +# if !defined (UINT8_C) +# define UINT8_C(x) (x) +# endif +# if !defined (UINT64_MAX) +# define UINT64_MAX 18446744073709551615ULL +# endif +# if !defined (INT64_MAX) +# define INT64_MAX 9223372036854775807LL +# endif +# if !defined (UINT32_MAX) +# define UINT32_MAX 4294967295UL +# endif +# if !defined (INT32_MAX) +# define INT32_MAX 2147483647L +# endif +# if !defined (INTMAX_MAX) +# define INTMAX_MAX INT64_MAX +# endif +# if !defined (INTMAX_MIN) +# define INTMAX_MIN INT64_MIN +# endif +# endif +#endif + +#ifndef _PSTDINT_H_INCLUDED +#define _PSTDINT_H_INCLUDED + +#ifndef SIZE_MAX +# define SIZE_MAX (~(size_t)0) +#endif + +/* + * Deduce the type assignments from limits.h under the assumption that + * integer sizes in bits are powers of 2, and follow the ANSI + * definitions. + */ + +#ifndef UINT8_MAX +# define UINT8_MAX 0xff +#endif +#ifndef uint8_t +# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) + typedef unsigned char uint8_t; +# define UINT8_C(v) ((uint8_t) v) +# else +# error "Platform not supported" +# endif +#endif + +#ifndef INT8_MAX +# define INT8_MAX 0x7f +#endif +#ifndef INT8_MIN +# define INT8_MIN INT8_C(0x80) +#endif +#ifndef int8_t +# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S) + typedef signed char int8_t; +# define INT8_C(v) ((int8_t) v) +# else +# error "Platform not supported" +# endif +#endif + +#ifndef UINT16_MAX +# define UINT16_MAX 0xffff +#endif +#ifndef uint16_t +#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S) + typedef unsigned int uint16_t; +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +# define UINT16_C(v) ((uint16_t) (v)) +#elif (USHRT_MAX == UINT16_MAX) + typedef unsigned short uint16_t; +# define UINT16_C(v) ((uint16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT16_MAX +# define INT16_MAX 0x7fff +#endif +#ifndef INT16_MIN +# define INT16_MIN INT16_C(0x8000) +#endif +#ifndef int16_t +#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) + typedef signed int int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "" +# endif +#elif (SHRT_MAX == INT16_MAX) + typedef signed short int16_t; +# define INT16_C(v) ((int16_t) (v)) +# ifndef PRINTF_INT16_MODIFIER +# define PRINTF_INT16_MODIFIER "h" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef UINT32_MAX +# define UINT32_MAX (0xffffffffUL) +#endif +#ifndef uint32_t +#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S) + typedef unsigned long uint32_t; +# define UINT32_C(v) v ## UL +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (UINT_MAX == UINT32_MAX) + typedef unsigned int uint32_t; +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +# define UINT32_C(v) v ## U +#elif (USHRT_MAX == UINT32_MAX) + typedef unsigned short uint32_t; +# define UINT32_C(v) ((unsigned short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +#ifndef INT32_MAX +# define INT32_MAX (0x7fffffffL) +#endif +#ifndef INT32_MIN +# define INT32_MIN INT32_C(0x80000000) +#endif +#ifndef int32_t +#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S) + typedef signed long int32_t; +# define INT32_C(v) v ## L +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "l" +# endif +#elif (INT_MAX == INT32_MAX) + typedef signed int int32_t; +# define INT32_C(v) v +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#elif (SHRT_MAX == INT32_MAX) + typedef signed short int32_t; +# define INT32_C(v) ((short) (v)) +# ifndef PRINTF_INT32_MODIFIER +# define PRINTF_INT32_MODIFIER "" +# endif +#else +#error "Platform not supported" +#endif +#endif + +/* + * The macro stdint_int64_defined is temporarily used to record + * whether or not 64 integer support is available. It must be + * defined for any 64 integer extensions for new platforms that are + * added. + */ + +#undef stdint_int64_defined +#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) +# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S) +# define stdint_int64_defined + typedef long long int64_t; + typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# endif +#endif + +#if !defined (stdint_int64_defined) +# if defined(__GNUC__) +# define stdint_int64_defined + __extension__ typedef long long int64_t; + __extension__ typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) +# define stdint_int64_defined + typedef long long int64_t; + typedef unsigned long long uint64_t; +# define UINT64_C(v) v ## ULL +# define INT64_C(v) v ## LL +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "ll" +# endif +# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) +# define stdint_int64_defined + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# define UINT64_C(v) v ## UI64 +# define INT64_C(v) v ## I64 +# ifndef PRINTF_INT64_MODIFIER +# define PRINTF_INT64_MODIFIER "I64" +# endif +# endif +#endif + +#if !defined (LONG_LONG_MAX) && defined (INT64_C) +# define LONG_LONG_MAX INT64_C (9223372036854775807) +#endif +#ifndef ULONG_LONG_MAX +# define ULONG_LONG_MAX UINT64_C (18446744073709551615) +#endif + +#if !defined (INT64_MAX) && defined (INT64_C) +# define INT64_MAX INT64_C (9223372036854775807) +#endif +#if !defined (INT64_MIN) && defined (INT64_C) +# define INT64_MIN INT64_C (-9223372036854775808) +#endif +#if !defined (UINT64_MAX) && defined (INT64_C) +# define UINT64_MAX UINT64_C (18446744073709551615) +#endif + +/* + * Width of hexadecimal for number field. + */ + +#ifndef PRINTF_INT64_HEX_WIDTH +# define PRINTF_INT64_HEX_WIDTH "16" +#endif +#ifndef PRINTF_INT32_HEX_WIDTH +# define PRINTF_INT32_HEX_WIDTH "8" +#endif +#ifndef PRINTF_INT16_HEX_WIDTH +# define PRINTF_INT16_HEX_WIDTH "4" +#endif +#ifndef PRINTF_INT8_HEX_WIDTH +# define PRINTF_INT8_HEX_WIDTH "2" +#endif + +#ifndef PRINTF_INT64_DEC_WIDTH +# define PRINTF_INT64_DEC_WIDTH "20" +#endif +#ifndef PRINTF_INT32_DEC_WIDTH +# define PRINTF_INT32_DEC_WIDTH "10" +#endif +#ifndef PRINTF_INT16_DEC_WIDTH +# define PRINTF_INT16_DEC_WIDTH "5" +#endif +#ifndef PRINTF_INT8_DEC_WIDTH +# define PRINTF_INT8_DEC_WIDTH "3" +#endif + +/* + * Ok, lets not worry about 128 bit integers for now. Moore's law says + * we don't need to worry about that until about 2040 at which point + * we'll have bigger things to worry about. + */ + +#ifdef stdint_int64_defined + typedef int64_t intmax_t; + typedef uint64_t uintmax_t; +# define INTMAX_MAX INT64_MAX +# define INTMAX_MIN INT64_MIN +# define UINTMAX_MAX UINT64_MAX +# define UINTMAX_C(v) UINT64_C(v) +# define INTMAX_C(v) INT64_C(v) +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH +# endif +#else + typedef int32_t intmax_t; + typedef uint32_t uintmax_t; +# define INTMAX_MAX INT32_MAX +# define UINTMAX_MAX UINT32_MAX +# define UINTMAX_C(v) UINT32_C(v) +# define INTMAX_C(v) INT32_C(v) +# ifndef PRINTF_INTMAX_MODIFIER +# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER +# endif +# ifndef PRINTF_INTMAX_HEX_WIDTH +# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH +# endif +# ifndef PRINTF_INTMAX_DEC_WIDTH +# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH +# endif +#endif + +/* + * Because this file currently only supports platforms which have + * precise powers of 2 as bit sizes for the default integers, the + * least definitions are all trivial. Its possible that a future + * version of this file could have different definitions. + */ + +#ifndef stdint_least_defined + typedef int8_t int_least8_t; + typedef uint8_t uint_least8_t; + typedef int16_t int_least16_t; + typedef uint16_t uint_least16_t; + typedef int32_t int_least32_t; + typedef uint32_t uint_least32_t; +# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER +# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER +# define UINT_LEAST8_MAX UINT8_MAX +# define INT_LEAST8_MAX INT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define INT_LEAST16_MAX INT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# ifdef stdint_int64_defined + typedef int64_t int_least64_t; + typedef uint64_t uint_least64_t; +# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER +# define UINT_LEAST64_MAX UINT64_MAX +# define INT_LEAST64_MAX INT64_MAX +# define INT_LEAST64_MIN INT64_MIN +# endif +#endif +#undef stdint_least_defined + +/* + * The ANSI C committee pretending to know or specify anything about + * performance is the epitome of misguided arrogance. The mandate of + * this file is to *ONLY* ever support that absolute minimum + * definition of the fast integer types, for compatibility purposes. + * No extensions, and no attempt to suggest what may or may not be a + * faster integer type will ever be made in this file. Developers are + * warned to stay away from these types when using this or any other + * stdint.h. + */ + +typedef int_least8_t int_fast8_t; +typedef uint_least8_t uint_fast8_t; +typedef int_least16_t int_fast16_t; +typedef uint_least16_t uint_fast16_t; +typedef int_least32_t int_fast32_t; +typedef uint_least32_t uint_fast32_t; +#define UINT_FAST8_MAX UINT_LEAST8_MAX +#define INT_FAST8_MAX INT_LEAST8_MAX +#define UINT_FAST16_MAX UINT_LEAST16_MAX +#define INT_FAST16_MAX INT_LEAST16_MAX +#define UINT_FAST32_MAX UINT_LEAST32_MAX +#define INT_FAST32_MAX INT_LEAST32_MAX +#define INT_FAST8_MIN INT_LEAST8_MIN +#define INT_FAST16_MIN INT_LEAST16_MIN +#define INT_FAST32_MIN INT_LEAST32_MIN +#ifdef stdint_int64_defined + typedef int_least64_t int_fast64_t; + typedef uint_least64_t uint_fast64_t; +# define UINT_FAST64_MAX UINT_LEAST64_MAX +# define INT_FAST64_MAX INT_LEAST64_MAX +# define INT_FAST64_MIN INT_LEAST64_MIN +#endif + +#undef stdint_int64_defined + +/* + * Whatever piecemeal, per compiler thing we can do about the wchar_t + * type limits. + */ + +#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__) +# include +# ifndef WCHAR_MIN +# define WCHAR_MIN 0 +# endif +# ifndef WCHAR_MAX +# define WCHAR_MAX ((wchar_t)-1) +# endif +#endif + +/* + * Whatever piecemeal, per compiler/platform thing we can do about the + * (u)intptr_t types and limits. + */ + +#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED) +# define STDINT_H_UINTPTR_T_DEFINED +#endif + +#ifndef STDINT_H_UINTPTR_T_DEFINED +# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) +# define stdint_intptr_bits 64 +# elif defined (__WATCOMC__) || defined (__TURBOC__) +# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) +# define stdint_intptr_bits 16 +# else +# define stdint_intptr_bits 32 +# endif +# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) +# define stdint_intptr_bits 32 +# elif defined (__INTEL_COMPILER) +/* TODO -- what will Intel do about x86-64? */ +# endif + +# ifdef stdint_intptr_bits +# define stdint_intptr_glue3_i(a,b,c) a##b##c +# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c) +# ifndef PRINTF_INTPTR_MODIFIER +# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER) +# endif +# ifndef PTRDIFF_MAX +# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) +# endif +# ifndef PTRDIFF_MIN +# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) +# endif +# ifndef UINTPTR_MAX +# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX) +# endif +# ifndef INTPTR_MAX +# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) +# endif +# ifndef INTPTR_MIN +# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) +# endif +# ifndef INTPTR_C +# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x) +# endif +# ifndef UINTPTR_C +# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x) +# endif + typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; + typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; +# else +/* TODO -- This following is likely wrong for some platforms, and does + nothing for the definition of uintptr_t. */ + typedef ptrdiff_t intptr_t; +# endif +# define STDINT_H_UINTPTR_T_DEFINED +#endif + +/* + * Assumes sig_atomic_t is signed and we have a 2s complement machine. + */ + +#ifndef SIG_ATOMIC_MAX +# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1) +#endif + +#endif diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt b/indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt new file mode 100644 index 000000000..635765c83 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt @@ -0,0 +1,3 @@ +# -*- cmake -*- + +add_subdirectory(src) diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro b/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro new file mode 100644 index 000000000..c031e1971 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +win32: CONFIG += console +mac:CONFIG -= app_bundle + +CONFIG += qtestlib + +include(../../src/src.pri) + +# Input +SOURCES += tst_trie.cpp +HEADERS += diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp new file mode 100644 index 000000000..e4bdc6d4e --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp @@ -0,0 +1,270 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include + +class tst_Trie : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void trie_data(); + void trie(); + + void insert_data(); + void insert(); + void clear(); + void find_data(); + void find(); + void remove_data(); + void remove(); + void all(); +}; + +// Subclass that exposes the protected functions. +class SubTrie : public Trie +{ +public: + +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_Trie::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_Trie::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_Trie::init() +{ +} + +// This will be called after every test function. +void tst_Trie::cleanup() +{ +} + +void tst_Trie::trie_data() +{ +} + +void tst_Trie::trie() +{ + SubTrie t; + t.clear(); + QCOMPARE(t.find(QStringList()), QList()); + QCOMPARE(t.remove(QStringList(), -1), false); + QCOMPARE(t.all(), QList()); + t.insert(QStringList(), -1); +} + +void tst_Trie::insert_data() +{ +#if 0 + QTest::addColumn("key"); + QTest::addColumn("value"); + QTest::newRow("null") << QStringList() << T(); +#endif +} + +// public void insert(QStringList const& key, T value) +void tst_Trie::insert() +{ +#if 0 + QFETCH(QStringList, key); + QFETCH(T, value); + + SubTrie t>; + + t>.insert(key, value); +#endif + QSKIP("Test is not implemented.", SkipAll); +} + +// public void clear() +void tst_Trie::clear() +{ + SubTrie t; + t.insert(QStringList(), 0); + t.clear(); + QCOMPARE(t.find(QStringList()), QList()); + QCOMPARE(t.all(), QList()); +} + +Q_DECLARE_METATYPE(QStringList) +typedef QList IntList; +Q_DECLARE_METATYPE(IntList) +void tst_Trie::find_data() +{ + QTest::addColumn("keys"); + QTest::addColumn("values"); + QTest::addColumn("find"); + QTest::addColumn("found"); + + QTest::newRow("null") << QStringList() << IntList() << QStringList() << IntList(); + + QStringList wiki = (QStringList() << "t,e,a" << "i" << "t,e,n" << "i,n" << "i,n,n" << "t,o"); + IntList wikiNum = (IntList() << 3 << 11 << 12 << 5 << 9 << 7); + + QTest::newRow("wikipedia-0") + << wiki + << wikiNum + << (QStringList() << "t") + << (IntList()); + + QTest::newRow("wikipedia-1") + << wiki + << wikiNum + << (QStringList() << "t" << "o") + << (IntList() << 7); + + QTest::newRow("wikipedia-2") + << (wiki << "t,o") + << (wikiNum << 4) + << (QStringList() << "t" << "o") + << (IntList() << 7 << 4); + + QTest::newRow("wikipedia-3") + << wiki + << wikiNum + << (QStringList() << "i" << "n" << "n") + << (IntList() << 9); + +} + +// public QList const find(QStringList const& key) +void tst_Trie::find() +{ + QFETCH(QStringList, keys); + QFETCH(IntList, values); + QFETCH(QStringList, find); + QFETCH(IntList, found); + + SubTrie t; + for (int i = 0; i < keys.count(); ++i) + t.insert(keys[i].split(","), values[i]); + QCOMPARE(t.all(), values); + QCOMPARE(t.find(find), found); +} + +void tst_Trie::remove_data() +{ + QTest::addColumn("keys"); + QTest::addColumn("values"); + QTest::addColumn("removeKey"); + QTest::addColumn("removeValue"); + QTest::addColumn("removed"); + + QTest::newRow("null") << QStringList() << IntList() << QStringList() << -1 << false; + + QStringList wiki = (QStringList() << "t,e,a" << "i" << "t,e,n" << "i,n" << "i,n,n" << "t,o"); + IntList wikiNum = (IntList() << 3 << 11 << 12 << 5 << 9 << 7); + + QTest::newRow("valid key-0") + << wiki + << wikiNum + << (QStringList() << "t") + << -1 + << false; + + QTest::newRow("valid key-1") + << wiki + << wikiNum + << (QStringList() << "t" << "o") + << -1 + << false; + + QTest::newRow("valid key-2") + << wiki + << wikiNum + << (QStringList() << "t" << "o" << "w") + << 2 + << false; + + QTest::newRow("valid key-3") + << wiki + << wikiNum + << (QStringList() << "t" << "o") + << 7 + << true; + + QTest::newRow("valid key-4") + << wiki + << wikiNum + << (QStringList() << "i" << "n") + << 3 + << false; + + QTest::newRow("valid key-5") + << wiki + << wikiNum + << (QStringList() << "i" << "n") + << 5 + << true; + +} + +// public bool remove(QStringList const& key, T value) +void tst_Trie::remove() +{ + QFETCH(QStringList, keys); + QFETCH(IntList, values); + QFETCH(QStringList, removeKey); + QFETCH(int, removeValue); + QFETCH(bool, removed); + + SubTrie t; + for (int i = 0; i < keys.count(); ++i) + t.insert(keys[i].split(","), values[i]); + QCOMPARE(t.all(), values); + QCOMPARE(t.remove(removeKey, removeValue), removed); + if (removed) + values.removeOne(removeValue); + QCOMPARE(t.all(), values); +} + +void tst_Trie::all() +{ + SubTrie t; + // hmm everyone else tests this it seems + QSKIP("Test is not implemented.", SkipAll); +} + +QTEST_MAIN(tst_Trie) +#include "tst_trie.moc" + diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro b/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro new file mode 100644 index 000000000..350fbc0f6 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro @@ -0,0 +1,17 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +win32: CONFIG += console +mac:CONFIG -= app_bundle + +CONFIG += qtestlib + +include(../../src/src.pri) +#include(../../../dev/code/webweaver/src/iris.pri) +#include(../../../dev/arora/src/src.pri) + +# Input +SOURCES += main.cpp +HEADERS += diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp new file mode 100644 index 000000000..863d6b0be --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp @@ -0,0 +1,159 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include +#include + +class CookieJarBenchmark: public QObject { + Q_OBJECT + +private slots: + void setCookiesFromUrl(); + void cookiesForUrl(); + void player(); + +private: + QNetworkCookieJar *getJar(bool populate = true); + QList generateCookies(int size); +}; + +QNetworkCookieJar *CookieJarBenchmark::getJar(bool populate) +{ + QNetworkCookieJar *jar; + if (qgetenv("JAR") == "CookieJar") { + jar = new NetworkCookieJar(this); + } else { + jar = new QNetworkCookieJar(this); + } + if (!populate) + return jar; + + // pre populate + for (int i = 0; i < 500; ++i) { + QList cookies = generateCookies(1); + QUrl url = QUrl(QString("http://%1").arg(cookies[0].domain())); + jar->setCookiesFromUrl(cookies, url); + } + + return jar; +} + +QList CookieJarBenchmark::generateCookies(int size) +{ + QList cookies; + for (int i = 0; i < size; ++i) { + QNetworkCookie cookie; + + QString tld; + int c = qrand() % 3; + if (c == 0) tld = "com"; + if (c == 1) tld = "net"; + if (c == 2) tld = "org"; + + QString mid; + int size = qrand() % 6 + 3; + while (mid.count() < size) + mid += QString(QChar::fromAscii(qrand() % 26 + 65)); + + QString sub; + c = qrand() % 3; + if (c == 0) sub = "."; + if (c == 1) sub = ".www."; + if (c == 2) sub = ".foo"; + + cookie.setDomain(QString("%1%2.%3").arg(sub).arg(mid).arg(tld)); + cookie.setName("a"); + cookie.setValue("b"); + cookie.setPath("/"); + cookies.append(cookie); + } + return cookies; +} + +void CookieJarBenchmark::setCookiesFromUrl() +{ + QNetworkCookieJar *jar = getJar(); + QList cookies = generateCookies(1); + QUrl url = QUrl(QString("http://%1").arg(cookies[0].domain())); + QBENCHMARK { + jar->setCookiesFromUrl(cookies, url); + } + delete jar; +} + +void CookieJarBenchmark::cookiesForUrl() +{ + QNetworkCookieJar *jar = getJar(); + QList cookies = generateCookies(1); + cookies[0].setDomain("www.foo.tld"); + QUrl url = QUrl("http://www.foo.tld"); + //QUrl url = QUrl(QString("http://foo%1/").arg(cookies[0].domain())); + jar->setCookiesFromUrl(cookies, url); + //qDebug() << cookies << url; + int c = 0; + QBENCHMARK { + c += jar->cookiesForUrl(url).count(); + } + delete jar; +} + +// Grab the cookie.log file from the manualtest/browser directory +void CookieJarBenchmark::player() +{ + QBENCHMARK { + QFile file("cookie.log"); + file.open(QFile::ReadOnly); + QDataStream stream(&file); + QNetworkCookieJar *jar = getJar(false); + while (!stream.atEnd()) { + QString command; + QUrl url; + stream >> command; + stream >> url; + //qDebug() << command << url; + if (command == "cookiesForUrl") { + jar->cookiesForUrl(url); + } + if (command == "setCookiesFromUrl") { + QByteArray data; + stream >> data; + QDataStream dstream(&data, QIODevice::ReadWrite); + qint32 c; + dstream >> c; + QList cookies; + for (int i = 0; i < c; ++i) { + QByteArray text; + dstream >> text; + cookies += QNetworkCookie::parseCookies(text); + } + jar->setCookiesFromUrl(cookies, url); + } + } + } +} + +QTEST_MAIN(CookieJarBenchmark) +#include "main.moc" diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro new file mode 100644 index 000000000..a363bbefc --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro @@ -0,0 +1,11 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Wed Jan 7 13:19:00 2009 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +include(../../src/src.pri) +# Input +SOURCES += main.cpp diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp new file mode 100644 index 000000000..6d21759fc --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp @@ -0,0 +1,85 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include +#include +#include + +QFile file; +QDataStream stream; + +class CookieLog : public NetworkCookieJar { + + Q_OBJECT + +public: + CookieLog(QObject *parent = 0) : NetworkCookieJar(parent) + { + file.setFileName("cookie.log"); + file.open(QFile::WriteOnly); + stream.setDevice(&file); + }; + + virtual QList cookiesForUrl(const QUrl & url) const + { + stream << QString("cookiesForUrl") << url; + QList cookies = NetworkCookieJar::cookiesForUrl(url); + //stream << "#" << cookies; + file.flush(); + return cookies; + } + + virtual bool setCookiesFromUrl(const QList &cookieList, const QUrl &url) + { + QByteArray data; + QDataStream dstream(&data, QIODevice::ReadWrite); + qint32 c = cookieList.count(); + dstream << c; + qDebug() << cookieList.count(); + for (int i = 0; i < c; ++i) + dstream << cookieList[i].toRawForm(); + dstream.device()->close(); + stream << QString("setCookiesFromUrl") << url << data;// << cookieList; + bool set = NetworkCookieJar::setCookiesFromUrl(cookieList, url); + file.flush(); + return set; + } + +}; + +int main(int argc, char**argv) { + QApplication application(argc, argv); + QWebView view; + QString url = "http://www.google.com"; + if (argc > 1) + url = argv[1]; + view.load(QUrl(url)); + view.page()->networkAccessManager()->setCookieJar(new CookieLog()); + view.show(); + return application.exec(); +} + +#include "main.moc" diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro new file mode 100644 index 000000000..0ad65f1bf --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro @@ -0,0 +1,12 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Wed Jan 7 13:19:00 2009 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +include(../../src/src.pri) +DEFINES += QT_NO_CAST_FROM_ASCII QT_STRICT_ITERATOR +# Input +SOURCES += main.cpp diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp new file mode 100644 index 000000000..28c79a1c2 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp @@ -0,0 +1,100 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include + +QStringList generateKey() { + QStringList key; + int size = qrand() % 20 + 3; + while (key.count() < size) + key += QString(QChar::fromAscii(qrand() % 26 + 64)); + return key; +} + +void basicCheck() { + QStringList list; + list << QLatin1String("to") << QLatin1String("tea") << QLatin1String("ten") << QLatin1String("i") << QLatin1String("in") << QLatin1String("inn"); + Trie trie; + for (int i = 0; i < list.count(); ++i) { + QString key = list[i]; + QStringList keyList; + for (int j = 0; j < key.count(); ++j) + keyList.append(QString(key[j])); + trie.insert(keyList, i); + } + QByteArray data; + { + QDataStream stream(&data, QIODevice::ReadWrite); + stream << trie; + } + Trie trie2; + { + QDataStream stream(&data, QIODevice::ReadOnly); + stream >> trie2; + } + for (int i = 0; i < list.count(); ++i) { + QString key = list[i]; + QStringList keyList; + for (int j = 0; j < key.count(); ++j) + keyList.append(QString(key[j])); + QList x = trie2.find(keyList); + qDebug() << x.count() << i << x[0] << i; + qDebug() << trie2.remove(keyList, i); + qDebug() << trie2.find(keyList).count(); + } +} + +int main(int argc, char **argv) { + Q_UNUSED(argc); + Q_UNUSED(argv); + + basicCheck(); + + QHash hash; + Trie t; + while (hash.count() < 500) { + qDebug() << hash.count(); + QStringList key = generateKey(); + int value = qrand() % 50000; + hash[key.join(QLatin1String(","))] = value; + t.insert(key, value); + + QHashIterator i(hash); + while (i.hasNext()) { + i.next(); + if (t.find(i.key().split(QLatin1Char(','))).count() == 0) + qDebug() << i.key(); + Q_ASSERT(t.find(i.key().split(QLatin1Char(','))).count() > 0); + if (qrand() % 500 == 0) { + t.remove(i.key().split(QLatin1Char(',')), i.value()); + hash.remove(i.key()); + } + //cout << i.key() << ": " << i.value() << endl; + } + } + return 0; +} + diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt b/indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt new file mode 100644 index 000000000..20bacf3eb --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt @@ -0,0 +1,27 @@ +# -*- cmake -*- + +project(networkcookiejar) + +set(networkcookiejar_SOURCE_FILES + networkcookiejar.cpp + ) + +set(networkcookiejar_HEADER_FILES + networkcookiejar.h + networkcookiejar_p.h + trie_p.h + twoleveldomains_p.h + + ) + +QT4_WRAP_CPP(networkcookiejar_HEADERS_MOC ${networkcookiejar_HEADER_FILES}) + +add_library(networkcookiejar + ${networkcookiejar_SOURCE_FILES} + ${networkcookiejar_HEADERS_MOC} + ${networkcookiejar_UI_MOC} +) + +add_dependencies(networkcookiejar prepare) + +target_link_libraries(networkcookiejar) \ No newline at end of file diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp new file mode 100644 index 000000000..274d9e1c1 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp @@ -0,0 +1,444 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include "networkcookiejar.h" +#include "networkcookiejar_p.h" +#include "twoleveldomains_p.h" + +//#define NETWORKCOOKIEJAR_DEBUG + +#ifndef QT_NO_DEBUG +// ^ Prevent being left on in a released product by accident +// qDebug any cookies that are rejected for further inspection +#define NETWORKCOOKIEJAR_LOGREJECTEDCOOKIES +#include +#endif + +#include +#include + +#if defined(NETWORKCOOKIEJAR_DEBUG) +#include +#endif + + +NetworkCookieJar::NetworkCookieJar(QObject *parent) + : QNetworkCookieJar(parent) +{ + d = new NetworkCookieJarPrivate; +} + +NetworkCookieJar::~NetworkCookieJar() +{ + delete d; +} + +static QStringList splitHost(const QString &host) { + QStringList parts = host.split(QLatin1Char('.'), QString::KeepEmptyParts); + // Remove empty components that are on the start and end + while (!parts.isEmpty() && parts.last().isEmpty()) + parts.removeLast(); + while (!parts.isEmpty() && parts.first().isEmpty()) + parts.removeFirst(); + return parts; +} + +inline static bool shorterPaths(const QNetworkCookie &c1, const QNetworkCookie &c2) +{ + return c2.path().length() < c1.path().length(); +} + +QList NetworkCookieJar::cookiesForUrl(const QUrl &url) const +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << url; +#endif + // Generate split host + QString host = url.host(); + if (url.scheme().toLower() == QLatin1String("file")) + host = QLatin1String("localhost"); + QStringList urlHost = splitHost(host); + + // Get all the cookies for url + QList cookies = d->tree.find(urlHost); + if (urlHost.count() > 2) { + int top = 2; + if (d->matchesBlacklist(urlHost.last())) + top = 3; + + urlHost.removeFirst(); + while (urlHost.count() >= top) { + cookies += d->tree.find(urlHost); + urlHost.removeFirst(); + } + } + + // Prevent doing anything expensive in the common case where + // there are no cookies to check + if (cookies.isEmpty()) + return cookies; + + QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); + const QString urlPath = d->urlPath(url); + const bool isSecure = url.scheme().toLower() == QLatin1String("https"); + QList::iterator i = cookies.begin(); + for (; i != cookies.end();) { + if (!d->matchingPath(*i, urlPath)) { +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << __FUNCTION__ << "Ignoring cookie, path does not match" << *i << urlPath; +#endif + i = cookies.erase(i); + continue; + } + if (!isSecure && i->isSecure()) { + i = cookies.erase(i); +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << __FUNCTION__ << "Ignoring cookie, security mismatch" + << *i << !isSecure; +#endif + continue; + } + if (!i->isSessionCookie() && now > i->expirationDate()) { + // remove now (expensive short term) because there will + // probably be many more cookiesForUrl calls for this host + d->tree.remove(splitHost(i->domain()), *i); +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << __FUNCTION__ << "Ignoring cookie, expiration issue" + << *i << now; +#endif + i = cookies.erase(i); + continue; + } + ++i; + } + + // shorter paths should go first + qSort(cookies.begin(), cookies.end(), shorterPaths); +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "returning" << cookies.count(); + qDebug() << cookies; +#endif + return cookies; +} + +static const qint32 NetworkCookieJarMagic = 0xae; + +QByteArray NetworkCookieJar::saveState () const +{ + int version = 1; + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + + stream << qint32(NetworkCookieJarMagic); + stream << qint32(version); + stream << d->tree; + return data; +} + +bool NetworkCookieJar::restoreState(const QByteArray &state) +{ + int version = 1; + QByteArray sd = state; + QDataStream stream(&sd, QIODevice::ReadOnly); + if (stream.atEnd()) + return false; + qint32 marker; + qint32 v; + stream >> marker; + stream >> v; + if (marker != NetworkCookieJarMagic || v != version) + return false; + stream >> d->tree; + if (stream.status() != QDataStream::Ok) { + d->tree.clear(); + return false; + } + return true; +} + +/*! + Remove any session cookies or cookies that have expired. + */ +void NetworkCookieJar::endSession() +{ + const QList cookies = d->tree.all(); + QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); + QList::const_iterator i = cookies.constBegin(); + for (; i != cookies.constEnd();) { + if (i->isSessionCookie() + || (!i->isSessionCookie() && now > i->expirationDate())) { + d->tree.remove(splitHost(i->domain()), *i); + } + ++i; + } +} + +static const int maxCookiePathLength = 1024; + +bool NetworkCookieJar::setCookiesFromUrl(const QList &cookieList, const QUrl &url) +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << url; + qDebug() << cookieList; +#endif + QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); + bool changed = false; + QString fullUrlPath = url.path(); + QString defaultPath = fullUrlPath.mid(0, fullUrlPath.lastIndexOf(QLatin1Char('/')) + 1); + if (defaultPath.isEmpty()) + defaultPath = QLatin1Char('/'); + + QString urlPath = d->urlPath(url); + foreach (QNetworkCookie cookie, cookieList) { + if (cookie.path().length() > maxCookiePathLength) + continue; + + bool alreadyDead = !cookie.isSessionCookie() && cookie.expirationDate() < now; + + if (cookie.path().isEmpty()) { + cookie.setPath(defaultPath); + } + // Matching the behavior of Firefox, no path checking is done when setting cookies + // Safari does something even odder, when that paths don't match it keeps + // the cookie, but changes the paths to the default path +#if 0 + else if (!d->matchingPath(cookie, urlPath)) { +#ifdef NETWORKCOOKIEJAR_LOGREJECTEDCOOKIES + qDebug() << "NetworkCookieJar::" << __FUNCTION__ + << "Blocked cookie because: path doesn't match: " << cookie << url; +#endif + continue; + } +#endif + + if (cookie.domain().isEmpty()) { + QString host = url.host().toLower(); + if (host.isEmpty()) + continue; + cookie.setDomain(host); + } else if (!d->matchingDomain(cookie, url)) { +#ifdef NETWORKCOOKIEJAR_LOGREJECTEDCOOKIES + qDebug() << "NetworkCookieJar::" << __FUNCTION__ + << "Blocked cookie because: domain doesn't match: " << cookie << url; +#endif + continue; + } + + // replace/remove existing cookies + removeCookie(cookie); + + // Notify derived class + onCookieSetFromURL(cookie, url, alreadyDead); + + if (alreadyDead) + continue; + + changed = true; + d->tree.insert(splitHost(cookie.domain()), cookie); + } + + return changed; +} + +QList NetworkCookieJar::allCookies() const +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__; +#endif + return d->tree.all(); +} + +void NetworkCookieJar::clearCookies() +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__; +#endif + d->tree.clear(); +} + +void NetworkCookieJar::setCookies(const QList &cookieList) +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << cookieList.count(); +#endif + + QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); + + foreach (const QNetworkCookie &cookie, cookieList) + { + // If a matching cookie is already in the list, remove it. + removeCookie(cookie); + + if(!cookie.isSessionCookie() && cookie.expirationDate() < now) + { +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "removing cookie: " << cookie; +#endif + // This cookie has expired -- don't re-add it + } + else + { +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "adding cookie: " << cookie; +#endif + // this cookie has not expired -- save it + d->tree.insert(splitHost(cookie.domain()), cookie); + } + + } +} + +void NetworkCookieJar::setAllCookies(const QList &cookieList) +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << cookieList.count(); +#endif + clearCookies(); + setCookies(cookieList); +} + +void NetworkCookieJar::removeCookie(const QNetworkCookie &cookie) +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "removing cookie: " << cookie; +#endif + + // If a cookie with the matching domain, path, and name exists in the cookiejar, remove it. + QString domain = cookie.domain(); + Q_ASSERT(!domain.isEmpty()); + QStringList urlHost = splitHost(domain); + + QList cookies = d->tree.find(urlHost); + QList::const_iterator it = cookies.constBegin(); + for (; it != cookies.constEnd(); ++it) + { + if (cookie.name() == it->name() && + domain == it->domain() && + cookie.path() == it->path()) + { +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "found matching cookie: " << *it; +#endif + d->tree.remove(urlHost, *it); + break; + } + } +} + +void NetworkCookieJar::dump() +{ +#if defined(NETWORKCOOKIEJAR_DEBUG) + qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "dumping all cookies: "; + QList cookies = allCookies(); + foreach (const QNetworkCookie &cookie, cookies) + { + qDebug() << " " << cookie; + } +#endif +} + +QString NetworkCookieJarPrivate::urlPath(const QUrl &url) const +{ + QString urlPath = url.path(); + if (!urlPath.endsWith(QLatin1Char('/'))) + urlPath += QLatin1Char('/'); + return urlPath; +} + +bool NetworkCookieJarPrivate::matchingPath(const QNetworkCookie &cookie, const QString &urlPath) const +{ + QString cookiePath = cookie.path(); + if (!cookiePath.endsWith(QLatin1Char('/'))) + cookiePath += QLatin1Char('/'); + + return urlPath.startsWith(cookiePath); +} + +bool NetworkCookieJarPrivate::matchesBlacklist(const QString &string) const +{ + if (!setSecondLevelDomain) { + // Alternatively to save a little bit of ram we could just + // use bsearch on twoLevelDomains in place + for (int j = 0; twoLevelDomains[j]; ++j) + secondLevelDomains += QLatin1String(twoLevelDomains[j]); + setSecondLevelDomain = true; + } + QStringList::const_iterator i = + qBinaryFind(secondLevelDomains.constBegin(), secondLevelDomains.constEnd(), string); + return (i != secondLevelDomains.constEnd()); +} + +bool NetworkCookieJarPrivate::matchingDomain(const QNetworkCookie &cookie, const QUrl &url) const +{ + QString domain = cookie.domain().simplified().toLower(); + domain.remove(QLatin1Char(' ')); + QStringList parts = splitHost(domain); + if (parts.isEmpty()) + return false; + + // When there is only one part only file://localhost/ is accepted + if (parts.count() == 1) { + QString s = parts.first(); + if (parts.first() != QLatin1String("localhost")) + return false; + if (url.scheme().toLower() == QLatin1String("file")) + return true; + } + + // Check for blacklist + if (parts.count() == 2 && matchesBlacklist(parts.last())) + return false; + + QStringList urlParts = url.host().toLower().split(QLatin1Char('.'), QString::SkipEmptyParts); + if (urlParts.isEmpty()) + return false; + while (urlParts.count() > parts.count()) + urlParts.removeFirst(); + + for (int j = 0; j < urlParts.count(); ++j) { + if (urlParts.at(j) != parts.at(j)) { + return false; + } + } + + return true; +} + +void NetworkCookieJar::setSecondLevelDomains(const QStringList &secondLevelDomains) +{ + d->setSecondLevelDomain = true; + d->secondLevelDomains = secondLevelDomains; + qSort(d->secondLevelDomains); +} + + +void NetworkCookieJar::onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead) +{ + Q_UNUSED(cookie); + Q_UNUSED(url); + Q_UNUSED(already_dead); + + // Derived classes can use this to track cookie changes. +} diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h new file mode 100644 index 000000000..86b14fa16 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef NETWORKCOOKIEJAR_H +#define NETWORKCOOKIEJAR_H + +#include + +class NetworkCookieJarPrivate; +class NetworkCookieJar : public QNetworkCookieJar { + Q_OBJECT +public: + NetworkCookieJar(QObject *parent = 0); + ~NetworkCookieJar(); + + virtual QList cookiesForUrl(const QUrl & url) const; + virtual bool setCookiesFromUrl(const QList &cookieList, const QUrl &url); + +protected: + QByteArray saveState() const; + bool restoreState(const QByteArray &state); + void endSession(); + + QList allCookies() const; + void clearCookies(); + void setCookies(const QList &cookieList); + void setAllCookies(const QList &cookieList); + void removeCookie(const QNetworkCookie &cookie); + void dump(); + void setSecondLevelDomains(const QStringList &secondLevelDomains); + + virtual void onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead); + +private: + NetworkCookieJarPrivate *d; +}; + +#endif + diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h new file mode 100644 index 000000000..d8f22cfce --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef NETWORKCOOKIEJARPRIVATE_H +#define NETWORKCOOKIEJARPRIVATE_H + +#include "trie_p.h" + +QT_BEGIN_NAMESPACE +QDataStream &operator<<(QDataStream &stream, const QNetworkCookie &cookie) +{ + stream << cookie.toRawForm(); + return stream; +} + +QDataStream &operator>>(QDataStream &stream, QNetworkCookie &cookie) +{ + QByteArray value; + stream >> value; + QList newCookies = QNetworkCookie::parseCookies(value); + if (!newCookies.isEmpty()) + cookie = newCookies.first(); + return stream; +} +QT_END_NAMESPACE + +class NetworkCookieJarPrivate { +public: + NetworkCookieJarPrivate() + : setSecondLevelDomain(false) + {} + + Trie tree; + mutable bool setSecondLevelDomain; + mutable QStringList secondLevelDomains; + + bool matchesBlacklist(const QString &string) const; + bool matchingDomain(const QNetworkCookie &cookie, const QUrl &url) const; + QString urlPath(const QUrl &url) const; + bool matchingPath(const QNetworkCookie &cookie, const QString &urlPath) const; +}; + +#endif + diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri b/indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri new file mode 100644 index 000000000..78ac273a1 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri @@ -0,0 +1,5 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + +HEADERS += trie_p.h networkcookiejar.h twoleveldomains_p.h networkcookiejar_p.h +SOURCES += networkcookiejar.cpp diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h new file mode 100644 index 000000000..a4959a198 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h @@ -0,0 +1,247 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef TRIE_H +#define TRIE_H + +//#define TRIE_DEBUG + +#include + +#if defined(TRIE_DEBUG) +#include +#endif + +/* + A Trie tree (prefix tree) where the lookup takes m in the worst case. + + The key is stored in *reverse* order + + Example: + Keys: x,a y,a + + Trie: + a + | \ + x y +*/ + +template +class Trie { +public: + Trie(); + ~Trie(); + + void clear(); + void insert(const QStringList &key, const T &value); + bool remove(const QStringList &key, const T &value); + QList find(const QStringList &key) const; + QList all() const; + + inline bool contains(const QStringList &key) const; + inline bool isEmpty() const { return children.isEmpty() && values.isEmpty(); } + +private: + const Trie* walkTo(const QStringList &key) const; + Trie* walkTo(const QStringList &key, bool create = false); + + template friend QDataStream &operator<<(QDataStream &, const Trie&); + template friend QDataStream &operator>>(QDataStream &, Trie&); + + QList values; + QStringList childrenKeys; + QList > children; +}; + +template +Trie::Trie() { +} + +template +Trie::~Trie() { +} + +template +void Trie::clear() { +#if defined(TRIE_DEBUG) + qDebug() << "Trie::" << __FUNCTION__; +#endif + values.clear(); + childrenKeys.clear(); + children.clear(); +} + +template +bool Trie::contains(const QStringList &key) const { + return walkTo(key); +} + +template +void Trie::insert(const QStringList &key, const T &value) { +#if defined(TRIE_DEBUG) + qDebug() << "Trie::" << __FUNCTION__ << key << value; +#endif + Trie *node = walkTo(key, true); + if (node) + node->values.append(value); +} + +template +bool Trie::remove(const QStringList &key, const T &value) { +#if defined(TRIE_DEBUG) + qDebug() << "Trie::" << __FUNCTION__ << key << value; +#endif + Trie *node = walkTo(key, true); + if (node) { + bool removed = node->values.removeOne(value); + if (!removed) + return false; + + // A faster implementation of removing nodes up the tree + // can be created if profile shows this to be slow + QStringList subKey = key; + while (node->values.isEmpty() + && node->children.isEmpty() + && !subKey.isEmpty()) { + QString currentLevelKey = subKey.first(); + QStringList parentKey = subKey.mid(1); + Trie *parent = walkTo(parentKey, false); + Q_ASSERT(parent); + QStringList::iterator iterator; + iterator = qBinaryFind(parent->childrenKeys.begin(), + parent->childrenKeys.end(), + currentLevelKey); + Q_ASSERT(iterator != parent->childrenKeys.end()); + int index = iterator - parent->childrenKeys.begin(); + parent->children.removeAt(index); + parent->childrenKeys.removeAt(index); + + node = parent; + subKey = parentKey; + } + return removed; + } + return false; +} + +template +QList Trie::find(const QStringList &key) const { +#if defined(TRIE_DEBUG) + qDebug() << "Trie::" << __FUNCTION__ << key; +#endif + const Trie *node = walkTo(key); + if (node) + return node->values; + return QList(); +} + +template +QList Trie::all() const { +#if defined(TRIE_DEBUG) + qDebug() << "Trie::" << __FUNCTION__; +#endif + QList all = values; + for (int i = 0; i < children.count(); ++i) + all += children[i].all(); + return all; +} + +template +QDataStream &operator<<(QDataStream &out, const Trie&trie) { + out << trie.values; + out << trie.childrenKeys; + out << trie.children; + Q_ASSERT(trie.childrenKeys.count() == trie.children.count()); + return out; +} + +template +QDataStream &operator>>(QDataStream &in, Trie &trie) { + trie.clear(); + if (in.status() != QDataStream::Ok) + return in; + in >> trie.values; + in >> trie.childrenKeys; + in >> trie.children; + //Q_ASSERT(trie.childrenKeys.count() == trie.children.count()); + if (trie.childrenKeys.count() != trie.children.count()) + in.setStatus(QDataStream::ReadCorruptData); + return in; +} + +// Very fast const walk +template +const Trie* Trie::walkTo(const QStringList &key) const { + const Trie *node = this; + QStringList::const_iterator childIterator; + QStringList::const_iterator begin, end; + + int depth = key.count() - 1; + while (depth >= 0) { + const QString currentLevelKey = key.at(depth--); + begin = node->childrenKeys.constBegin(); + end = node->childrenKeys.constEnd(); + childIterator = qBinaryFind(begin, end, currentLevelKey); + if (childIterator == end) + return 0; + node = &node->children.at(childIterator - begin); + } + return node; +} + +template +Trie* Trie::walkTo(const QStringList &key, bool create) { + QStringList::iterator iterator; + Trie *node = this; + QStringList::iterator begin, end; + int depth = key.count() - 1; + while (depth >= 0) { + const QString currentLevelKey = key.at(depth--); + begin = node->childrenKeys.begin(); + end = node->childrenKeys.end(); + iterator = qBinaryFind(begin, end, currentLevelKey); +#if defined(TRIE_DEBUG) + qDebug() << "\t" << node << key << currentLevelKey << node->childrenKeys; +#endif + int index = -1; + if (iterator == end) { + if (!create) + return 0; + iterator = qLowerBound(begin, + end, + currentLevelKey); + index = iterator - begin; + node->childrenKeys.insert(iterator, currentLevelKey); + node->children.insert(index, Trie()); + } else { + index = iterator - begin; + } + Q_ASSERT(index >= 0 && index < node->children.count()); + node = &node->children[index]; + } + return node; +} + +#endif diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h new file mode 100644 index 000000000..e4c046cb6 --- /dev/null +++ b/indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +// Updated from https://wiki.mozilla.org/TLD_List#External_Links +// To set a custom list use NetworkCookieJar::setSecondLevelDomains() +static const char *const twoLevelDomains[] = { + "ao", + "ar", + "arpa", + "bd", + "bn", + "br", + "co", + "cr", + "cy", + "do", + "eg", + "et", + "fj", + "fk", + "gh", + "gn", + "gu", + "id", + "il", + "jm", + "ke", + "kh", + "ki", + "kw", + "kz", + "lb", + "lc", + "lr", + "ls", + "ml", + "mm", + "mv", + "mw", + "mx", + "my", + "ng", + "ni", + "np", + "nz", + "om", + "pa", + "pe", + "pg", + "pw", + "py", + "qa", + "sa", + "sb", + "sv", + "sy", + "th", + "tn", + "tz", + "uk", + "uy", + "va", + "ve", + "ye", + "yu", + "za", + "zm", + "zw", + 0 +}; diff --git a/indra/llqtwebkit/static.pri b/indra/llqtwebkit/static.pri new file mode 100644 index 000000000..8c282347d --- /dev/null +++ b/indra/llqtwebkit/static.pri @@ -0,0 +1,18 @@ +# Detect if Qt is static or shared +CONFIG(debug, debug|release) { + win32:PRL = $$[QT_INSTALL_LIBS] QtGui.prl +} else { + win32:PRL = $$[QT_INSTALL_LIBS] QtGuid.prl +} + +unix:!mac: PRL = $$[QT_INSTALL_LIBS] libQtGui.prl +mac: PRL = $$[QT_INSTALL_LIBS] QtGui.framework/QtGui.prl +include($$join(PRL, "/")) + +contains(QMAKE_PRL_CONFIG, static) { + DEFINES += STATIC_QT + QTPLUGIN += qgif +} else { + DEFINES += SHARED_QT +} + diff --git a/indra/llqtwebkit/tests/3dgl/3dgl.cpp b/indra/llqtwebkit/tests/3dgl/3dgl.cpp new file mode 100644 index 000000000..c07c5d89c --- /dev/null +++ b/indra/llqtwebkit/tests/3dgl/3dgl.cpp @@ -0,0 +1,269 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ +#define FREEGLUT_STATIC + +#include "zpr.h" +#include "llqtwebkit.h" + +#include +#include +#include +#include + +bool gDebugMode = false; +int gBrowserWindowId=-1; +GLuint gBrowserTexture=-1; +GLuint gCheckerTexture=-1; + +// manually make part of the browser texture transparent - for testing - LLQtWebKit will handle this eventually +void alphaize_browser_texture(unsigned char* texture_pixels) +{ + const int texture_depth=4; + + int texture_width = LLQtWebKit::getInstance()->getBrowserWidth(gBrowserWindowId); + int texture_height = LLQtWebKit::getInstance()->getBrowserHeight(gBrowserWindowId); + + const int num_squares=16; + int sqr1_alpha=0xff; + int sqr2_alpha=0x00; + + for(int y1=0;y1pump(200); + LLQtWebKit::getInstance()->grabBrowserWindow( gBrowserWindowId ); + glutPostRedisplay(); + }; +} + +void display(void) +{ + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + + glBindTexture(GL_TEXTURE_2D, gCheckerTexture); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.8f, -0.8f, -0.8f); + glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.8f, 0.8f, -0.8f); + glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.8f, 0.8f, -0.8f); + glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.8f, -0.8f, -0.8f); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, gBrowserTexture); + if(!gDebugMode) + { + const unsigned char* browser_pixels=LLQtWebKit::getInstance()->getBrowserWindowPixels(gBrowserWindowId); + if(browser_pixels) + { + int texture_width = LLQtWebKit::getInstance()->getBrowserWidth(gBrowserWindowId); + int texture_height = LLQtWebKit::getInstance()->getBrowserHeight(gBrowserWindowId); + int texture_depth = 4; + + unsigned char* texture_pixels = new unsigned char[texture_width*texture_height*texture_depth]; + memcpy(texture_pixels, browser_pixels, texture_width*texture_height*texture_depth); + alphaize_browser_texture(texture_pixels); + + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, + texture_width, texture_height, + GL_RGBA, + GL_UNSIGNED_BYTE, + texture_pixels); + + delete [] texture_pixels; + }; + }; + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.8f, -0.8f, 0.8f); + glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.8f, -0.8f, 0.8f); + glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.8f, 0.8f, 0.8f); + glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.8f, 0.8f, 0.8f); + glEnd(); + + glPopMatrix(); + + glutSwapBuffers(); +} + +GLuint make_rgba_texture(int texture_width, int texture_height) +{ + const int texture_depth=4; + + unsigned char* texture_pixels = new unsigned char[texture_width*texture_height*texture_depth]; + + const int num_squares=rand()%10+10; + int sqr1_r=rand()%0xa0+0x20; + int sqr1_g=rand()%0xa0+0x20; + int sqr1_b=rand()%0xa0+0x20; + int sqr1_alpha=0xff; + + int sqr2_r=rand()%0xa0+0x20; + int sqr2_g=rand()%0xa0+0x20; + int sqr2_b=rand()%0xa0+0x20; + int sqr2_alpha=0x00; + + for(int y1=0;y1init(std::string(), app_dir, profile_dir, GetDesktopWindow()); + + LLQtWebKit::getInstance()->enableJavaScript(true); + LLQtWebKit::getInstance()->enableCookies(true); + LLQtWebKit::getInstance()->enablePlugins(true); + + const std::string start_url("http://news.google.com"); + //const std::string start_url("http://www.youtube.com/watch?v=4Z3r9X8OahA&feature=rbl_entertainment"); + gBrowserWindowId=LLQtWebKit::getInstance()->createBrowserWindow(browser_width, browser_height); + LLQtWebKit::getInstance()->setSize(gBrowserWindowId, browser_width, browser_height); + LLQtWebKit::getInstance()->flipWindow(gBrowserWindowId, true); + LLQtWebKit::getInstance()->navigateTo(gBrowserWindowId, start_url); + } + + gCheckerTexture = make_rgba_texture( browser_width, browser_height); + + glutMainLoop(); + + return 0; +} diff --git a/indra/llqtwebkit/tests/3dgl/3dgl.pro b/indra/llqtwebkit/tests/3dgl/3dgl.pro new file mode 100644 index 000000000..6285128ef --- /dev/null +++ b/indra/llqtwebkit/tests/3dgl/3dgl.pro @@ -0,0 +1,38 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +INCLUDEPATH += ../../ +CONFIG -= app_bundle + +QT += webkit opengl network + +!mac { +unix { + DEFINES += LL_LINUX + LIBS += -lglui -lglut + LIBS += $$PWD/../../libllqtwebkit.a +} +} + +mac { + DEFINES += LL_OSX + LIBS += -framework GLUT -framework OpenGL + LIBS += $$PWD/libllqtwebkit.dylib +} + +win32 { + DEFINES += _WINDOWS + INCLUDEPATH += ../ + INCLUDEPATH += $$PWD/../../stage/packages/include + DESTDIR=../build + release { + LIBS += $$PWD/../../Release/llqtwebkit.lib + LIBS += $$PWD/../build/freeglut_static.lib + LIBS += comdlg32.lib + } +} + +include(../../static.pri) + +SOURCES += 3dgl.cpp zpr.c diff --git a/indra/llqtwebkit/tests/3dgl/zpr.c b/indra/llqtwebkit/tests/3dgl/zpr.c new file mode 100644 index 000000000..65373efc5 --- /dev/null +++ b/indra/llqtwebkit/tests/3dgl/zpr.c @@ -0,0 +1,429 @@ +#include +#include +#include +#include + +#include "zpr.h" + +/* This code was originally C++ :-) */ + +#define bool int +#define true 1 +#define false 0 + +static double _left = 0.0; +static double _right = 0.0; +static double _bottom = 0.0; +static double _top = 0.0; +static double _zNear = -10.0; +static double _zFar = 10.0; + +static int _mouseX = 0; +static int _mouseY = 0; +static bool _mouseLeft = false; +static bool _mouseMiddle = false; +static bool _mouseRight = false; + +static double _dragPosX = 0.0; +static double _dragPosY = 0.0; +static double _dragPosZ = 0.0; + +static double _matrix[16]; +static double _matrixInverse[16]; + +static double vlen(double x,double y,double z); +static void pos(double *px,double *py,double *pz,const int x,const int y,const int *viewport); +static void getMatrix(); +static void invertMatrix(const GLdouble *m, GLdouble *out ); + +static void zprReshape(int w,int h); +static void zprMouse(int button, int state, int x, int y); +static void zprMotion(int x, int y); + +static void zprPick(GLdouble x, GLdouble y,GLdouble delX, GLdouble delY); + +/* Configurable center point for zooming and rotation */ + +GLfloat zprReferencePoint[4] = { 0,0,0,0 }; + +void +zprInit() +{ + getMatrix(); + + glutReshapeFunc(zprReshape); + glutMouseFunc(zprMouse); + glutMotionFunc(zprMotion); +} + +static void +zprReshape(int w,int h) +{ + glViewport(0,0,w,h); + + _top = 1.0; + _bottom = -1.0; + _left = -(double)w/(double)h; + _right = -_left; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(_left,_right,_bottom,_top,_zNear,_zFar); + + glMatrixMode(GL_MODELVIEW); +} + +static void +zprMouse(int button, int state, int x, int y) +{ + GLint viewport[4]; + + /* Do picking */ + if (state==GLUT_DOWN) + zprPick(x,glutGet(GLUT_WINDOW_HEIGHT)-1-y,3,3); + + _mouseX = x; + _mouseY = y; + + if (state==GLUT_UP) + switch (button) + { + case GLUT_LEFT_BUTTON: _mouseLeft = false; break; + case GLUT_MIDDLE_BUTTON: _mouseMiddle = false; break; + case GLUT_RIGHT_BUTTON: _mouseRight = false; break; + } + else + switch (button) + { + case GLUT_LEFT_BUTTON: _mouseLeft = true; break; + case GLUT_MIDDLE_BUTTON: _mouseMiddle = true; break; + case GLUT_RIGHT_BUTTON: _mouseRight = true; break; + } + + glGetIntegerv(GL_VIEWPORT,viewport); + pos(&_dragPosX,&_dragPosY,&_dragPosZ,x,y,viewport); + glutPostRedisplay(); +} + +static void +zprMotion(int x, int y) +{ + bool changed = false; + + const int dx = x - _mouseX; + const int dy = y - _mouseY; + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT,viewport); + + if (dx==0 && dy==0) + return; + + if (_mouseMiddle || (_mouseLeft && _mouseRight)) + { + double s = exp((double)dy*0.01); + + glTranslatef( zprReferencePoint[0], zprReferencePoint[1], zprReferencePoint[2]); + glScalef(s,s,s); + glTranslatef(-zprReferencePoint[0],-zprReferencePoint[1],-zprReferencePoint[2]); + + changed = true; + } + else + if (_mouseLeft) + { + double ax,ay,az; + double bx,by,bz; + double angle; + + ax = dy; + ay = dx; + az = 0.0; + angle = vlen(ax,ay,az)/(double)(viewport[2]+1)*180.0; + + /* Use inverse matrix to determine local axis of rotation */ + + bx = _matrixInverse[0]*ax + _matrixInverse[4]*ay + _matrixInverse[8] *az; + by = _matrixInverse[1]*ax + _matrixInverse[5]*ay + _matrixInverse[9] *az; + bz = _matrixInverse[2]*ax + _matrixInverse[6]*ay + _matrixInverse[10]*az; + + glTranslatef( zprReferencePoint[0], zprReferencePoint[1], zprReferencePoint[2]); + glRotatef(angle,bx,by,bz); + glTranslatef(-zprReferencePoint[0],-zprReferencePoint[1],-zprReferencePoint[2]); + + changed = true; + } + else + if (_mouseRight) + { + double px,py,pz; + + pos(&px,&py,&pz,x,y,viewport); + + glLoadIdentity(); + glTranslatef(px-_dragPosX,py-_dragPosY,pz-_dragPosZ); + glMultMatrixd(_matrix); + + _dragPosX = px; + _dragPosY = py; + _dragPosZ = pz; + + changed = true; + } + + _mouseX = x; + _mouseY = y; + + if (changed) + { + getMatrix(); + glutPostRedisplay(); + } +} + +/***************************************************************** + * Utility functions + *****************************************************************/ + +static double +vlen(double x,double y,double z) +{ + return sqrt(x*x+y*y+z*z); +} + +static void +pos(double *px,double *py,double *pz,const int x,const int y,const int *viewport) +{ + /* + Use the ortho projection and viewport information + to map from mouse co-ordinates back into world + co-ordinates + */ + + *px = (double)(x-viewport[0])/(double)(viewport[2]); + *py = (double)(y-viewport[1])/(double)(viewport[3]); + + *px = _left + (*px)*(_right-_left); + *py = _top + (*py)*(_bottom-_top); + *pz = _zNear; +} + +static void +getMatrix() +{ + glGetDoublev(GL_MODELVIEW_MATRIX,_matrix); + invertMatrix(_matrix,_matrixInverse); +} + +/* + * From Mesa-2.2\src\glu\project.c + * + * Compute the inverse of a 4x4 matrix. Contributed by scotter@lafn.org + */ + +static void +invertMatrix(const GLdouble *m, GLdouble *out ) +{ + +/* NB. OpenGL Matrices are COLUMN major. */ +#define MAT(m,r,c) (m)[(c)*4+(r)] + +/* Here's some shorthand converting standard (row,column) to index. */ +#define m11 MAT(m,0,0) +#define m12 MAT(m,0,1) +#define m13 MAT(m,0,2) +#define m14 MAT(m,0,3) +#define m21 MAT(m,1,0) +#define m22 MAT(m,1,1) +#define m23 MAT(m,1,2) +#define m24 MAT(m,1,3) +#define m31 MAT(m,2,0) +#define m32 MAT(m,2,1) +#define m33 MAT(m,2,2) +#define m34 MAT(m,2,3) +#define m41 MAT(m,3,0) +#define m42 MAT(m,3,1) +#define m43 MAT(m,3,2) +#define m44 MAT(m,3,3) + + GLdouble det; + GLdouble d12, d13, d23, d24, d34, d41; + GLdouble tmp[16]; /* Allow out == in. */ + + /* Inverse = adjoint / det. (See linear algebra texts.)*/ + + /* pre-compute 2x2 dets for last two rows when computing */ + /* cofactors of first two rows. */ + d12 = (m31*m42-m41*m32); + d13 = (m31*m43-m41*m33); + d23 = (m32*m43-m42*m33); + d24 = (m32*m44-m42*m34); + d34 = (m33*m44-m43*m34); + d41 = (m34*m41-m44*m31); + + tmp[0] = (m22 * d34 - m23 * d24 + m24 * d23); + tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13); + tmp[2] = (m21 * d24 + m22 * d41 + m24 * d12); + tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12); + + /* Compute determinant as early as possible using these cofactors. */ + det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3]; + + /* Run singularity test. */ + if (det == 0.0) { + /* printf("invert_matrix: Warning: Singular matrix.\n"); */ +/* memcpy(out,_identity,16*sizeof(double)); */ + } + else { + GLdouble invDet = 1.0 / det; + /* Compute rest of inverse. */ + tmp[0] *= invDet; + tmp[1] *= invDet; + tmp[2] *= invDet; + tmp[3] *= invDet; + + tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet; + tmp[5] = (m11 * d34 + m13 * d41 + m14 * d13) * invDet; + tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet; + tmp[7] = (m11 * d23 - m12 * d13 + m13 * d12) * invDet; + + /* Pre-compute 2x2 dets for first two rows when computing */ + /* cofactors of last two rows. */ + d12 = m11*m22-m21*m12; + d13 = m11*m23-m21*m13; + d23 = m12*m23-m22*m13; + d24 = m12*m24-m22*m14; + d34 = m13*m24-m23*m14; + d41 = m14*m21-m24*m11; + + tmp[8] = (m42 * d34 - m43 * d24 + m44 * d23) * invDet; + tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet; + tmp[10] = (m41 * d24 + m42 * d41 + m44 * d12) * invDet; + tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet; + tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet; + tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13) * invDet; + tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet; + tmp[15] = (m31 * d23 - m32 * d13 + m33 * d12) * invDet; + + memcpy(out, tmp, 16*sizeof(GLdouble)); + } + +#undef m11 +#undef m12 +#undef m13 +#undef m14 +#undef m21 +#undef m22 +#undef m23 +#undef m24 +#undef m31 +#undef m32 +#undef m33 +#undef m34 +#undef m41 +#undef m42 +#undef m43 +#undef m44 +#undef MAT +} + +/***************************************** Picking ****************************************************/ + +static void (*selection)(void) = NULL; +static void (*pick)(GLint name) = NULL; + +void zprSelectionFunc(void (*f)(void)) +{ + selection = f; +} + +void zprPickFunc(void (*f)(GLint name)) +{ + pick = f; +} + +/* Draw in selection mode */ + +static void +zprPick(GLdouble x, GLdouble y,GLdouble delX, GLdouble delY) +{ + GLuint buffer[1024]; + const int bufferSize = sizeof(buffer)/sizeof(GLuint); + + GLint viewport[4]; + GLdouble projection[16]; + + GLint hits; + GLint i,j,k; + + GLint min = -1; + GLuint minZ = -1; + + glSelectBuffer(bufferSize,buffer); /* Selection buffer for hit records */ + glRenderMode(GL_SELECT); /* OpenGL selection mode */ + glInitNames(); /* Clear OpenGL name stack */ + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); /* Push current projection matrix */ + glGetIntegerv(GL_VIEWPORT,viewport); /* Get the current viewport size */ + glGetDoublev(GL_PROJECTION_MATRIX,projection); /* Get the projection matrix */ + glLoadIdentity(); /* Reset the projection matrix */ + gluPickMatrix(x,y,delX,delY,viewport); /* Set the picking matrix */ + glMultMatrixd(projection); /* Apply projection matrix */ + + glMatrixMode(GL_MODELVIEW); + + if (selection) + selection(); /* Draw the scene in selection mode */ + + hits = glRenderMode(GL_RENDER); /* Return to normal rendering mode */ + + /* Diagnostic output to stdout */ + + #ifndef NDEBUG + if (hits!=0) + { + printf("hits = %d\n",hits); + + for (i=0,j=0; i rotate + * Middle button -> zoom + * Right button -> pan + * + * Picking is also provided via two configurable callbacks: + * + * void zprSelectionFunc(void (*f)(void)) + * + * The draw function to be called in OpenGL selection + * mode in response to a mouse-down button event. + * + * void zprPickFunc(void (*f)(GLint name)) + * + * The callback function which will receive the + * top-most item of the name stack of the closest selection + * hit. If there is no selection hit, -1 + * + * Limitations + * ----------- + * + * Works best with zprReferencePoint appropriately configured. + * Works best with ortho projection. + * You may need to use glEnable(GL_NORMALIZATION) for correct lighting. + * Near and far clip planes are hard-coded. + * Zooming and rotation is centered on the origin. + * Only one window can use the callbacks at one time. + * + */ + +#ifdef WIN32 +#include +#endif + +#define FREEGLUT_STATIC + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * + */ + +/* Mouse Manipulation API */ + +void zprInit(); + +extern GLfloat zprReferencePoint[4]; + +/* Picking API (Optional) */ + +extern void zprSelectionFunc(void (*f)(void)); /* Selection-mode draw function */ +extern void zprPickFunc(void (*f)(GLint name)); /* Pick event handling function */ + +/* + * + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/indra/llqtwebkit/tests/qttestapp/main.cpp b/indra/llqtwebkit/tests/qttestapp/main.cpp new file mode 100644 index 000000000..3ab3a9c17 --- /dev/null +++ b/indra/llqtwebkit/tests/qttestapp/main.cpp @@ -0,0 +1,341 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#include +#include + +class WebPage : public QWidget, LLEmbeddedBrowserWindowObserver +{ + Q_OBJECT + +signals: + void locationChanged(const QString &); + void canGoBack(bool); + void canGoForward(bool); + +public: + WebPage(QWidget *parent = 0); + ~WebPage(); + + void onCursorChanged(const EventType& event); + void onPageChanged(const EventType& event); + void onNavigateBegin(const EventType& event); + void onNavigateComplete(const EventType& event); + void onUpdateProgress(const EventType& event); + void onStatusTextChange(const EventType& event); + void onLocationChange(const EventType& event); + void onClickLinkHref(const EventType& event); + void onClickLinkNoFollow(const EventType& event); + +public slots: + void goBack(); + void goForward(); + void reload(); + void loadUrl(const QString &); + +protected: + void resizeEvent(QResizeEvent *event); + void paintEvent(QPaintEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); +private: + void updateSLvariables(); + int mBrowserWindowId; +}; + +WebPage::WebPage(QWidget *parent) + : QWidget(parent) +{ + setMouseTracking(true); + std::string applicationDir = std::string(); + std::string componentDir = applicationDir; + std::string profileDir = applicationDir + "\\" + "testGL_profile"; + LLQtWebKit::getInstance()->init(applicationDir, componentDir, profileDir, 0); + + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(width(), height()); + + // observer events that LLQtWebKit emits + LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + + // append details to agent string + LLQtWebKit::getInstance()->setBrowserAgentId("testqtapp"); + + // don't flip bitmap + LLQtWebKit::getInstance()->flipWindow(mBrowserWindowId, false); + + // test Second Life viewer specific functions + LLQtWebKit::getInstance()->setSLObjectEnabled( true ); // true means feature is turned on + LLQtWebKit::getInstance()->setAgentLanguage( "tst-en" ); // viewer language selected by agent + LLQtWebKit::getInstance()->setAgentRegion( "QtTestAppRegion" ); // name of region where agent is located + LLQtWebKit::getInstance()->setAgentLocation( 9.8, 7.6, 5.4 ); // agent's x,y,z location within a region + LLQtWebKit::getInstance()->setAgentGlobalLocation( 119.8, 227.6, 335.4 ); // agent's x,y,z location within the grid + LLQtWebKit::getInstance()->setAgentMaturity( "Very immature" ); // selected maturity level of agent + LLQtWebKit::getInstance()->setAgentOrientation( (rand()%36000)/100.0f ); // direction avatar is facing + LLQtWebKit::getInstance()->emitLocation(); + LLQtWebKit::getInstance()->emitLanguage(); + LLQtWebKit::getInstance()->emitMaturity(); + + // go to the "home page" + LLQtWebKit::getInstance()->navigateTo(mBrowserWindowId, "http://callum-linden.s3.amazonaws.com/browsertest.html"); +} + +WebPage::~WebPage() +{ + // unhook observer + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + + // clean up + LLQtWebKit::getInstance()->reset(); +} + +void WebPage::updateSLvariables() +{ + // randomly update SL values to test + LLQtWebKit::getInstance()->setAgentOrientation( (rand()%36000)/100.0f ); + LLQtWebKit::getInstance()->setAgentLocation( (rand()%25600)/100.0f, (rand()%25600)/100.0f, (rand()%25600)/100.0f ); + LLQtWebKit::getInstance()->setAgentGlobalLocation( (rand()%25600)/100.0f, (rand()%25600)/100.0f, (rand()%25600)/100.0f ); + + if ( rand() % 2 ) + LLQtWebKit::getInstance()->setAgentLanguage( "One language" ); + else + LLQtWebKit::getInstance()->setAgentLanguage( "Another language" ); + + if ( rand() % 2 ) + LLQtWebKit::getInstance()->setAgentRegion( "Region Wibble" ); + else + LLQtWebKit::getInstance()->setAgentRegion( "Region Flasm" ); + + if ( rand() % 2 ) + LLQtWebKit::getInstance()->setAgentMaturity( "Adults only" ); + else + LLQtWebKit::getInstance()->setAgentMaturity( "Children only" ); + + LLQtWebKit::getInstance()->emitLocation(); + LLQtWebKit::getInstance()->emitLanguage(); + LLQtWebKit::getInstance()->emitMaturity(); +} + +void WebPage::onCursorChanged(const EventType& event) +{ + //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); + switch (event.getIntValue()) { + case LLQtWebKit::C_ARROW: setCursor(QCursor(Qt::ArrowCursor)); break; + case LLQtWebKit::C_IBEAM: setCursor(QCursor(Qt::IBeamCursor)); break; + case LLQtWebKit::C_SPLITV: setCursor(QCursor(Qt::SplitHCursor)); break; + case LLQtWebKit::C_SPLITH: setCursor(QCursor(Qt::SplitVCursor)); break; + case LLQtWebKit::C_POINTINGHAND: setCursor(QCursor(Qt::PointingHandCursor)); break; + default: break; + } +} + +void WebPage::onPageChanged(const EventType& event) +{ + Q_UNUSED(event); + LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); + //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); + update(); +} + +void WebPage::onNavigateBegin(const EventType& event) +{ + Q_UNUSED(event); + //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); +} + +void WebPage::onNavigateComplete(const EventType& event) +{ + Q_UNUSED(event); + //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); +} + +void WebPage::onUpdateProgress(const EventType& event) +{ + Q_UNUSED(event); +} + +void WebPage::onStatusTextChange(const EventType& event) +{ + Q_UNUSED(event); +} + +void WebPage::onLocationChange(const EventType& event) +{ + //qDebug() << __FUNCTION__; + emit locationChanged(QString::fromStdString(event.getEventUri())); + //void canGoBack(bool); + //void canGoForward(bool); +} + +void WebPage::onClickLinkHref(const EventType& event) +{ + Q_UNUSED(event); +} + +void WebPage::onClickLinkNoFollow(const EventType& event) +{ + Q_UNUSED(event); +} + +void WebPage::resizeEvent(QResizeEvent *event) +{ + LLQtWebKit::getInstance()->setSize(mBrowserWindowId, event->size().width(), event->size().height()); + QWidget::resizeEvent(event); +} + +void WebPage::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + int width = LLQtWebKit::getInstance()->getBrowserWidth(mBrowserWindowId); + int height = LLQtWebKit::getInstance()->getBrowserHeight(mBrowserWindowId); + const unsigned char* pixels = LLQtWebKit::getInstance()->getBrowserWindowPixels(mBrowserWindowId); + QImage image(pixels, width, height, QImage::Format_RGB32); + image = image.rgbSwapped(); + QPainter painter(this); + painter.drawImage(QPoint(0, 0), image); +} + +void WebPage::mouseDoubleClickEvent(QMouseEvent *event) +{ + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_DOUBLE_CLICK, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + event->x(), event->y(), + LLQtWebKit::KM_MODIFIER_NONE ); +} + +void WebPage::mouseMoveEvent(QMouseEvent *event) +{ + updateSLvariables(); + + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_MOVE, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + event->x(), event->y(), + LLQtWebKit::KM_MODIFIER_NONE ); +} + +void WebPage::mousePressEvent(QMouseEvent *event) +{ + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_DOWN, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + event->x(), event->y(), + LLQtWebKit::KM_MODIFIER_NONE ); +} + +void WebPage::mouseReleaseEvent(QMouseEvent *event) +{ + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_UP, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + event->x(), event->y(), + LLQtWebKit::KM_MODIFIER_NONE ); + + LLQtWebKit::getInstance()->focusBrowser(mBrowserWindowId, true); +} + +void WebPage::keyPressEvent(QKeyEvent *event) +{ + Q_UNUSED(event); +} + +void WebPage::keyReleaseEvent(QKeyEvent *event) +{ + Q_UNUSED(event); + //LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, event->text().at(0).unicode(),LLQtWebKit::KM_MODIFIER_NONE); +} + +void WebPage::goBack() +{ + LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK); +} + +void WebPage::goForward() +{ + LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD); +} + +void WebPage::reload() +{ + LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD); +} + +void WebPage::loadUrl(const QString &url) +{ + LLQtWebKit::getInstance()->navigateTo(mBrowserWindowId, url.toStdString()); +} + +#include "ui_window.h" + +class Window : public QDialog, public Ui_Dialog +{ + Q_OBJECT +public: + Window(QWidget *parent = 0); + +public slots: + void loadUrl(); +}; + +Window::Window(QWidget *parent) + : QDialog(parent) +{ + setupUi(this); + connect(webpage, SIGNAL(locationChanged(const QString &)), + location, SLOT(setText(const QString &))); + connect(webpage, SIGNAL(canGoBack(bool)), + backButton, SLOT(setEnabled(bool))); + connect(webpage, SIGNAL(canGoForward(bool)), + forwardButton, SLOT(setEnabled(bool))); + connect(backButton, SIGNAL(clicked()), + webpage, SLOT(goBack())); + connect(forwardButton, SIGNAL(clicked()), + webpage, SLOT(goForward())); + connect(reloadButton, SIGNAL(clicked()), + webpage, SLOT(reload())); + connect(location, SIGNAL(returnPressed()), + this, SLOT(loadUrl())); +} + +void Window::loadUrl() +{ + webpage->loadUrl(location->text()); +} + + +int main(int argc, char **argv) +{ + QApplication application(argc, argv); + Window window; + window.show(); + return application.exec(); +} + +#include "main.moc" diff --git a/indra/llqtwebkit/tests/qttestapp/qttestapp.pro b/indra/llqtwebkit/tests/qttestapp/qttestapp.pro new file mode 100644 index 000000000..5a0ca33cf --- /dev/null +++ b/indra/llqtwebkit/tests/qttestapp/qttestapp.pro @@ -0,0 +1,38 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +INCLUDEPATH += ../../ +CONFIG -= app_bundle + +include(../../static.pri) + +QT += webkit opengl network + +unix { + LIBS += $$PWD/../../libllqtwebkit.a +} + +!mac { +unix { + DEFINES += LL_LINUX +} +} + +mac { + DEFINES += LL_OSX +} + + +win32{ + DEFINES += _WINDOWS + INCLUDEPATH += ../ + DESTDIR=../build + release { + LIBS += $$PWD/../../Release/llqtwebkit.lib + } +} + +# Input +SOURCES += main.cpp +FORMS += window.ui diff --git a/indra/llqtwebkit/tests/qttestapp/webpage.h b/indra/llqtwebkit/tests/qttestapp/webpage.h new file mode 100644 index 000000000..e69de29bb diff --git a/indra/llqtwebkit/tests/qttestapp/window.ui b/indra/llqtwebkit/tests/qttestapp/window.ui new file mode 100644 index 000000000..6125821cc --- /dev/null +++ b/indra/llqtwebkit/tests/qttestapp/window.ui @@ -0,0 +1,79 @@ + + + Dialog + + + + 0 + 0 + 766 + 613 + + + + Dialog + + + + 0 + + + + + 6 + + + 6 + + + 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + + WebPage + QWidget +
webpage.h
+ 1 +
+
+ + +
diff --git a/indra/llqtwebkit/tests/ssltest/ssltest.cpp b/indra/llqtwebkit/tests/ssltest/ssltest.cpp new file mode 100644 index 000000000..fcbf80314 --- /dev/null +++ b/indra/llqtwebkit/tests/ssltest/ssltest.cpp @@ -0,0 +1,229 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef _WINDOWS +extern "C" { +#include +} +#endif + +#ifdef _WINDOWS +#include +#include +#endif + +#include +#include +#include + +#ifdef LL_OSX +// I'm not sure why STATIC_QT is getting defined, but the Q_IMPORT_PLUGIN thing doesn't seem to be necessary on the mac. +#undef STATIC_QT +#endif + +#ifdef STATIC_QT +#include +Q_IMPORT_PLUGIN(qgif) +#endif + +#include "llqtwebkit.h" + +class sslTest : + public LLEmbeddedBrowserWindowObserver +{ + public: + sslTest( std::string url, bool ignore_ca_file, bool ignore_ssl_errors ) : + mBrowserWindowWidth( 512 ), + mBrowserWindowHeight( 512 ), + mBrowserWindowHandle( 0 ), + mNavigateInProgress( true ) + { +#ifdef _WINDOWS + std::string cwd = std::string( _getcwd( NULL, 1024) ); + std::string profile_dir = cwd + "\\" + "ssltest_profile"; + void* native_window_handle = (void*)GetDesktopWindow(); + std::string ca_file_loc = cwd + "\\" + "CA.pem"; +#else + std::string cwd = std::string( getcwd( NULL, 1024) ); + std::string profile_dir = cwd + "/" + "ssltest_profile"; + void* native_window_handle = 0; + std::string ca_file_loc = cwd + "/" + "CA.pem"; +#endif + std::cout << "ssltest> === begin ===" << std::endl; + std::cout << "ssltest> current working dir is " << cwd << std::endl; + std::cout << "ssltest> profiles dir location is " << profile_dir << std::endl; + + LLQtWebKit::getInstance()->init( cwd, cwd, profile_dir, native_window_handle ); + + LLQtWebKit::getInstance()->enableJavaScript( true ); + LLQtWebKit::getInstance()->enablePlugins( true ); + + mBrowserWindowHandle = LLQtWebKit::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); + LLQtWebKit::getInstance()->setSize( mBrowserWindowHandle, mBrowserWindowWidth, mBrowserWindowHeight ); + + LLQtWebKit::getInstance()->addObserver( mBrowserWindowHandle, this ); + + if ( ! ignore_ca_file ) + { + std::cout << "ssltest> Expected certificate authority file location is " << ca_file_loc << std::endl; + LLQtWebKit::getInstance()->setCAFile( ca_file_loc.c_str() ); + } + else + { + std::cout << "ssltest> Not loading certificate authority file" << std::endl; + }; + + if ( ignore_ssl_errors ) + { + LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( true ); + std::cout << "ssltest> Ignoring SSL errors " << std::endl; + } + else + { + std::cout << "ssltest> Not ignoring SSL errors " << std::endl; + }; + + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowHandle, url ); + + std::cout << "ssltest> navigating to " << url << std::endl; + }; + + bool idle( void ) + { + LLQtWebKit::getInstance()->pump( 100 ); + +#if _WINDOWS + MSG msg; + while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + GetMessage( &msg, NULL, 0, 0 ); + TranslateMessage( &msg ); + DispatchMessage( &msg ); + }; +#endif + return mNavigateInProgress; + }; + + ~sslTest() + { + LLQtWebKit::getInstance()->remObserver( mBrowserWindowHandle, this ); + LLQtWebKit::getInstance()->reset(); + std::cout << "ssltest> === end ===" << std::endl; + }; + + void onNavigateBegin( const EventType& eventIn ) + { + mNavigateInProgress = true; + std::cout << "ssltest> Event: begin navigation to " << eventIn.getEventUri() << std::endl; + }; + + void onNavigateComplete( const EventType& eventIn ) + { + std::cout << "ssltest> Event: end navigation to " << eventIn.getEventUri() << std::endl; + mNavigateInProgress = false; + }; + + void onUpdateProgress( const EventType& eventIn ) + { + std::cout << "ssltest> Event: progress value updated to " << eventIn.getIntValue() << std::endl; + }; + + void onStatusTextChange( const EventType& eventIn ) + { + std::cout << "ssltest> Event: status updated to " << eventIn.getStringValue() << std::endl; + }; + + void onTitleChange( const EventType& eventIn ) + { + std::cout << "ssltest> Event: title changed to " << eventIn.getStringValue() << std::endl; + }; + + void onLocationChange( const EventType& eventIn ) + { + std::cout << "ssltest> Event: location changed to " << eventIn.getStringValue() << std::endl; + }; + + bool onCertError(const std::string &in_url, const std::string &in_msg) + { + std::cout << "ssltest> Cert error triggered\n" << in_url << "\n" << in_msg << std::endl; + return true; + } + + private: + int mBrowserWindowWidth; + int mBrowserWindowHeight; + int mBrowserWindowHandle; + bool mNavigateInProgress; +}; + +int main( int argc, char* argv[] ) +{ + bool ingore_ssl_errors = false; + bool ignore_ca_file = false; + + for( int i = 1; i < argc; ++i ) + { + if ( std::string( argv[ i ] ) == "--help" ) + { + std::cout << std::endl << "ssltest [--ignoresslerrors] [--ignorecafile]" << std::endl; + std::cout << "Looks for cert file CA.pem in the current working directory"; + + exit( 0 ); + }; + + if ( std::string( argv[ i ] ) == "--ignoresslerrors" ) + ingore_ssl_errors = true; + + if ( std::string( argv[ i ] ) == "--ignorecafile" ) + ignore_ca_file = true; + }; + + std::string url ( "https://my.secondlife.com/callum.linden" ); + for( int i = 1; i < argc; ++i ) + { + if ( std::string( argv[ i ] ).substr( 0, 2 ) != "--" ) + { + url = std::string( argv[ i ] ); + break; + }; + }; + + std::cout << std::endl << " --------- sslTest application starting --------- " << std::endl; + std::cout << "ssltest> URL specified is " << url << std::endl; + + sslTest* app = new sslTest( url, ignore_ca_file, ingore_ssl_errors ); + + bool result = app->idle(); + while( result ) + { + result = app->idle(); + }; + + delete app; + + std::cout << " --------- sslTest application ending --------- " << std::endl; + + return 0; +} diff --git a/indra/llqtwebkit/tests/ssltest/ssltest.pro b/indra/llqtwebkit/tests/ssltest/ssltest.pro new file mode 100644 index 000000000..981e35211 --- /dev/null +++ b/indra/llqtwebkit/tests/ssltest/ssltest.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +INCLUDEPATH += ../../ +CONFIG -= app_bundle +CONFIG += console + +QT += webkit network + +mac { + DEFINES += LL_OSX + LIBS += $$PWD/libllqtwebkit.dylib +} + +win32 { + DEFINES += _WINDOWS + INCLUDEPATH += ../ + DESTDIR=../build + LIBS += user32.lib + release { + LIBS += $$PWD/../../Release/llqtwebkit.lib + } +} + +include(../../static.pri) + +SOURCES += ssltest.cpp diff --git a/indra/llqtwebkit/tests/testgl/testgl.cpp b/indra/llqtwebkit/tests/testgl/testgl.cpp new file mode 100644 index 000000000..6dfb11a72 --- /dev/null +++ b/indra/llqtwebkit/tests/testgl/testgl.cpp @@ -0,0 +1,1002 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef _WINDOWS +extern "C" { +#include +} +#endif + +#ifdef _WINDOWS +#include +#include // file choser dialog +#include // for local file access +#endif + +#include +#include +#include +#include +#include + +#ifdef LL_OSX +// I'm not sure why STATIC_QT is getting defined, but the Q_IMPORT_PLUGIN thing doesn't seem to be necessary on the mac. +#undef STATIC_QT +#endif + +#ifdef STATIC_QT +#include +Q_IMPORT_PLUGIN(qgif) +#endif + +#ifdef LL_OSX +#include +#include +#else +#define FREEGLUT_STATIC +#include "GL/glut.h" +#endif +#include "llqtwebkit.h" + +#ifdef _WINDOWS + #define PATH_SEPARATOR "\\" +#else + #define PATH_SEPARATOR "/" +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +std::string chooseFileName() +{ +#ifdef _WINDOWS + OPENFILENAMEA ofn ; + static char szFile[_MAX_PATH] ; + + ZeroMemory( &ofn , sizeof( ofn) ); + ofn.lStructSize = sizeof ( ofn ); + ofn.hwndOwner = NULL ; + ofn.lpstrFile = szFile ; + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof( szFile ); + ofn.lpstrFilter = "All\0*.*\0Images\0*.jpg;*.png\0"; + ofn.nFilterIndex =1; + ofn.lpstrFileTitle = NULL ; + ofn.nMaxFileTitle = 0 ; + ofn.lpstrInitialDir=NULL ; + ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ; + + GetOpenFileNameA( &ofn ); + + return ofn.lpstrFile; +#else + return ""; +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of the test app - implemented as a class and derrives from +// the observer so we can catch events emitted by LLQtWebKit +// +class testGL : + public LLEmbeddedBrowserWindowObserver +{ + public: + testGL() : + mAppWindowWidth( 800 ), // dimensions of the app window - can be anything + mAppWindowHeight( 900 ), + mBrowserWindowWidth( mAppWindowWidth ), // dimensions of the embedded browser - can be anything + mBrowserWindowHeight( mAppWindowHeight ), // but looks best when it's the same as the app window + mAppTextureWidth( -1 ), // dimensions of the texture that the browser is rendered into + mAppTextureHeight( -1 ), // calculated at initialization + mAppTexture( 0 ), + mBrowserWindowId( 0 ), + mAppWindowName( "testGL" ), + mCwd(), + mHomeUrl(), + mNeedsUpdate( true ) // flag to indicate if browser texture needs an update + { +#ifdef _WINDOWS // to remove warning on Windows + mCwd = _getcwd(NULL, 1024); +#else + mCwd = getcwd(NULL, 1024); +#endif + mHomeUrl = "http://callum-linden.s3.amazonaws.com/browsertest.html"; + std::cout << "LLQtWebKit version: " << LLQtWebKit::getInstance()->getVersion() << std::endl; + + std::cout << "Current working directory is " << mCwd << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void init( const std::string argv0, const std::string argv1 ) + { + // OpenGL initialization + glClearColor( 0.0f, 0.0f, 0.0f, 0.5f); + glEnable( GL_COLOR_MATERIAL ); + glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); + glEnable( GL_TEXTURE_2D ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glEnable( GL_CULL_FACE ); + + // calculate texture size required (next power of two above browser window size + for ( mAppTextureWidth = 1; mAppTextureWidth < mBrowserWindowWidth; mAppTextureWidth <<= 1 ) + { + }; + + for ( mAppTextureHeight = 1; mAppTextureHeight < mBrowserWindowHeight; mAppTextureHeight <<= 1 ) + { + }; + + // create the texture used to display the browser data + glGenTextures( 1, &mAppTexture ); + glBindTexture( GL_TEXTURE_2D, mAppTexture ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexImage2D( GL_TEXTURE_2D, 0, + GL_RGB, + mAppTextureWidth, mAppTextureHeight, + 0, GL_RGB, GL_UNSIGNED_BYTE, 0 ); + + // create a single browser window and set things up. + mProfileDir = mCwd + PATH_SEPARATOR + "testGL_profile"; + std::cout << "Profiles dir location is " << mProfileDir << std::endl; + + mCookiePath = mProfileDir + PATH_SEPARATOR + "cookies.txt"; + std::cout << "Cookies.txt file location is " << mCookiePath << std::endl; + + LLQtWebKit::getInstance()->init( mApplicationDir, mApplicationDir, mProfileDir, getNativeWindowHandle() ); + + LLQtWebKit::getInstance()->enableQtMessageHandler( false ); + + // set host language test (in reality, string will be language code passed into client) + // IMPORTANT: must be called before createBrowserWindow(...) + LLQtWebKit::getInstance()->setHostLanguage( "EN-AB-CD-EF" ); + + // set up features + LLQtWebKit::getInstance()->enableJavaScript( true ); + LLQtWebKit::getInstance()->enableCookies( true ); + LLQtWebKit::getInstance()->enablePlugins( true ); + + // make a browser window + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); + + // tell LLQtWebKit about the size of the browser window + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mBrowserWindowWidth, mBrowserWindowHeight ); + + // observer events that LLQtWebKit emits + LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + + // append details to agent string + LLQtWebKit::getInstance()->setBrowserAgentId( mAppWindowName ); + + // don't flip bitmap + LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, false ); + + // only "trust" pages whose host match this regex + LLQtWebKit::getInstance()->setWhiteListRegex( mBrowserWindowId, "^([^.]+\\.)*amazonaws\\.com$" ); + + LLQtWebKit::getInstance()->enableLoadingOverlay( mBrowserWindowId, true ); + + // Attempt to read cookies from the cookie file and send them to llqtwebkit. + { + std::ifstream cookie_file(mCookiePath.c_str(), std::ios_base::in); + std::string cookies; + + while(cookie_file.good() && !cookie_file.eof()) + { + std::string tmp; + std::getline(cookie_file, tmp); + cookies += tmp; + cookies += "\n"; + } + + if(!cookies.empty()) + { + LLQtWebKit::getInstance()->setCookies(cookies); + } + } + + #if 0 + const std::vector before=LLQtWebKit::getInstance()->getInstalledCertsList(); + std::cout << "Certs before CA.pem load: " << before.size() << " items" << std::endl; + for(int i=0;isetCAFile( ca_pem_file_loc.c_str() ); + std::cout << "Expected CA.pem file location is " << ca_pem_file_loc << std::endl; + + #if 0 + const std::vector after=LLQtWebKit::getInstance()->getInstalledCertsList(); + std::cout << "Certs after CA.pem load: " << after.size() << " items" << std::endl; + for(int i=0;isetSLObjectEnabled( true ); // true means the feature is turned on + LLQtWebKit::getInstance()->setAgentLanguage( "tst-en" ); // viewer language selected by agent + LLQtWebKit::getInstance()->setAgentRegion( "TestGL region" ); // name of region where agent is located + LLQtWebKit::getInstance()->setAgentLocation( 9.8, 7.6, 5.4 ); // agent's x,y,z location within a region + LLQtWebKit::getInstance()->setAgentGlobalLocation( 1234.5, 6789.0, 3456.7 ); // agent's x,y,z location within a region + LLQtWebKit::getInstance()->setAgentOrientation( 175.69 ); // direction (0..359) agent is facing + LLQtWebKit::getInstance()->setAgentMaturity( "Very immature" ); // selected maturity level of agent + + // go to the "home page" or URL passed in via command line + if ( ! argv1.empty() ) + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, argv1 ); + else + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mHomeUrl ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void reset( void ) + { + // Get cookies from this instance + std::string cookies = LLQtWebKit::getInstance()->getAllCookies(); + + // Dump cookies to stdout +// std::cout << "Cookies:" << std::endl; +// std::cout << cookies; + + // and save them to cookies.txt in the profile directory + { + std::ofstream cookie_file(mCookiePath.c_str(), std::ios_base::out|std::ios_base::trunc); + + if(cookie_file.good()) + { + cookie_file << cookies; + } + + cookie_file.close(); + } + + // unhook observer + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + + // clean up + LLQtWebKit::getInstance()->reset(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void reshape( int widthIn, int heightIn ) + { + if ( heightIn == 0 ) + heightIn = 1; + + LLQtWebKit::getInstance()->setSize(mBrowserWindowId, widthIn, heightIn ); + mNeedsUpdate = true; + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + glViewport( 0, 0, widthIn, heightIn ); + glOrtho( 0.0f, widthIn, heightIn, 0.0f, -1.0f, 1.0f ); + + // we use these elsewhere so save + mAppWindowWidth = widthIn; + mAppWindowHeight = heightIn; + mBrowserWindowWidth = widthIn; + mBrowserWindowHeight = heightIn; + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + mNeedsUpdate = true; + idle(); + + glutPostRedisplay(); + }; + + void updateSLvariables() + { + if ( rand() % 2 ) + LLQtWebKit::getInstance()->setAgentRegion( "Region Wibble" ); + else + LLQtWebKit::getInstance()->setAgentRegion( "Region Flasm" ); + LLQtWebKit::getInstance()->setAgentLocation( (rand()%25600)/100.0f, (rand()%25600)/100.0f, (rand()%25600)/100.0f ); + LLQtWebKit::getInstance()->setAgentGlobalLocation( (rand()%25600)/10.0f, (rand()%25600)/10.0f, (rand()%25600)/10.0f ); + LLQtWebKit::getInstance()->setAgentOrientation( (rand()%3600)/10.0f ); + LLQtWebKit::getInstance()->emitLocation(); + + if ( rand() % 2 ) + LLQtWebKit::getInstance()->setAgentLanguage( "One language" ); + else + LLQtWebKit::getInstance()->setAgentLanguage( "Another language" ); + LLQtWebKit::getInstance()->emitLanguage(); + + if ( rand() % 2 ) + LLQtWebKit::getInstance()->setAgentMaturity( "Adults only" ); + else + LLQtWebKit::getInstance()->setAgentMaturity( "Children only" ); + LLQtWebKit::getInstance()->emitMaturity(); + } + + //////////////////////////////////////////////////////////////////////////////// + // + void idle() + { + static time_t starttime = time( NULL ); + if ( time( NULL ) - starttime ) + { + updateSLvariables(); + time( &starttime ); + }; + + LLQtWebKit::getInstance()->pump(100); + + // onPageChanged event sets this + if ( mNeedsUpdate ) + // grab a page but don't reset 'needs update' flag until we've written it to the texture in display() + LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); + + // lots of updates for smooth motion + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void display() + { + // clear screen + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glLoadIdentity(); + + // use the browser texture + glBindTexture( GL_TEXTURE_2D, mAppTexture ); + + // valid window ? + if ( mBrowserWindowId ) + { + // needs to be updated? + if ( mNeedsUpdate ) + { + // grab the page + const unsigned char* pixels = LLQtWebKit::getInstance()->getBrowserWindowPixels( mBrowserWindowId ); + if ( pixels ) + { + // write them into the texture + glTexSubImage2D( GL_TEXTURE_2D, 0, + 0, 0, + // because sometimes the rowspan != width * bytes per pixel (mBrowserWindowWidth) + LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) / LLQtWebKit::getInstance()->getBrowserDepth( mBrowserWindowId ), + mBrowserWindowHeight, +#ifdef _WINDOWS + LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId ) == 3 ? GL_RGBA : GL_RGBA, +#elif defined(__APPLE__) + GL_RGBA, +#elif defined(LL_LINUX) + GL_RGBA, +#endif + GL_UNSIGNED_BYTE, + pixels ); + }; + + // flag as already updated + mNeedsUpdate = false; + }; + }; + + // scale the texture so that it fits the screen + GLfloat textureScaleX = ( GLfloat )mBrowserWindowWidth / ( GLfloat )mAppTextureWidth; + GLfloat textureScaleY = ( GLfloat )mBrowserWindowHeight / ( GLfloat )mAppTextureHeight; + + // draw the single quad full screen (orthographic) + glMatrixMode( GL_TEXTURE ); + glPushMatrix(); + glScalef( textureScaleX, textureScaleY, 1.0f ); + + glEnable( GL_TEXTURE_2D ); + glColor3f( 1.0f, 1.0f, 1.0f ); + glBegin( GL_QUADS ); + glTexCoord2f( 1.0f, 0.0f ); + glVertex2d( mAppWindowWidth, 0 ); + + glTexCoord2f( 0.0f, 0.0f ); + glVertex2d( 0, 0 ); + + glTexCoord2f( 0.0f, 1.0f ); + glVertex2d( 0, mAppWindowHeight ); + + glTexCoord2f( 1.0f, 1.0f ); + glVertex2d( mAppWindowWidth, mAppWindowHeight ); + glEnd(); + + glMatrixMode( GL_TEXTURE ); + glPopMatrix(); + + glutSwapBuffers(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // convert a GLUT keyboard modifier to an LLQtWebKit one + // (only valid in mouse and keyboard callbacks + LLQtWebKit::EKeyboardModifier getLLQtWebKitKeyboardModifierCode() + { + int result = LLQtWebKit::KM_MODIFIER_NONE; + + int modifiers = glutGetModifiers(); + + if ( GLUT_ACTIVE_SHIFT & modifiers ) + { + result |= LLQtWebKit::KM_MODIFIER_SHIFT; + } + + if ( GLUT_ACTIVE_CTRL & modifiers ) + result |= LLQtWebKit::KM_MODIFIER_CONTROL; + + if ( GLUT_ACTIVE_ALT & modifiers ) + result |= LLQtWebKit::KM_MODIFIER_ALT; + + return (LLQtWebKit::EKeyboardModifier)result; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseButton( int button, int state, int xIn, int yIn ) + { + // texture is scaled to fit the screen so we scale mouse coords in the same way + xIn = ( xIn * mBrowserWindowWidth ) / mAppWindowWidth; + yIn = ( yIn * mBrowserWindowHeight ) / mAppWindowHeight; + + if ( button == GLUT_LEFT_BUTTON ) + { + if ( state == GLUT_DOWN ) + { + // send event to LLQtWebKit + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_DOWN, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + xIn, yIn, + getLLQtWebKitKeyboardModifierCode() ); + } + else + if ( state == GLUT_UP ) + { + // send event to LLQtWebKit + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_UP, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + xIn, yIn, + getLLQtWebKitKeyboardModifierCode() ); + + + // this seems better than sending focus on mouse down (still need to improve this) + LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, true ); + }; + }; + + // force a GLUT update + glutPostRedisplay(); + } + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int xIn , int yIn ) + { + // texture is scaled to fit the screen so we scale mouse coords in the same way + xIn = ( xIn * mBrowserWindowWidth ) / mAppWindowWidth; + yIn = ( yIn * mBrowserWindowHeight ) / mAppWindowHeight; + + // send event to LLQtWebKit + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, + LLQtWebKit::ME_MOUSE_MOVE, + LLQtWebKit::MB_MOUSE_BUTTON_LEFT, + xIn, yIn, + LLQtWebKit::KM_MODIFIER_NONE ); + + + // force a GLUT update + glutPostRedisplay(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyboard( unsigned char keyIn, bool isDown) + { + // ESC key exits + if ( keyIn == 27 ) + { + reset(); + + exit( 0 ); + }; + + // Translate some keys + switch(keyIn) + { + case 127: + // Turn delete char into backspace + keyIn = LLQtWebKit::KEY_BACKSPACE; + break; + case '\r': + case '\n': + // Turn CR and NL into enter key + keyIn = LLQtWebKit::KEY_RETURN; + break; + + case '\t': + keyIn = LLQtWebKit::KEY_TAB; + break; + + default: + break; + } + + // control-H goes home + if ( keyIn == 8 ) + { + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mHomeUrl ); + } + // control-B navigates back + else if ( keyIn == 2 ) + { + LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK); + } + // control-F navigates forward + else if ( keyIn == 6 ) + { + LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD); + } + // control-R reloads + else if ( keyIn == 18 ) + { + LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); + } + // control-I toggles inspector + else if ( keyIn == 23 ) + { + LLQtWebKit::getInstance()->showWebInspector( true ); + } + else if ( keyIn == '1' ) + { + if ( getLLQtWebKitKeyboardModifierCode() == LLQtWebKit::KM_MODIFIER_CONTROL ) + { + LLQtWebKit::getInstance()->setPageZoomFactor( 1.0 ); + } + } + else if ( keyIn == '2' ) + { + if ( getLLQtWebKitKeyboardModifierCode() == LLQtWebKit::KM_MODIFIER_CONTROL ) + { + LLQtWebKit::getInstance()->setPageZoomFactor( 2.0 ); + } + } + + char text[2]; + if(keyIn < 0x80) + { + text[0] = (char)keyIn; + } + else + { + text[0] = 0; + } + + text[1] = 0; + + std::cerr << "key " << (isDown?"down ":"up ") << (int)keyIn << ", modifiers = " << (int)getLLQtWebKitKeyboardModifierCode() << std::endl; + + // send event to LLQtWebKit + LLQtWebKit::getInstance()->keyboardEvent(mBrowserWindowId, isDown?LLQtWebKit::KE_KEY_DOWN:LLQtWebKit::KE_KEY_UP, keyIn, text, getLLQtWebKitKeyboardModifierCode() ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyboardSpecial( int specialIn, bool isDown) + { + uint32_t key = LLQtWebKit::KEY_NONE; + + switch(specialIn) + { + case GLUT_KEY_F1: key = LLQtWebKit::KEY_F1; break; + case GLUT_KEY_F2: key = LLQtWebKit::KEY_F2; break; + case GLUT_KEY_F3: key = LLQtWebKit::KEY_F3; break; + case GLUT_KEY_F4: key = LLQtWebKit::KEY_F4; break; + case GLUT_KEY_F5: key = LLQtWebKit::KEY_F5; break; + case GLUT_KEY_F6: key = LLQtWebKit::KEY_F6; break; + case GLUT_KEY_F7: key = LLQtWebKit::KEY_F7; break; + case GLUT_KEY_F8: key = LLQtWebKit::KEY_F8; break; + case GLUT_KEY_F9: key = LLQtWebKit::KEY_F9; break; + case GLUT_KEY_F10: key = LLQtWebKit::KEY_F10; break; + case GLUT_KEY_F11: key = LLQtWebKit::KEY_F11; break; + case GLUT_KEY_F12: key = LLQtWebKit::KEY_F12; break; + case GLUT_KEY_LEFT: key = LLQtWebKit::KEY_LEFT; break; + case GLUT_KEY_UP: key = LLQtWebKit::KEY_UP; break; + case GLUT_KEY_RIGHT: key = LLQtWebKit::KEY_RIGHT; break; + case GLUT_KEY_DOWN: key = LLQtWebKit::KEY_DOWN; break; + case GLUT_KEY_PAGE_UP: key = LLQtWebKit::KEY_PAGE_UP; break; + case GLUT_KEY_PAGE_DOWN: key = LLQtWebKit::KEY_PAGE_DOWN;break; + case GLUT_KEY_HOME: key = LLQtWebKit::KEY_HOME; break; + case GLUT_KEY_END: key = LLQtWebKit::KEY_END; break; + case GLUT_KEY_INSERT: key = LLQtWebKit::KEY_INSERT; break; + + default: + break; + } + + if(key != LLQtWebKit::KEY_NONE) + { + keyboard(key, isDown); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onPageChanged( const EventType& /*eventIn*/ ) + { + // flag that an update is required - page grab happens in idle() so we don't stall + mNeedsUpdate = true; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateBegin( const EventType& eventIn ) + { + std::cout << "Event: begin navigation to " << eventIn.getEventUri() << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateComplete( const EventType& eventIn ) + { + std::cout << "Event: end navigation to " << eventIn.getEventUri() << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onUpdateProgress( const EventType& eventIn ) + { + std::cout << "Event: progress value updated to " << eventIn.getIntValue() << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onStatusTextChange( const EventType& eventIn ) + { + std::cout << "Event: status updated to " << eventIn.getStringValue() << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onTitleChange( const EventType& eventIn ) + { + std::cout << "Event: title changed to " << eventIn.getStringValue() << std::endl; + glutSetWindowTitle( eventIn.getStringValue().c_str() ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLocationChange( const EventType& eventIn ) + { + std::cout << "Event: location changed to " << eventIn.getStringValue() << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkHref( const EventType& eventIn ) + { + std::string uuid = eventIn.getStringValue2(); + + std::cout << "Event: clicked on link:" << std::endl; + std::cout << " URL:" << eventIn.getEventUri() << std::endl; + std::cout << " target:" << eventIn.getStringValue() << std::endl; + std::cout << " UUID:" << uuid << std::endl; + std::cout << std::endl; + + // Since we never actually open the window, send a "proxy window closed" back to webkit to keep it from leaking. + LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid); + }; + + // virtual + void onClickLinkNoFollow(const EventType& eventIn) + { + std::cout << "Clink link no-follow --" << std::endl; + std::cout << " URL:" << eventIn.getEventUri() << std::endl; + std::cout << " type:" << eventIn.getNavigationType() << std::endl; + std::cout << " trusted:" << eventIn.getTrustedHost() << std::endl; + } + + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCookieChanged( const EventType& eventIn ) + { + int dead = eventIn.getIntValue(); + std::cout << (dead?"deleting cookie: ":"setting cookie: ") << eventIn.getStringValue() << std::endl; + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + std::string onRequestFilePicker( const EventType& ) + { + std::string fn = chooseFileName(); + return fn; + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) + { + std::cout << "Auth request, url = " << in_url << ", realm = " << in_realm << std::endl; + out_username = ""; // replace these temporarily with site username/password as required. + out_password = ""; + return false; + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + bool onCertError(const std::string &in_url, const std::string &in_msg) + { + std::cout << "Cert error, url = " << in_url << ", message = " << in_msg << std::endl; + return false; // cancel (return true to ignore errors and continue) + } + + virtual void onQtDebugMessage( const std::string& msg, const std::string& msg_type) + { + std::cout << "QtDebugMsg [" << msg_type << "]> " << msg << std::endl; + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLinkHovered( const EventType& eventIn ) + { + std::cout + << "Link hovered, link = " << eventIn.getEventUri() + << ", title = " << eventIn.getStringValue() + << ", text = " << eventIn.getStringValue2() + << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onWindowCloseRequested( const EventType& ) + { + std::cout << "Event: window close requested" << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateErrorPage( const EventType& event ) + { + std::cout << "Error page hit with code of " << event.getIntValue() << " - navigating to another URL" << std::endl; + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "http://bestbuy.com" ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onWindowGeometryChangeRequested( const EventType& eventIn) + { + int x, y, width, height; + eventIn.getRectValue(x, y, width, height); + + std::cout << "Event: window geometry change requested" << std::endl; + std::cout << " uuid: " << eventIn.getStringValue() << std::endl; + std::cout << " location: (" << x << ", " << y << ")" << std::endl; + std::cout << " size: (" << width << ", " << height << ")" << std::endl; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getAppWindowWidth() + { + return mAppWindowWidth; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + int getAppWindowHeight() + { + return mAppWindowHeight; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + std::string getAppWindowName() + { + return mAppWindowName; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void* getNativeWindowHandle() + { + // My implementation of the embedded browser needs a native window handle + // Can't get this via GLUT so had to use this hack + #ifdef _WINDOWS + return FindWindow( NULL, (LPCWSTR)mAppWindowName.c_str() ); + #else + #ifdef LL_OSX + // not needed on osx + return 0; + #else + //#error "You will need an implementation of this method" + return 0; + #endif + #endif + }; + + private: + int mAppWindowWidth; + int mAppWindowHeight; + int mBrowserWindowWidth; + int mBrowserWindowHeight; + int mAppTextureWidth; + int mAppTextureHeight; + GLuint mAppTexture; + int mBrowserWindowId; + std::string mAppWindowName; + std::string mHomeUrl; + std::string mCwd; + bool mNeedsUpdate; + std::string mApplicationDir; + std::string mProfileDir; + std::string mCookiePath; +}; + +testGL* theApp; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutReshape( int widthIn, int heightIn ) +{ + if ( theApp ) + theApp->reshape( widthIn, heightIn ); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutDisplay() +{ + if ( theApp ) + theApp->display(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutIdle() +{ + if ( theApp ) + theApp->idle(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutKeyboard( unsigned char keyIn, int /*xIn*/, int /*yIn*/ ) +{ + if ( theApp ) + { + theApp->keyboard( keyIn, true ); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutKeyboardUp( unsigned char keyIn, int /*xIn*/, int /*yIn*/ ) +{ + if ( theApp ) + { + theApp->keyboard( keyIn, false ); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutSpecial( int specialIn, int /*xIn*/, int /*yIn*/ ) +{ + if ( theApp ) + { + theApp->keyboardSpecial( specialIn, true ); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutSpecialUp( int specialIn, int /*xIn*/, int /*yIn*/ ) +{ + if ( theApp ) + { + theApp->keyboardSpecial( specialIn, false ); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseMove( int xIn , int yIn ) +{ + if ( theApp ) + theApp->mouseMove( xIn, yIn ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void glutMouseButton( int buttonIn, int stateIn, int xIn, int yIn ) +{ + if ( theApp ) + theApp->mouseButton( buttonIn, stateIn, xIn, yIn ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +int main( int argc, char* argv[] ) +{ + glutInit( &argc, argv ); + glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB ); + + // implementation in a class so we can observer events + // means we need this painful GLUT <--> class shim... + theApp = new testGL; + + if ( theApp ) + { + glutInitWindowPosition( 80, 0 ); + glutInitWindowSize( theApp->getAppWindowWidth(), theApp->getAppWindowHeight() ); + + glutCreateWindow( theApp->getAppWindowName().c_str() ); + + std::string url = ""; + if ( 2 == argc ) + url = std::string( argv[ 1 ] ); + + theApp->init( std::string( argv[ 0 ] ), url ); + + glutKeyboardFunc( glutKeyboard ); + glutKeyboardUpFunc( glutKeyboardUp ); + glutSpecialFunc( glutSpecial ); + glutSpecialUpFunc( glutSpecialUp ); + + glutMouseFunc( glutMouseButton ); + glutPassiveMotionFunc( glutMouseMove ); + glutMotionFunc( glutMouseMove ); + + glutDisplayFunc( glutDisplay ); + glutReshapeFunc( glutReshape ); + + glutIdleFunc( glutIdle ); + + glutMainLoop(); + + std::cout << "glutMainLoop returned" << std::endl; + + delete theApp; + }; + + return 0; +} diff --git a/indra/llqtwebkit/tests/testgl/testgl.pro b/indra/llqtwebkit/tests/testgl/testgl.pro new file mode 100644 index 000000000..42692d68d --- /dev/null +++ b/indra/llqtwebkit/tests/testgl/testgl.pro @@ -0,0 +1,38 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +INCLUDEPATH += ../../ +CONFIG -= app_bundle + +QT += webkit opengl network + +!mac { +unix { + DEFINES += LL_LINUX + LIBS += -lglui -lglut + LIBS += $$PWD/../../libllqtwebkit.a +} +} + +mac { + DEFINES += LL_OSX + LIBS += -framework GLUT -framework OpenGL + LIBS += $$PWD/libllqtwebkit.dylib +} + +win32 { + DEFINES += _WINDOWS + INCLUDEPATH += ../ + INCLUDEPATH += $$PWD/../../stage/packages/include + DESTDIR=../build + release { + LIBS += $$PWD/../../Release/llqtwebkit.lib + LIBS += $$PWD/../build/freeglut_static.lib + LIBS += comdlg32.lib + } +} + +include(../../static.pri) + +SOURCES += testgl.cpp diff --git a/indra/llqtwebkit/tests/textmode/textmode.cpp b/indra/llqtwebkit/tests/textmode/textmode.cpp new file mode 100644 index 000000000..019fba902 --- /dev/null +++ b/indra/llqtwebkit/tests/textmode/textmode.cpp @@ -0,0 +1,292 @@ +/* Copyright (c) 2006-2010, Linden Research, Inc. + * + * LLQtWebKit 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 GPL-license.txt in this distribution, or online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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 FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/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. + */ + +#ifndef _WINDOWS +extern "C" { +#include +} +#endif + +#ifdef _WINDOWS +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef LL_OSX +// I'm not sure why STATIC_QT is getting defined, but the Q_IMPORT_PLUGIN thing doesn't seem to be necessary on the mac. +#undef STATIC_QT +#endif + +#ifdef STATIC_QT +#include +Q_IMPORT_PLUGIN(qgif) +#endif + +#include "llqtwebkit.h" + +class textMode : + public LLEmbeddedBrowserWindowObserver +{ + public: + textMode( std::string url, bool ignore_ca_file, bool ignore_ssl_errors ) : + mBrowserWindowWidth( 512 ), + mBrowserWindowHeight( 512 ), + mBrowserWindowHandle( 0 ), + mNavigateInProgress( true ), + mLogLine( "" ) + { + +#ifdef _WINDOWS + std::string cwd = std::string( _getcwd( NULL, 1024) ); + std::string profile_dir = cwd + "\\" + "textmode_profile"; + void* native_window_handle = (void*)GetDesktopWindow(); + std::string ca_file_loc = cwd + "\\" + "CA.pem"; +#else + std::string cwd = std::string( getcwd( NULL, 1024) ); + std::string profile_dir = cwd + "/" + "textmode_profile"; + void* native_window_handle = 0; + std::string ca_file_loc = cwd + "/" + "CA.pem"; +#endif + mLogLine << "Current working dir is " << cwd << std::endl; + mLogLine << "Profiles dir is " << profile_dir; + writeLine( mLogLine.str() ); + + LLQtWebKit::getInstance()->init( cwd, cwd, profile_dir, native_window_handle ); + + LLQtWebKit::getInstance()->enableQtMessageHandler( true ); + + LLQtWebKit::getInstance()->enableJavaScript( true ); + LLQtWebKit::getInstance()->enablePlugins( true ); + + mBrowserWindowHandle = LLQtWebKit::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); + LLQtWebKit::getInstance()->setSize( mBrowserWindowHandle, mBrowserWindowWidth, mBrowserWindowHeight ); + + LLQtWebKit::getInstance()->addObserver( mBrowserWindowHandle, this ); + + if ( ! ignore_ca_file ) + { + mLogLine.str(""); + mLogLine << "Expected certificate authority file location is " << ca_file_loc; + writeLine( mLogLine.str() ); + LLQtWebKit::getInstance()->setCAFile( ca_file_loc.c_str() ); + } + else + { + mLogLine.str(""); + mLogLine << "Not loading certificate authority file"; + writeLine( mLogLine.str() ); + }; + + if ( ignore_ssl_errors ) + { + LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( true ); + mLogLine.str(""); + mLogLine << "Ignoring SSL errors"; + writeLine( mLogLine.str() ); + } + else + { + mLogLine.str(""); + mLogLine << "Not ignoring SSL errors"; + writeLine( mLogLine.str() ); + }; + + mLogLine.str(""); + mLogLine << "Navigating to " << url; + writeLine( mLogLine.str() ); + + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowHandle, url ); + }; + + bool idle( void ) + { + LLQtWebKit::getInstance()->pump( 100 ); + +#if _WINDOWS + MSG msg; + while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + GetMessage( &msg, NULL, 0, 0 ); + TranslateMessage( &msg ); + DispatchMessage( &msg ); + }; +#endif + return mNavigateInProgress; + }; + + ~textMode() + { + LLQtWebKit::getInstance()->remObserver( mBrowserWindowHandle, this ); + LLQtWebKit::getInstance()->reset(); + }; + + void onNavigateBegin( const EventType& eventIn ) + { + mNavigateInProgress = true; + mLogLine.str(""); + mLogLine << "Event: Begin navigation to " << eventIn.getEventUri(); + writeLine( mLogLine.str() ); + }; + + void onNavigateComplete( const EventType& eventIn ) + { + mLogLine.str(""); + mLogLine << "Event: End navigation to " << eventIn.getEventUri(); + writeLine( mLogLine.str() ); + mNavigateInProgress = false; + }; + + void onUpdateProgress( const EventType& eventIn ) + { + mLogLine.str(""); + mLogLine << "Event: progress value updated to " << eventIn.getIntValue(); + writeLine( mLogLine.str() ); + }; + + void onStatusTextChange( const EventType& eventIn ) + { + mLogLine.str(""); + mLogLine << "Event: status updated to " << eventIn.getStringValue(); + writeLine( mLogLine.str() ); + }; + + void onTitleChange( const EventType& eventIn ) + { + mLogLine.str(""); + mLogLine << "Event: title change to " << eventIn.getStringValue(); + writeLine( mLogLine.str() ); + }; + + void onLocationChange( const EventType& eventIn ) + { + mLogLine.str(""); + mLogLine << "Event: location changed to " << eventIn.getStringValue(); + writeLine( mLogLine.str() ); + }; + + bool onCertError(const std::string &in_url, const std::string &in_msg) + { + mLogLine.str(""); + mLogLine << "Cert error triggered: " << std::endl << in_url << "\n" << in_msg; + writeLine( mLogLine.str() ); + return true; + } + + void onCookieChanged(const EventType& event) + { + std::string url = event.getEventUri(); + std::string cookie = event.getStringValue(); + int dead = event.getIntValue(); + mLogLine.str(""); + if ( ! dead ) + mLogLine << "Cookie added:" << cookie; + else + mLogLine << "Cookie deleted:" << cookie; + writeLine( mLogLine.str() ); + } + + virtual void onQtDebugMessage( const std::string& msg, const std::string& msg_type) + { + mLogLine.str(""); + mLogLine << "QtDebugMsg (" << msg_type << "): " << msg.substr(msg.length() - 1); + writeLine( mLogLine.str() ); + } + + void writeLine( std::string line ) + { + double elapsed_seconds = (double)clock() / (double)CLOCKS_PER_SEC; + + std::cout << "[" << std::setprecision(7) << std::setw(3) << std::setfill('0') << elapsed_seconds << "] "; + const int max_len = 140; + if ( line.length() > max_len ) + { + std::cout << line.substr(0, max_len); + std::cout << "...."; + } + else + { + std::cout << line; + } + std::cout << std::endl; + //std::cout << std::endl; + } + + private: + int mBrowserWindowWidth; + int mBrowserWindowHeight; + int mBrowserWindowHandle; + bool mNavigateInProgress; + std::ostringstream mLogLine; +}; + +int main( int argc, char* argv[] ) +{ + bool ingore_ssl_errors = false; + bool ignore_ca_file = false; + + for( int i = 1; i < argc; ++i ) + { + if ( std::string( argv[ i ] ) == "--help" ) + { + std::cout << std::endl << "textmode " << std::endl; + exit( 0 ); + }; + + if ( std::string( argv[ i ] ) == "--ignoresslerrors" ) + ingore_ssl_errors = true; + + if ( std::string( argv[ i ] ) == "--ignorecafile" ) + ignore_ca_file = true; + }; + + std::string url ( "https://my.secondlife.com/callum.linden" ); + for( int i = 1; i < argc; ++i ) + { + if ( std::string( argv[ i ] ).substr( 0, 2 ) != "--" ) + { + url = std::string( argv[ i ] ); + break; + }; + }; + + textMode* app = new textMode( url, ignore_ca_file, ingore_ssl_errors ); + + bool result = app->idle(); + while( result ) + { + result = app->idle(); + }; + + delete app; + + return 0; +} diff --git a/indra/llqtwebkit/tests/textmode/textmode.pro b/indra/llqtwebkit/tests/textmode/textmode.pro new file mode 100644 index 000000000..d41e1ea68 --- /dev/null +++ b/indra/llqtwebkit/tests/textmode/textmode.pro @@ -0,0 +1,28 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +INCLUDEPATH += ../../ +CONFIG -= app_bundle +CONFIG += console + +QT += webkit network + +mac { + DEFINES += LL_OSX + LIBS += $$PWD/libllqtwebkit.dylib +} + +win32 { + DEFINES += _WINDOWS + INCLUDEPATH += ../ + DESTDIR=../build + LIBS += user32.lib + release { + LIBS += $$PWD/../../Release/llqtwebkit.lib + } +} + +include(../../static.pri) + +SOURCES += textmode.cpp diff --git a/indra/llqtwebkit/win32/3p-qt-vars.bat b/indra/llqtwebkit/win32/3p-qt-vars.bat new file mode 100644 index 000000000..5ea118848 --- /dev/null +++ b/indra/llqtwebkit/win32/3p-qt-vars.bat @@ -0,0 +1,6 @@ +@echo off +echo Setting up a Qt environment using 3p-qt HG repository +set QTDIR=C:\Work\3p-llqtwebkit\stage +set PATH=C:\Work\3p-llqtwebkit\stage\bin;%PATH% +set QMAKESPEC=win32-msvc2010 +call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat" diff --git a/indra/llqtwebkit/win32/Qt Command Prompt (3p-qt).lnk b/indra/llqtwebkit/win32/Qt Command Prompt (3p-qt).lnk new file mode 100644 index 0000000000000000000000000000000000000000..460a9e9cf126aa1725435f3759d4ba768a4a9730 GIT binary patch literal 2369 zcmeHITS(JU82@b=cY{v!!P>$J8kQVt>~J zH#*@&7kuz?R0j5h5HD0BQ3u;eZ;#7UTm)1`FwbO5pI~Ms$j@UjZ8%A+9=PB^F*p^O zXcWmM_f({`>*4S?jjj`}h@Yn_pCt+j=1gupc?xN6aS+Q1BQZ~q#7|%cDTgHg7g

zvYjOJ<48-d4o~YS!SIEmV-K&%9(DtHL^i@6#iJu*N9?NXi1sNR7L*gCiLpG2c521w zrcWKLM;Hws{XRsyn|d+UQPU&;ALiIqOqtFBY(Vj#?E=lrfbXoyc(IzQT4OmRMg?Xi$H`C3ba?jno)19=Z zla`UNSy)_~dUwPqlT@!{;IO__l+CKuTBTkj>ZeKK>;+;_|DM z`)}Z{f0sGFo%ZE2K!9a0!iqu!BO!xC0k? z_AKgjc*#3>TI7xIB$t+iBUlb#iBkGAJ_eMMuJwt$(KdNJOBsTUaH`0eR>vXK271+p f-d@p2tW^AdKc!d#xDq%FXJ3Gtv{= INIT_STATE_NAVIGATE_COMPLETE) { if(!mInitialNavigateURL.empty()) { @@ -284,7 +284,7 @@ private: bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); if ( result ) { - mInitState = INIT_STATE_INITIALIZED; + setInitState(INIT_STATE_INITIALIZED); // debug spam sent to viewer and displayed in the log as usual postDebugMessage( "browser initialized okay" ); From b0415370f874f631a4321bd730792f7aa8965596 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Thu, 13 Sep 2012 18:19:38 -0400 Subject: [PATCH 013/138] Breakpad cmake --- indra/cmake/CMakeLists.txt | 2 ++ indra/cmake/FindGoogleBreakpad.cmake | 40 ++++++++++++++++++++++++++++ indra/cmake/GoogleBreakpad.cmake | 19 +++++++++++++ install.xml | 19 +++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 indra/cmake/FindGoogleBreakpad.cmake create mode 100644 indra/cmake/GoogleBreakpad.cmake diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 21eee45ac..0f7c2dea9 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -27,6 +27,7 @@ set(cmake_SOURCE_FILES FindBerkeleyDB.cmake FindCARes.cmake FindELFIO.cmake + FindGoogleBreakpad.cmake FindGooglePerfTools.cmake FindHunSpell.cmake FindMT.cmake @@ -37,6 +38,7 @@ set(cmake_SOURCE_FILES FMODEX.cmake FreeType.cmake GStreamer010Plugin.cmake + GoogleBreakpad.cmake GooglePerfTools.cmake Hunspell.cmake JPEG.cmake diff --git a/indra/cmake/FindGoogleBreakpad.cmake b/indra/cmake/FindGoogleBreakpad.cmake new file mode 100644 index 000000000..1a0493be5 --- /dev/null +++ b/indra/cmake/FindGoogleBreakpad.cmake @@ -0,0 +1,40 @@ +# -*- cmake -*- + +# - Find Google BreakPad +# Find the Google BreakPad includes and library +# This module defines +# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc. +# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad. +# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad. +# also defined, but not for general use are +# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library. + +FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h) + +SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client) +FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY + NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} + ) + +IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) + SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY}) + SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES") +ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) + SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO") +ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR) + + +IF (BREAKPAD_EXCEPTION_HANDLER_FOUND) + IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) + MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}") + ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY) +ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND) + IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find Google BreakPad library") + ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED) +ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND) + +MARK_AS_ADVANCED( + BREAKPAD_EXCEPTION_HANDLER_LIBRARY + BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR + ) diff --git a/indra/cmake/GoogleBreakpad.cmake b/indra/cmake/GoogleBreakpad.cmake new file mode 100644 index 000000000..749867404 --- /dev/null +++ b/indra/cmake/GoogleBreakpad.cmake @@ -0,0 +1,19 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON) + include(FindGoogleBreakpad) +else (STANDALONE) + use_prebuilt_binary(google_breakpad) + if (DARWIN) + set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler) + endif (DARWIN) + if (LINUX) + set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client) + endif (LINUX) + if (WINDOWS) + set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client common) + endif (WINDOWS) +endif (STANDALONE) + diff --git a/install.xml b/install.xml index 1434b9cd0..9a994bdda 100644 --- a/install.xml +++ b/install.xml @@ -567,6 +567,25 @@ + google_breakpad + + copyright + Copyright (c) Google Inc. + description + A cross platform crashreporter + license + bsd + packages + + windows + + md5sum + 0bf54905717704c56d4cd0d72d2208b5 + url + https://github.com/downloads/LightDrake/Public-Libraries/google_breakpad-0.0.0-rev599-windows-20110218.tar.bz2 + + + gperftools copyright From e0a7c7e935289c3fa8a1d83650b36978fbfaf553 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Thu, 13 Sep 2012 19:39:02 -0400 Subject: [PATCH 014/138] Renamed our log files to not conflict with linden --- indra/newview/llappviewer.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 955a420c6..0b1c97a1d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -316,10 +316,10 @@ BOOL gLogoutInProgress = FALSE; // Internal globals... that should be removed. static std::string gArgs; -const std::string MARKER_FILE_NAME("SecondLife.exec_marker"); -const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker"); -const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker"); -const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker"); +const std::string MARKER_FILE_NAME("Singularity.exec_marker"); +const std::string ERROR_MARKER_FILE_NAME("Singularity.error_marker"); +const std::string LLERROR_MARKER_FILE_NAME("Singularity.llerror_marker"); +const std::string LOGOUT_MARKER_FILE_NAME("Singularity.logout_marker"); static BOOL gDoDisconnect = FALSE; // //static BOOL gBusyDisconnect = FALSE; @@ -1869,15 +1869,15 @@ bool LLAppViewer::initLogging() // Remove the last ".old" log file. std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "SecondLife.old"); + "Singularity.old"); LLFile::remove(old_log_file); // Rename current log file to ".old" std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "SecondLife.log"); + "Singularity.log"); LLFile::rename(log_file, old_log_file); - // Set the log file to SecondLife.log + // Set the log file to Singularity.log LLError::logToFile(log_file); @@ -2931,10 +2931,10 @@ void LLAppViewer::initMarkerFile() LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL; //We've got 4 things to test for here - // - Other Process Running (SecondLife.exec_marker present, locked) - // - Freeze (SecondLife.exec_marker present, not locked) - // - LLError Crash (SecondLife.llerror_marker present) - // - Other Crash (SecondLife.error_marker present) + // - Other Process Running (Singularity.exec_marker present, locked) + // - Freeze (Singularity.exec_marker present, not locked) + // - LLError Crash (Singularity.llerror_marker present) + // - Other Crash (Singularity.error_marker present) // These checks should also remove these files for the last 2 cases if they currently exist //LLError/Error checks. Only one of these should ever happen at a time. From cb9f972d13bdade57af263b750a3c32edc1d2cf3 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Fri, 14 Sep 2012 00:30:25 -0400 Subject: [PATCH 015/138] BE GONE --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c56bf2a54..bbd3247a9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /bin-release /indra/viewer-* /indra/newview/vivox-runtime/ +/indra/newview/dbghelp.dll /libraries/ /lib/ *.pyc From f50d23a0d425bc53044e02912646c560a402f86a Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Fri, 14 Sep 2012 00:30:52 -0400 Subject: [PATCH 016/138] Fast Timers brought up to linden equiv --- indra/llcharacter/llcharacter.cpp | 11 +- indra/llcharacter/llmotioncontroller.cpp | 7 +- indra/llmessage/llurlrequest.cpp | 5 +- indra/llrender/llimagegl.cpp | 2 + indra/llui/lltrans.cpp | 10 +- indra/llui/lluictrl.cpp | 3 + indra/llui/llview.cpp | 2 +- indra/newview/llappviewer.cpp | 5 +- indra/newview/lldrawpoolavatar.cpp | 8 +- indra/newview/llpolymesh.cpp | 4 + indra/newview/llpolymorph.cpp | 4 + indra/newview/llviewerobjectlist.cpp | 21 ++- indra/newview/llvograss.cpp | 1 + indra/newview/llvopartgroup.cpp | 2 +- indra/newview/llvosky.cpp | 4 +- indra/newview/llvotree.cpp | 1 - indra/newview/llvowater.cpp | 2 + indra/newview/llvowlsky.cpp | 1 + indra/newview/llworld.cpp | 2 + indra/newview/pipeline.cpp | 175 +++++++++++++++-------- indra/newview/pipeline.h | 2 +- 21 files changed, 192 insertions(+), 80 deletions(-) diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 6818be493..23d1fbeb3 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -193,21 +193,30 @@ void LLCharacter::requestStopMotion( LLMotion* motion) //----------------------------------------------------------------------------- // updateMotions() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation"); +static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim"); +static LLFastTimer::DeclareTimer FTM_UPDATE_MOTIONS("Update Motions"); + void LLCharacter::updateMotions(e_update_t update_type) { if (update_type == HIDDEN_UPDATE) { + LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION); mMotionController.updateMotionsMinimal(); } else { + LLFastTimer t(FTM_UPDATE_ANIMATION); // unpause if the number of outstanding pause requests has dropped to the initial one if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) { mMotionController.unpauseAllMotions(); } bool force_update = (update_type == FORCE_UPDATE); - mMotionController.updateMotions(force_update); + { + LLFastTimer t(FTM_UPDATE_MOTIONS); + mMotionController.updateMotions(force_update); + } } } diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index d040a1a22..eecbd1823 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -547,6 +547,8 @@ void LLMotionController::updateIdleActiveMotions() //----------------------------------------------------------------------------- // updateMotionsByType() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_MOTION_ON_UPDATE("Motion onUpdate"); + void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type) { BOOL update_result = TRUE; @@ -704,7 +706,10 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty } // perform motion update - update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); + { + LLFastTimer t(FTM_MOTION_ON_UPDATE); + update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); + } } //********************** diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 6b6fd445f..65967085f 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -253,6 +253,8 @@ LLIOPipe::EStatus LLURLRequest::handleError( } static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request"); +static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); +static LLFastTimer::DeclareTimer FTM_URL_PERFORM("Perform"); // virtual LLIOPipe::EStatus LLURLRequest::process_impl( @@ -323,7 +325,6 @@ LLIOPipe::EStatus LLURLRequest::process_impl( { PUMP_DEBUG; LLIOPipe::EStatus status = STATUS_BREAK; - static LLFastTimer::DeclareTimer FTM_URL_PERFORM("Perform"); { LLFastTimer t(FTM_URL_PERFORM); mDetail->mCurlRequest->perform(); @@ -333,8 +334,6 @@ LLIOPipe::EStatus LLURLRequest::process_impl( { CURLcode result; - static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); - bool newmsg = false; { LLFastTimer t(FTM_PROCESS_URL_REQUEST_GET_RESULT); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index dfac4c2af..5bf4f1f38 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -290,9 +290,11 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) //---------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_STATS("Image Stats"); // static void LLImageGL::updateStats(F32 current_time) { + LLFastTimer t(FTM_IMAGE_UPDATE_STATS); sLastFrameTime = current_time; sBoundTextureMemoryInBytes = sCurBoundTextureMemory; sCurBoundTextureMemory = 0; diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index f7988c965..13721aa40 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -92,9 +92,15 @@ bool LLTrans::parseStrings(const std::string& xml_filename, const std::setgetWindow()->processMiscNativeEvents(); } - + pingMainloopTimeout("Main:GatherInput"); if (gViewerWindow) @@ -1207,6 +1209,7 @@ bool LLAppViewer::mainLoop() // yield some time to the os based on command line option if(mYieldTime >= 0) { + LLFastTimer t(FTM_YIELD); ms_sleep(mYieldTime); } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 3e818faa4..e74bacaa8 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -99,7 +99,6 @@ S32 AVATAR_OFFSET_TEX0 = 32; S32 AVATAR_OFFSET_TEX1 = 40; S32 AVATAR_VERTEX_BYTES = 48; - BOOL gAvatarEmbossBumpMap = FALSE; static BOOL sRenderingSkinned = FALSE; S32 normal_channel = -1; @@ -1040,9 +1039,12 @@ void LLDrawPoolAvatar::endDeferredSkinned() gGL.getTexUnit(0)->activate(); } +static LLFastTimer::DeclareTimer FTM_RENDER_AVATARS("renderAvatars"); void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { + LLFastTimer t(FTM_RENDER_AVATARS); + if (pass == -1) { for (S32 i = 1; i < getNumPasses(); i++) @@ -1546,8 +1548,12 @@ void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar) renderRigged(avatar, RIGGED_DEFERRED_BUMP); } +static LLFastTimer::DeclareTimer FTM_RIGGED_VBO("Rigged VBO"); + void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { + LLFastTimer t(FTM_RIGGED_VBO); + //update rigged vertex buffers for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type) { diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index d7b342b25..1265ed7c7 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -1912,8 +1912,12 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion"); + void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { + LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY); + F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); LLJoint* joint; diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index b43837e89..cfbe6907c 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -781,6 +781,8 @@ F32 LLPolyMorphTarget::getMaxDistortion() //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph"); + void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) @@ -788,6 +790,8 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) return; } + LLFastTimer t(FTM_APPLY_MORPH_TARGET); + mLastSex = avatar_sex; // Check for NaN condition (NaN is detected if a variable doesn't equal itself. diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 475950f5d..df6a14a20 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1499,6 +1499,10 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id) mPendingPhysicsFlags.erase(object_id); } +static LLFastTimer::DeclareTimer FTM_SHIFT_OBJECTS("Shift Objects"); +static LLFastTimer::DeclareTimer FTM_PIPELINE_SHIFT("Pipeline Shift"); +static LLFastTimer::DeclareTimer FTM_REGION_SHIFT("Region Shift"); + void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { // This is called when we shift our origin when we cross region boundaries... @@ -1510,6 +1514,8 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) return; } + LLFastTimer t(FTM_SHIFT_OBJECTS); + LLViewerObject *objectp; for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) { @@ -1526,8 +1532,15 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) } } - gPipeline.shiftObjects(offset); - LLWorld::getInstance()->shiftRegions(offset); + { + LLFastTimer t(FTM_PIPELINE_SHIFT); + gPipeline.shiftObjects(offset); + } + + { + LLFastTimer t(FTM_REGION_SHIFT); + LLWorld::getInstance()->shiftRegions(offset); + } } void LLViewerObjectList::repartitionObjects() @@ -2062,8 +2075,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) llinfos << "Agent: " << objectp->getPositionAgent() << llendl; addDebugBeacon(objectp->getPositionAgent(),""); #endif - gPipeline.markMoved(objectp->mDrawable); - objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); + gPipeline.markMoved(objectp->mDrawable); + objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); // Flag the object as no longer orphaned childp->mOrphaned = FALSE; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 6434dd619..c36ad0787 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -330,6 +330,7 @@ BOOL LLVOGrass::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return TRUE ; } + if (mPatch && (mLastPatchUpdateTime != mPatch->getLastUpdateTime())) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 0a5a76900..3dca0b479 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -167,6 +167,7 @@ void LLVOPartGroup::freeVBSlot(S32 idx) *sVBSlotCursor = idx; } } + LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLAlphaObject(id, pcode, regionp), mViewerPartGroupp(NULL) @@ -181,7 +182,6 @@ LLVOPartGroup::~LLVOPartGroup() { } - BOOL LLVOPartGroup::isActive() const { return FALSE; diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 416834eee..de657beed 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -352,7 +352,6 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) cloud_pos_density1 = LLColor3(); cloud_pos_density2 = LLColor3(); - mInitialized = FALSE; mbCanSelect = FALSE; mUpdateTimer.reset(); @@ -409,7 +408,6 @@ LLVOSky::~LLVOSky() mCubeMap = NULL; } - void LLVOSky::init() { const F32 haze_int = color_intens(mHaze.calcSigSca(0)); @@ -1250,6 +1248,7 @@ void LLVOSky::createDummyVertexBuffer() } static LLFastTimer::DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update"); + void LLVOSky::updateDummyVertexBuffer() { if(!LLVertexBuffer::sEnableVBOs) @@ -1491,6 +1490,7 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons } llassert(facep->getVertexBuffer()->getNumIndices() == 6); + index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index e50c11ced..c765371c6 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -894,7 +894,6 @@ void LLVOTree::updateMesh() S32 stop_depth = 0; F32 alpha = 1.0; - U32 vert_count = 0; U32 index_count = 0; diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 05e033392..6f085d6cc 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -140,6 +140,7 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) } static LLFastTimer::DeclareTimer FTM_UPDATE_WATER("Update Water"); + BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(FTM_UPDATE_WATER); @@ -213,6 +214,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { //bump edge patches down 10 cm to prevent aliasing along edges z_fudge = -0.1f; } + for (y = 0; y < size; y++) { for (x = 0; x < size; x++) diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index e9a03fee8..492bfe174 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -354,6 +354,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) llinfos << "WL Skydome strips in " << strips_segments << " batches." << llendl; mStripsVerts.resize(strips_segments, NULL); + LLTimer timer; timer.start(); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 6f92bedf9..e4605ec9c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1253,9 +1253,11 @@ void LLWorld::disconnectRegions() } } +static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim"); void process_enable_simulator(LLMessageSystem *msg, void **user_data) { + LLFastTimer t(FTM_ENABLE_SIMULATOR); // enable the appropriate circuit for this simulator and // add its values into the gSimulator structure U64 handle; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 12f7c170e..4a8a021a2 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -110,7 +110,7 @@ #include "llspatialpartition.h" #include "llmutelist.h" -// [RLVa:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] @@ -185,8 +185,13 @@ LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); +LLFastTimer::DeclareTimer FTM_PIPELINE_CREATE("Pipeline Create"); LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); LLFastTimer::DeclareTimer FTM_POOLS("Pools"); +LLFastTimer::DeclareTimer FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)"); +LLFastTimer::DeclareTimer FTM_DEFERRED_POOLS("Pools (Deferred)"); +LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)"); +LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLS("Pools (Post)"); LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); @@ -1474,7 +1479,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::createObjects(F32 max_dtime) { - LLFastTimer ftm(FTM_GEO_UPDATE); + LLFastTimer ftm(FTM_PIPELINE_CREATE); LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); LLTimer update_timer; @@ -2311,14 +2316,19 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool"); +static LLFastTimer::DeclareTimer FTM_UPDATE_GL("Update GL"); + void LLPipeline::updateGL() { - while (!LLGLUpdate::sGLQ.empty()) { - LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); - glu->updateGL(); - glu->mInQ = FALSE; - LLGLUpdate::sGLQ.pop_front(); + LLFastTimer t(FTM_UPDATE_GL); + while (!LLGLUpdate::sGLQ.empty()) + { + LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); + glu->updateGL(); + glu->mInQ = FALSE; + LLGLUpdate::sGLQ.pop_front(); + } } /*{ //seed VBO Pools @@ -2327,11 +2337,14 @@ void LLPipeline::updateGL() }*/ } +static LLFastTimer::DeclareTimer FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups"); + void LLPipeline::rebuildPriorityGroups() { + LLFastTimer t(FTM_REBUILD_PRIORITY_GROUPS); LLTimer update_timer; LLMemType mt(LLMemType::MTYPE_PIPELINE); - + assertInitialized(); gMeshRepo.notifyLoadedMeshes(); @@ -2350,7 +2363,9 @@ void LLPipeline::rebuildPriorityGroups() mGroupQ1Locked = false; } - + +static LLFastTimer::DeclareTimer FTM_REBUILD_GROUPS("Rebuild Groups"); + void LLPipeline::rebuildGroups() { if (mGroupQ2.empty()) @@ -2358,6 +2373,7 @@ void LLPipeline::rebuildGroups() return; } + LLFastTimer t(FTM_REBUILD_GROUPS); mGroupQ2Locked = true; // Iterate through some drawables on the non-priority build queue S32 size = (S32) mGroupQ2.size(); @@ -2614,6 +2630,10 @@ void LLPipeline::markShift(LLDrawable *drawablep) } } +static LLFastTimer::DeclareTimer FTM_SHIFT_DRAWABLE("Shift Drawable"); +static LLFastTimer::DeclareTimer FTM_SHIFT_OCTREE("Shift Octree"); +static LLFastTimer::DeclareTimer FTM_SHIFT_HUD("Shift HUD"); + void LLPipeline::shiftObjects(const LLVector3 &offset) { LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); @@ -2626,35 +2646,44 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) LLVector4a offseta; offseta.load3(offset.mV); - for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); - iter != mShiftList.end(); iter++) { - LLDrawable *drawablep = *iter; - if (drawablep->isDead()) + LLFastTimer t(FTM_SHIFT_DRAWABLE); + for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); + iter != mShiftList.end(); iter++) { - continue; - } - drawablep->shiftPos(offseta); - drawablep->clearState(LLDrawable::ON_SHIFT_LIST); - } - mShiftList.resize(0); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) + LLDrawable *drawablep = *iter; + if (drawablep->isDead()) { - part->shift(offseta); + continue; + } + drawablep->shiftPos(offseta); + drawablep->clearState(LLDrawable::ON_SHIFT_LIST); + } + mShiftList.resize(0); + } + + { + LLFastTimer t(FTM_SHIFT_OCTREE); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->shift(offseta); + } } } } - LLHUDText::shiftAll(offset); - LLHUDNameTag::shiftAll(offset); + { + LLFastTimer t(FTM_SHIFT_HUD); + LLHUDText::shiftAll(offset); + LLHUDNameTag::shiftAll(offset); + } display_update_camera(); } @@ -2687,8 +2716,10 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable) } } +static LLFastTimer::DeclareTimer FTM_PROCESS_PARTITIONQ("PartitionQ"); void LLPipeline::processPartitionQ() { + LLFastTimer t(FTM_PROCESS_PARTITIONQ); for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter) { LLDrawable* drawable = *iter; @@ -3228,7 +3259,7 @@ void LLPipeline::postSort(LLCamera& camera) rebuildPriorityGroups(); llpushcallstacks ; - + //build render map for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { @@ -3849,7 +3880,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); LLFastTimer t(FTM_RENDER_GEOMETRY); - LLFastTimer t2(FTM_POOLS); + LLFastTimer t2(FTM_DEFERRED_POOLS); LLGLEnable cull(GL_CULL_FACE); @@ -3892,7 +3923,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) { - LLFastTimer t(FTM_POOLRENDER); + LLFastTimer t(FTM_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -3947,7 +3978,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); - LLFastTimer t(FTM_POOLS); + LLFastTimer t(FTM_POST_DEFERRED_POOLS); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -3982,7 +4013,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LLFastTimer t(FTM_POOLRENDER); + LLFastTimer t(FTM_POST_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -4398,8 +4429,7 @@ void LLPipeline::renderDebug() gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV); gGL.end(); - } - + } } /*gGL.flush(); @@ -4527,8 +4557,11 @@ void LLPipeline::renderDebug() } } +static LLFastTimer::DeclareTimer FTM_REBUILD_POOLS("Rebuild Pools"); + void LLPipeline::rebuildPools() { + LLFastTimer t(FTM_REBUILD_POOLS); LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); assertInitialized(); @@ -6126,13 +6159,16 @@ void LLPipeline::resetVertexBuffers() { mResetVertexBuffers = true; } +static LLFastTimer::DeclareTimer FTM_RESET_VB("Reset VB"); + void LLPipeline::doResetVertexBuffers() { if (!mResetVertexBuffers) { return; } - + + LLFastTimer t(FTM_RESET_VB); mResetVertexBuffers = false; mCubeVB = NULL; @@ -6631,7 +6667,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length)); blur_constant /= 1000.f; //convert to meters for shader F32 magnification = focal_length/(subject_distance-focal_length); - + { //build diffuse+bloom+CoF mDeferredLight.bindTarget(); shader = &gDeferredCoFProgram; @@ -7238,7 +7274,7 @@ void LLPipeline::renderDeferredLighting() static const LLCachedControl RenderShadowBlurDistFactor("RenderShadowBlurDistFactor",.1f); static const LLCachedControl RenderDeferredAtmospheric("RenderDeferredAtmospheric",false); static const LLCachedControl RenderLocalLights("RenderLocalLights",false); - + { LLFastTimer ftm(FTM_RENDER_DEFERRED); @@ -7498,7 +7534,7 @@ void LLPipeline::renderDeferredLighting() } mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - + LLGLDepthTest depth(GL_TRUE, GL_FALSE); for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) { @@ -7544,7 +7580,7 @@ void LLPipeline::renderDeferredLighting() } sVisibleLightCount++; - + if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || camera->getOrigin().mV[0] < c[0] - s - 0.2f || camera->getOrigin().mV[1] > c[1] + s + 0.2f || @@ -8040,14 +8076,14 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gGL.setColorMask(true, false); mWaterRef.getViewport(gGLViewport); - + stop_glerror(); gGL.pushMatrix(); mat.set_scale(glh::vec3f(1,1,-1)); mat.set_translate(glh::vec3f(0,0,height*2.f)); - + glh::matrix4f current = glh_get_current_modelview(); mat = current * mat; @@ -8067,7 +8103,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) glCullFace(GL_FRONT); static LLCullResult ref_result; - + if (LLDrawPoolWater::sNeedsReflectionUpdate) { //initial sky pass (no user clip plane) @@ -8100,10 +8136,10 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) #endif if (detail < 3) { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); + clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); if (detail < 2) { - clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); + clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES); } } } @@ -8379,7 +8415,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gDeferredShadowAlphaMaskProgram.bind(); gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | @@ -8593,6 +8629,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector } +static LLFastTimer::DeclareTimer FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); void LLPipeline::generateSunShadow(LLCamera& camera) { @@ -8611,6 +8648,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) return; } + LLFastTimer t(FTM_GEN_SUN_SHADOW); + BOOL skip_avatar_update = FALSE; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) { @@ -9372,6 +9411,12 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu } } +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_SETUP("Impostor Setup"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_BACKGROUND("Impostor Background"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_ALLOCATE("Impostor Allocate"); +static LLFastTimer::DeclareTimer FTM_IMPOSTOR_RESIZE("Impostor Resize"); + void LLPipeline::generateImpostor(LLVOAvatar* avatar) { LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); @@ -9427,22 +9472,26 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) sImpostorRender = TRUE; LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); - markVisible(avatar->mDrawable, *viewer_camera); - LLVOAvatar::sUseImpostors = FALSE; - LLVOAvatar::attachment_map_t::iterator iter; - for (iter = avatar->mAttachmentPoints.begin(); - iter != avatar->mAttachmentPoints.end(); - ++iter) { - LLViewerJointAttachment *attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + LLFastTimer t(FTM_IMPOSTOR_MARK_VISIBLE); + markVisible(avatar->mDrawable, *viewer_camera); + LLVOAvatar::sUseImpostors = FALSE; + + LLVOAvatar::attachment_map_t::iterator iter; + for (iter = avatar->mAttachmentPoints.begin(); + iter != avatar->mAttachmentPoints.end(); + ++iter) { - if (LLViewerObject* attached_object = (*attachment_iter)) + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + if (LLViewerObject* attached_object = (*attachment_iter)) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } } } } @@ -9455,6 +9504,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) U32 resX = 0; { + LLFastTimer t(FTM_IMPOSTOR_SETUP); const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); @@ -9509,6 +9559,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (!avatar->mImpostor.isComplete()) { + LLFastTimer t(FTM_IMPOSTOR_ALLOCATE); avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); if (LLPipeline::sRenderDeferred) @@ -9523,6 +9574,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight()) { + LLFastTimer t(FTM_IMPOSTOR_RESIZE); avatar->mImpostor.resize(resX,resY,GL_RGBA); } @@ -9544,6 +9596,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) } { //create alpha mask based on depth buffer (grey out if muted) + LLFastTimer t(FTM_IMPOSTOR_BACKGROUND); if (LLPipeline::sRenderDeferred) { GLuint buff = GL_COLOR_ATTACHMENT0; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 6dd80b5b1..e5ed58ca1 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -168,7 +168,7 @@ public: void markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE); void markPartitionMove(LLDrawable* drawablep); void markMeshDirty(LLSpatialGroup* group); - + //get the object between start and end that's closest to start. LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, BOOL pick_transparent, From efb252206b9490e6685bc948564532ddd8ac9f3c Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Mon, 17 Sep 2012 22:22:02 -0400 Subject: [PATCH 017/138] Cached controls in cmdline chatbar --- indra/newview/chatbar_as_cmdline.cpp | 241 +++++++++++++++------------ 1 file changed, 136 insertions(+), 105 deletions(-) diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index a0051de59..5f416241c 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -210,7 +210,24 @@ bool stort_calls(const std::pair& left, const std::pair sAscentCmdLine(gSavedSettings, "AscentCmdLine"); + static LLCachedControl sAscentCmdLinePos(gSavedSettings, "AscentCmdLinePos"); + static LLCachedControl sAscentCmdLineDrawDistance(gSavedSettings, "AscentCmdLineDrawDistance"); + static LLCachedControl sAscentCmdTeleportToCam(gSavedSettings, "AscentCmdTeleportToCam"); + static LLCachedControl sAscentCmdLineKeyToName(gSavedSettings, "AscentCmdLineKeyToName"); + static LLCachedControl sAscentCmdLineOfferTp(gSavedSettings, "AscentCmdLineOfferTp"); + static LLCachedControl sAscentCmdLineGround(gSavedSettings, "AscentCmdLineGround"); + static LLCachedControl sAscentCmdLineHeight(gSavedSettings, "AscentCmdLineHeight"); + static LLCachedControl sAscentCmdLineTeleportHome(gSavedSettings, "AscentCmdLineTeleportHome"); + static LLCachedControl sAscentCmdLineRezPlatform(gSavedSettings, "AscentCmdLineRezPlatform"); + static LLCachedControl sAscentCmdLineMapTo(gSavedSettings, "AscentCmdLineMapTo"); + static LLCachedControl sAscentCmdLineMapToKeepPos(gSavedSettings, "AscentMapToKeepPos"); + static LLCachedControl sAscentCmdLineCalc(gSavedSettings, "AscentCmdLineCalc"); + static LLCachedControl sAscentCmdLineTP2(gSavedSettings, "AscentCmdLineTP2"); + static LLCachedControl sSinguCmdLineClearChat(gSavedSettings, "SinguCmdLineAway"); + static LLCachedControl sAscentCmdLineClearChat(gSavedSettings, "AscentCmdLineClearChat"); + + if(sAscentCmdLine) { std::istringstream i(revised_text); std::string command; @@ -218,7 +235,7 @@ bool cmd_line_chat(std::string revised_text, EChatType type) command = utf8str_tolower(command); if(command != "") { - if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLinePos"))) + if(command == utf8str_tolower(sAscentCmdLinePos)) { F32 x,y,z; if (i >> x) @@ -241,74 +258,73 @@ bool cmd_line_chat(std::string revised_text, EChatType type) } } } - else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineDrawDistance"))) + else if(command == utf8str_tolower(sAscentCmdLineDrawDistance)) { - int drawDist; - if(i >> drawDist) - { - gSavedSettings.setF32("RenderFarClip", drawDist); - gAgentCamera.mDrawDistance=drawDist; - char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ - snprintf(buffer,sizeof(buffer),"Draw distance set to: %dm",drawDist); + int drawDist; + if(i >> drawDist) + { + gSavedSettings.setF32("RenderFarClip", drawDist); + gAgentCamera.mDrawDistance=drawDist; + char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ + snprintf(buffer,sizeof(buffer),"Draw distance set to: %dm",drawDist); cmdline_printchat(std::string(buffer)); return false; - } + } } - else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdTeleportToCam"))) - { + else if(command == utf8str_tolower(sAscentCmdTeleportToCam)) + { gAgent.teleportViaLocation(gAgentCamera.getCameraPositionGlobal()); return false; - } - else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineKeyToName"))) - { - LLUUID targetKey; - if(i >> targetKey) - { - std::string object_name; - gCacheName->getFullName(targetKey, object_name); - char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ - snprintf(buffer,sizeof(buffer),"%s: (%s)",targetKey.asString().c_str(), object_name.c_str()); + } + else if(command == utf8str_tolower(sAscentCmdLineKeyToName)) + { + LLUUID targetKey; + if(i >> targetKey) + { + std::string object_name; + gCacheName->getFullName(targetKey, object_name); + char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ + snprintf(buffer,sizeof(buffer),"%s: (%s)",targetKey.asString().c_str(), object_name.c_str()); cmdline_printchat(std::string(buffer)); - } + } return false; - } - else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineOfferTp"))) - { - std::string avatarKey; + } + else if(command == utf8str_tolower(sAscentCmdLineOfferTp)) + { + std::string avatarKey; // llinfos << "CMD DEBUG 0 " << command << " " << avatarName << llendl; - if(i >> avatarKey) - { + if(i >> avatarKey) + { // llinfos << "CMD DEBUG 0 afterif " << command << " " << avatarName << llendl; - LLUUID tempUUID; - if(LLUUID::parseUUID(avatarKey, &tempUUID)) - { - char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ - LLDynamicArray ids; - ids.push_back(tempUUID); - std::string tpMsg="Join me!"; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_StartLure); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Info); - msg->addU8Fast(_PREHASH_LureType, (U8)0); + LLUUID tempUUID; + if(LLUUID::parseUUID(avatarKey, &tempUUID)) + { + char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ + LLDynamicArray ids; + ids.push_back(tempUUID); + std::string tpMsg="Join me!"; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_StartLure); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Info); + msg->addU8Fast(_PREHASH_LureType, (U8)0); - msg->addStringFast(_PREHASH_Message, tpMsg); - for(LLDynamicArray::iterator itr = ids.begin(); itr != ids.end(); ++itr) - { - msg->nextBlockFast(_PREHASH_TargetData); - msg->addUUIDFast(_PREHASH_TargetID, *itr); - } - gAgent.sendReliableMessage(); - snprintf(buffer,sizeof(buffer),"Offered TP to key %s",tempUUID.asString().c_str()); + msg->addStringFast(_PREHASH_Message, tpMsg); + for(LLDynamicArray::iterator itr = ids.begin(); itr != ids.end(); ++itr) + { + msg->nextBlockFast(_PREHASH_TargetData); + msg->addUUIDFast(_PREHASH_TargetID, *itr); + } + gAgent.sendReliableMessage(); + snprintf(buffer,sizeof(buffer),"Offered TP to key %s",tempUUID.asString().c_str()); cmdline_printchat(std::string(buffer)); return false; - } - } - } - - else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineGround"))) + } + } + } + else if(command == utf8str_tolower(sAscentCmdLineGround)) { LLVector3 agentPos = gAgent.getPositionAgent(); U64 agentRegion = gAgent.getRegion()->getHandle(); @@ -317,7 +333,8 @@ bool cmd_line_chat(std::string revised_text, EChatType type) pos_global += LLVector3d((F64)targetPos.mV[0],(F64)targetPos.mV[1],(F64)targetPos.mV[2]); gAgent.teleportViaLocation(pos_global); return false; - }else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineHeight"))) + } + else if(command == utf8str_tolower(sAscentCmdLineHeight)) { F32 z; if(i >> z) @@ -330,17 +347,20 @@ bool cmd_line_chat(std::string revised_text, EChatType type) gAgent.teleportViaLocation(pos_global); return false; } - }else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineTeleportHome"))) + } + else if(command == utf8str_tolower(sAscentCmdLineTeleportHome)) { gAgent.teleportHome(); return false; - }else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineRezPlatform"))) - { + } + else if(command == utf8str_tolower(sAscentCmdLineRezPlatform)) + { F32 width; if (i >> width) cmdline_rezplat(false, width); else cmdline_rezplat(); return false; - }else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineMapTo"))) + } + else if(command == utf8str_tolower(sAscentCmdLineMapTo)) { if (revised_text.length() > command.length() + 1) //Typing this command with no argument was causing a crash. -Madgeek { @@ -351,7 +371,7 @@ bool cmd_line_chat(std::string revised_text, EChatType type) std::string region_name = LLWeb::escapeURL(revised_text.substr(command.length()+1)); std::string url; - if(!gSavedSettings.getBOOL("AscentMapToKeepPos")) + if(!sAscentCmdLineMapToKeepPos) { agent_x = 128; agent_y = 128; @@ -362,7 +382,8 @@ bool cmd_line_chat(std::string revised_text, EChatType type) LLURLDispatcher::dispatch(url, NULL, true); } return false; - }else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineCalc")))//Cryogenic Blitz + } + else if(command == utf8str_tolower(sAscentCmdLineCalc))//Cryogenic Blitz { bool success; F32 result = 0.f; @@ -391,7 +412,8 @@ bool cmd_line_chat(std::string revised_text, EChatType type) cmdline_printchat(out); return false; } - }else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineTP2"))) + } + else if(command == utf8str_tolower(sAscentCmdLineTP2)) { if (revised_text.length() > command.length() + 1) //Typing this command with no argument was causing a crash. -Madgeek { @@ -399,11 +421,13 @@ bool cmd_line_chat(std::string revised_text, EChatType type) cmdline_tp2name(name); } return false; - }else if(command == utf8str_tolower(gSavedSettings.getString("SinguCmdLineAway"))) + } + else if(command == utf8str_tolower(sSinguCmdLineClearChat)) { handle_fake_away_status(NULL); return false; - }else if(command == "typingstop") + } + else if(command == "typingstop") { std::string text; if(i >> text) @@ -411,7 +435,7 @@ bool cmd_line_chat(std::string revised_text, EChatType type) gChatBar->sendChatFromViewer(text, CHAT_TYPE_STOP, FALSE); } } - else if(command == utf8str_tolower(gSavedSettings.getString("AscentCmdLineClearChat"))) + else if(command == utf8str_tolower(sAscentCmdLineClearChat)) { LLFloaterChat* chat = LLFloaterChat::getInstance(LLSD()); if(chat) @@ -422,7 +446,8 @@ bool cmd_line_chat(std::string revised_text, EChatType type) history_editor_with_mute->clear(); return false; } - }else if(command == "invrepair") + } + else if(command == "invrepair") { invrepair(); } @@ -513,55 +538,61 @@ void cmdline_tp2name(std::string target) void cmdline_rezplat(bool use_saved_value, F32 visual_radius) //cmdline_rezplat() will still work... just will use the saved value { - LLVector3 agentPos = gAgent.getPositionAgent()+(gAgent.getVelocity()*(F32)0.333); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectAdd); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU8Fast(_PREHASH_PCode, LL_PCODE_VOLUME); - msg->addU8Fast(_PREHASH_Material, LL_MCODE_METAL); + LLVector3 agentPos = gAgent.getPositionAgent()+(gAgent.getVelocity()*(F32)0.333); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ObjectAdd); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU8Fast(_PREHASH_PCode, LL_PCODE_VOLUME); + msg->addU8Fast(_PREHASH_Material, LL_MCODE_METAL); - if(agentPos.mV[2] > 4096.0)msg->addU32Fast(_PREHASH_AddFlags, FLAGS_CREATE_SELECTED); - else msg->addU32Fast(_PREHASH_AddFlags, 0); + if(agentPos.mV[2] > 4096.0) + msg->addU32Fast(_PREHASH_AddFlags, FLAGS_CREATE_SELECTED); + else + msg->addU32Fast(_PREHASH_AddFlags, 0); - LLVolumeParams volume_params; + LLVolumeParams volume_params; - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE_33 ); - volume_params.setRatio ( 2, 2 ); - volume_params.setShear ( 0, 0 ); - volume_params.setTaper(2.0f,2.0f); - volume_params.setTaperX(0.f); - volume_params.setTaperY(0.f); + volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE_33 ); + volume_params.setRatio( 2, 2 ); + volume_params.setShear( 0, 0 ); + volume_params.setTaper(2.0f,2.0f); + volume_params.setTaperX(0.f); + volume_params.setTaperY(0.f); - LLVolumeMessage::packVolumeParams(&volume_params, msg); - LLVector3 rezpos = agentPos - LLVector3(0.0f,0.0f,2.5f); - LLQuaternion rotation; - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + LLVolumeMessage::packVolumeParams(&volume_params, msg); + LLVector3 rezpos = agentPos - LLVector3(0.0f,0.0f,2.5f); + LLQuaternion rotation; + rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); + + if (use_saved_value) + { + visual_radius = gSavedSettings.getF32("AscentPlatformSize"); + } - if (use_saved_value) visual_radius = gSavedSettings.getF32("AscentPlatformSize"); F32 realsize = visual_radius / 3.0f; if (realsize < 0.01f) realsize = 0.01f; else if (realsize > 10.0f) realsize = 10.0f; - msg->addVector3Fast(_PREHASH_Scale, LLVector3(0.01f,realsize,realsize) ); - msg->addQuatFast(_PREHASH_Rotation, rotation ); - msg->addVector3Fast(_PREHASH_RayStart, rezpos ); - msg->addVector3Fast(_PREHASH_RayEnd, rezpos ); - msg->addU8Fast(_PREHASH_BypassRaycast, (U8)1 ); - msg->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); - msg->addU8Fast(_PREHASH_State, 0); - msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null ); - msg->sendReliable(gAgent.getRegionHost()); + msg->addVector3Fast(_PREHASH_Scale, LLVector3(0.01f,realsize,realsize) ); + msg->addQuatFast(_PREHASH_Rotation, rotation ); + msg->addVector3Fast(_PREHASH_RayStart, rezpos ); + msg->addVector3Fast(_PREHASH_RayEnd, rezpos ); + msg->addU8Fast(_PREHASH_BypassRaycast, (U8)1 ); + msg->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); + msg->addU8Fast(_PREHASH_State, 0); + msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null ); + msg->sendReliable(gAgent.getRegionHost()); } void cmdline_printchat(std::string message) { - LLChat chat; - chat.mText = message; + LLChat chat; + chat.mText = message; chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChat(chat, FALSE, FALSE); + LLFloaterChat::addChat(chat, FALSE, FALSE); } From daa9466b7a8cd0aa1a0abb04e4f2e691126b43a3 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Mon, 17 Sep 2012 22:22:28 -0400 Subject: [PATCH 018/138] Spelling fixin a comment :D --- indra/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 08daa9681..3f9209da9 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -18,7 +18,7 @@ cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR) cmake_policy(SET CMP0003 OLD) set(ROOT_PROJECT_NAME "Singularity" CACHE STRING - "The root project/makefile/solution name. Defaults to SecondLife.") + "The root project/makefile/solution name. Defaults to Singularity.") project(${ROOT_PROJECT_NAME}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") From a09f7d274fd6a378f90d9de430b051fce901e4a0 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Mon, 17 Sep 2012 22:23:57 -0400 Subject: [PATCH 019/138] Fixed a bit of cmake derpyness --- indra/newview/CMakeLists.txt | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 884164934..494a3d3bb 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -10,9 +10,10 @@ include(ELFIO) if(FMODEX) include(FMODEX) set(FMOD OFF) -else(FMODEX) - include(FMOD) endif(FMODEX) +if(FMOD) + include(FMOD) +endif(FMOD) include(OPENAL) include(FindOpenGL) include(Hunspell) @@ -1368,13 +1369,10 @@ if (FMOD OR FMODEX) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD") endif (FMOD) - if (DARWIN) - if(FMOD) + if (DARWIN AND FMOD) set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp) add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES}) - if (FMOD) - set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY}) - endif (FMOD) + set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY}) set_target_properties( fmodwrapper PROPERTIES @@ -1384,11 +1382,7 @@ if (FMOD OR FMODEX) ) set(FMODWRAPPER_LIBRARY fmodwrapper) target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES}) - endif(FMOD) - if(FMODEX) - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) - endif(FMODEX) - else (DARWIN) + else (DARWIN AND FMOD) # fmodwrapper unnecessary on linux or windows, for fmod and fmodex if (FMODEX) set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) @@ -1396,7 +1390,7 @@ if (FMOD OR FMODEX) if (FMOD) set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY}) endif (FMOD) - endif (DARWIN) + endif (DARWIN AND FMOD) endif (FMOD OR FMODEX) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") @@ -1432,9 +1426,9 @@ set(PACKAGE ${PACKAGE_DEFAULT} CACHE BOOL if (WINDOWS) if(MSVC10) set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map") - else() + else(MSVC10) set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map") - endif() + endif(MSVC10) if (FMOD) if(MANIFEST_LIBRARIES) From 90a10b3508adc463f1002c326bc9f9968517ab7f Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Mon, 17 Sep 2012 22:40:30 -0400 Subject: [PATCH 020/138] Removed packaged dbghelp.dll --- indra/cmake/ViewerMiscLibs.cmake | 5 ----- install.xml | 19 ------------------- 2 files changed, 24 deletions(-) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index e52492c38..275b840a0 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -19,8 +19,3 @@ else (NOT STANDALONE) endif(LINUX AND ${ARCH} STREQUAL "x86_64") set(STANDALONE ON) endif(NOT STANDALONE) - -if (WINDOWS) - use_prebuilt_binary(dbghelp) -endif (WINDOWS) - diff --git a/install.xml b/install.xml index 9a994bdda..8caea2ba4 100644 --- a/install.xml +++ b/install.xml @@ -300,25 +300,6 @@ - dbghelp - - copyright - Copyright Microsoft Corporation - description - dbghelp: Debug helper from Microsoft Debugging Tools For Windows - license - MSDTW - packages - - windows - - md5sum - b7563064037e032143ca2d610aae5153 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbghelp-6.11.1.404-windows-20090520.tar.bz2 - - - dbusglib copyright From d7da5153f362e09e345dbd240bcc2897f602b6de Mon Sep 17 00:00:00 2001 From: Lirusaito Date: Tue, 18 Sep 2012 10:06:21 -0400 Subject: [PATCH 021/138] Fixed up the Post-Process floater~ Vertical tabs, as requested by Shyotl --- .../xui/en-us/floater_post_process.xml | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/indra/newview/skins/default/xui/en-us/floater_post_process.xml b/indra/newview/skins/default/xui/en-us/floater_post_process.xml index 12e3d8ad6..771f47b0a 100644 --- a/indra/newview/skins/default/xui/en-us/floater_post_process.xml +++ b/indra/newview/skins/default/xui/en-us/floater_post_process.xml @@ -3,13 +3,13 @@ can_resize="false" height="400" left="50" min_height="400" min_width="300" mouse_opaque="true" name="Post-Process Floater" title="Post-Process Settings" width="400"> - - Gamma - @@ -30,7 +30,7 @@ width="355"> Brightness - @@ -41,7 +41,7 @@ width="355"> Saturation - @@ -52,7 +52,7 @@ width="355"> Contrast - Contrast Base Colors - - Passes to apply - - Light Amplification Multiple - Noise Size - Noise Strength - @@ -149,7 +149,7 @@ - Layer Count - - Luminosity Extraction - Bloom Size - Bloom Strength - - - -