diff options
| author | Nat Goodspeed <nat@lindenlab.com> | 2015-07-09 21:44:02 -0400 | 
|---|---|---|
| committer | Nat Goodspeed <nat@lindenlab.com> | 2015-07-09 21:44:02 -0400 | 
| commit | 768ef450678a93496fb69012efaa15c915969c47 (patch) | |
| tree | 023ead1927667d4fb11cb56dceadc33694d35937 | |
| parent | 657944cda7228ba824239d94b270160ac0460934 (diff) | |
| parent | 33007699cc701baf0c312ff669e659d874f3ae2f (diff) | |
Merge suppress http_proxy in INTEGRATION_TEST_llcorehttp
190 files changed, 11389 insertions, 10703 deletions
diff --git a/BuildParams b/BuildParams index aeea3b1246..7aff447dda 100755 --- a/BuildParams +++ b/BuildParams @@ -4,7 +4,7 @@  #  https://wiki.secondlife.com/wiki/Automated_Build_System -# Global setting for now... +# Global setting for now....  Darwin.symbolfiles = "newview/Release/secondlife-symbols-darwin.tar.bz2"  CYGWIN.symbolfiles = "newview/Release/secondlife-symbols-windows.tar.bz2"  Linux.symbolfiles = "newview/secondlife-symbols-linux.tar.bz2" diff --git a/autobuild.xml b/autobuild.xml index 52d750f64d..ff8bde0ea7 100755 --- a/autobuild.xml +++ b/autobuild.xml @@ -266,9 +266,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>d1c5125650a339a5209f429c70f4d395</string> +              <string>89db4a1aa22599cf377ae49630b7b5b1</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/curl_3p-update-curl/rev/297172/arch/Darwin/installer/curl-7.38.0.297172-darwin-297172.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/curl_3p-update-curl/rev/301717/arch/Darwin/installer/curl-7.42.1.301717-darwin-301717.tar.bz2</string>              </map>              <key>name</key>              <string>darwin</string> @@ -278,9 +278,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>ee6c089ee193e551040d610befc5d1c1</string> +              <string>de9e0c855ff6ee30c9e027a70bbef032</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/curl_3p-update-curl/rev/297172/arch/Linux/installer/curl-7.38.0.297172-linux-297172.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/curl_3p-update-curl/rev/301717/arch/Linux/installer/curl-7.42.1.301717-linux-301717.tar.bz2</string>              </map>              <key>name</key>              <string>linux</string> @@ -290,16 +290,16 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>fdeca7cbc074a88d2701d74a31d21bd8</string> +              <string>98d15713de8c439b7f54cc14f2df07ac</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/curl_3p-update-curl/rev/297172/arch/CYGWIN/installer/curl-7.38.0.297172-windows-297172.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/curl_3p-update-curl/rev/301717/arch/CYGWIN/installer/curl-7.42.1.301717-windows-301717.tar.bz2</string>              </map>              <key>name</key>              <string>windows</string>            </map>          </map>          <key>version</key> -        <string>7.38.0.297172</string> +        <string>7.42.1.301717</string>        </map>        <key>db</key>        <map> diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt index c0fc1b2be0..81d14c695b 100755 --- a/indra/linux_crash_logger/CMakeLists.txt +++ b/indra/linux_crash_logger/CMakeLists.txt @@ -4,6 +4,7 @@ project(linux_crash_logger)  include(00-Common)  include(GLH) +include(LLCoreHttp)  include(LLCommon)  include(LLCrashLogger)  include(LLMath) @@ -13,8 +14,10 @@ include(LLXML)  include(Linking)  include(UI)  include(FreeType) +include(Boost)  include_directories( +    ${LLCOREHTTP_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS}      ${LLCRASHLOGGER_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS} @@ -53,6 +56,10 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")  add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES}) +# llcommon uses `clock_gettime' which is provided by librt on linux. +set(LIBRT_LIBRARY rt) + +  target_link_libraries(linux-crash-logger      ${LLCRASHLOGGER_LIBRARIES}      ${LLVFS_LIBRARIES} @@ -60,10 +67,14 @@ target_link_libraries(linux-crash-logger      ${LLMESSAGE_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${LLCOMMON_LIBRARIES} +    ${BOOST_CONTEXT_LIBRARY} +    ${BOOST_COROUTINE_LIBRARY}      ${UI_LIBRARIES}      ${DB_LIBRARIES}      ${FREETYPE_LIBRARIES} +    ${LIBRT_LIBRARY}      )  add_custom_target(linux-crash-logger-target ALL diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 1459b9ada2..9757679ce1 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -8,6 +8,7 @@ include(LLCommon)  include(Linking)  include(Boost)  include(LLSharedLibs) +include(JsonCpp)  include(GoogleBreakpad)  include(GooglePerfTools)  include(Copy3rdPartyLibs) @@ -17,6 +18,7 @@ include(URIPARSER)  include_directories(      ${EXPAT_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS} +    ${JSONCPP_INCLUDE_DIR}      ${ZLIB_INCLUDE_DIRS}      ${BREAKPAD_INCLUDE_DIRECTORIES}      ${URIPARSER_INCLUDE_DIRS} @@ -85,6 +87,7 @@ set(llcommon_SOURCE_FILES      llrefcount.cpp      llrun.cpp      llsd.cpp +    llsdjson.cpp      llsdparam.cpp      llsdserialize.cpp      llsdserialize_xml.cpp @@ -193,6 +196,7 @@ set(llcommon_HEADER_FILES      llrefcount.h      llsafehandle.h      llsd.h +    llsdjson.h      llsdparam.h      llsdserialize.h      llsdserialize_xml.h @@ -260,6 +264,7 @@ target_link_libraries(      ${APRUTIL_LIBRARIES}      ${APR_LIBRARIES}      ${EXPAT_LIBRARIES} +    ${JSONCPP_LIBRARIES}      ${ZLIB_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${BOOST_PROGRAM_OPTIONS_LIBRARY} diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index 5cfcdab41c..e5a913a6a9 100755 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -51,6 +51,7 @@  #include <cstdlib>  #include <ctime>  #include <iosfwd> +#include <memory>  // Linden only libs in alpha-order other than stdtypes.h  // *NOTE: Please keep includes here to a minimum, see above. diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index baaddcaed1..957fe034e1 100755 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -34,11 +34,65 @@  // std headers  // external library headers  #include <boost/bind.hpp> +#include <boost/thread/tss.hpp>  // other Linden headers  #include "llevents.h"  #include "llerror.h"  #include "stringize.h" +namespace { + +// do nothing, when we need nothing done +void no_cleanup(LLCoros::coro::self*) {} + +// When the dcoroutine library calls a top-level callable, it implicitly +// passes coro::self& as the first parameter. All our consumer code used to +// explicitly pass coro::self& down through all levels of call stack, because +// at the leaf level we need it for context-switching. But since coroutines +// are based on cooperative switching, we can cause the top-level entry point +// to stash a static pointer to the currently-running coroutine, and manage it +// appropriately as we switch out and back in. That eliminates the need to +// pass it as an explicit parameter down through every level, which is +// unfortunately viral in nature. Finding it implicitly rather than explicitly +// allows minor maintenance in which a leaf-level function adds a new async +// I/O call that suspends the calling coroutine, WITHOUT having to propagate +// coro::self& through every function signature down to that point -- and of +// course through every other caller of every such function. +// We use a boost::thread_specific_ptr because each thread potentially has its +// own distinct pool of coroutines. +// This thread_specific_ptr does NOT own the 'self' object! It merely +// identifies it. For this reason we instantiate it with a no-op cleanup +// function. +static boost::thread_specific_ptr<LLCoros::coro::self> +sCurrentSelf(no_cleanup); + +} // anonymous + +//static +LLCoros::coro::self& llcoro::get_self() +{ +    LLCoros::coro::self* current_self = sCurrentSelf.get(); +    if (! current_self) +    { +        LL_ERRS("LLCoros") << "Calling get_self() from non-coroutine context!" << LL_ENDL; +    } +    return *current_self; +} + +llcoro::Suspending::Suspending(): +    mSuspended(sCurrentSelf.get()) +{ +    // For the duration of our time away from this coroutine, sCurrentSelf +    // must NOT refer to this coroutine. +    sCurrentSelf.reset(); +} + +llcoro::Suspending::~Suspending() +{ +    // Okay, we're back, reinstate previous value of sCurrentSelf. +    sCurrentSelf.reset(mSuspended); +} +  LLCoros::LLCoros():      // MAINT-2724: default coroutine stack size too small on Windows.      // Previously we used @@ -60,7 +114,7 @@ bool LLCoros::cleanup(const LLSD&)          // since last tick?          if (mi->second->exited())          { -			   LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL; +            LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;              // The erase() call will invalidate its passed iterator value --              // so increment mi FIRST -- but pass its original value to              // erase(). This is what postincrement is all about. @@ -94,7 +148,7 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const      {          if (mCoros.find(name) == mCoros.end())          { -			   LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL; +            LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;              return name;          }      } @@ -114,10 +168,10 @@ bool LLCoros::kill(const std::string& name)      return true;  } -std::string LLCoros::getNameByID(const void* self_id) const +std::string LLCoros::getName() const  { -    // Walk the existing coroutines, looking for one from which the 'self_id' -    // passed to us comes. +    // Walk the existing coroutines, looking for the current one. +    void* self_id = llcoro::get_self().get_id();      for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)      {          namespace coro_private = boost::dcoroutines::detail; @@ -136,10 +190,24 @@ void LLCoros::setStackSize(S32 stacksize)      mStackSize = stacksize;  } +namespace { + +// Top-level wrapper around caller's coroutine callable. This function accepts +// the coroutine library's implicit coro::self& parameter and sets sCurrentSelf +// but does not pass it down to the caller's callable. +void toplevel(LLCoros::coro::self& self, const LLCoros::callable_t& callable) +{ +    sCurrentSelf.reset(&self); +    callable(); +    sCurrentSelf.reset(); +} + +} // anonymous +  /*****************************************************************************  *   MUST BE LAST  *****************************************************************************/ -// Turn off MSVC optimizations for just LLCoros::launchImpl() -- see +// Turn off MSVC optimizations for just LLCoros::launch() -- see  // DEV-32777. But MSVC doesn't support push/pop for optimization flags as it  // does for warning suppression, and we really don't want to force  // optimization ON for other code even in Debug or RelWithDebInfo builds. @@ -150,9 +218,13 @@ void LLCoros::setStackSize(S32 stacksize)  #pragma optimize("", off)  #endif // LL_MSVC -std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro) +std::string LLCoros::launch(const std::string& prefix, const callable_t& callable)  {      std::string name(generateDistinctName(prefix)); +    // Wrap the caller's callable in our toplevel() function so we can manage +    // sCurrentSelf appropriately at startup and shutdown of each coroutine. +    coro* newCoro = new coro(boost::bind(toplevel, _1, callable), mStackSize); +    // Store it in our pointer map      mCoros.insert(name, newCoro);      /* Run the coroutine until its first wait, then return here */      (*newCoro)(std::nothrow); diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 01ee11da1a..e478600f00 100755 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -32,10 +32,8 @@  #include <boost/dcoroutine/coroutine.hpp>  #include "llsingleton.h"  #include <boost/ptr_container/ptr_map.hpp> +#include <boost/function.hpp>  #include <string> -#include <boost/preprocessor/repetition/enum_params.hpp> -#include <boost/preprocessor/repetition/enum_binary_params.hpp> -#include <boost/preprocessor/iteration/local.hpp>  #include <stdexcept>  /** @@ -80,8 +78,8 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>  public:      /// Canonical boost::dcoroutines::coroutine signature we use      typedef boost::dcoroutines::coroutine<void()> coro; -    /// Canonical 'self' type -    typedef coro::self self; +    /// Canonical callable type +    typedef boost::function<void()> callable_t;      /**       * Create and start running a new coroutine with specified name. The name @@ -94,39 +92,33 @@ public:       * {       * public:       *     ... -     *     // Do NOT NOT NOT accept reference params other than 'self'! +     *     // Do NOT NOT NOT accept reference params!       *     // Pass by value only! -     *     void myCoroutineMethod(LLCoros::self& self, std::string, LLSD); +     *     void myCoroutineMethod(std::string, LLSD);       *     ...       * };       * ...       * std::string name = LLCoros::instance().launch( -     *    "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1, +     *    "mycoro", boost::bind(&MyClass::myCoroutineMethod, this,       *                          "somestring", LLSD(17));       * @endcode       * -     * Your function/method must accept LLCoros::self& as its first parameter. -     * It can accept any other parameters you want -- but ONLY BY VALUE! -     * Other reference parameters are a BAD IDEA! You Have Been Warned. See +     * Your function/method can accept any parameters you want -- but ONLY BY +     * VALUE! Reference parameters are a BAD IDEA! You Have Been Warned. See       * DEV-32777 comments for an explanation.       * -     * Pass a callable that accepts the single LLCoros::self& parameter. It -     * may work to pass a free function whose only parameter is 'self'; for -     * all other cases use boost::bind(). Of course, for a non-static class -     * method, the first parameter must be the class instance. Use the -     * placeholder _1 for the 'self' parameter. Any other parameters should be -     * passed via the bind() expression. +     * Pass a nullary callable. It works to directly pass a nullary free +     * function (or static method); for all other cases use boost::bind(). Of +     * course, for a non-static class method, the first parameter must be the +     * class instance. Any other parameters should be passed via the bind() +     * expression.       *       * launch() tweaks the suggested name so it won't collide with any       * existing coroutine instance, creates the coroutine instance, registers       * it with the tweaked name and runs it until its first wait. At that       * point it returns the tweaked name.       */ -    template <typename CALLABLE> -    std::string launch(const std::string& prefix, const CALLABLE& callable) -    { -        return launchImpl(prefix, new coro(callable, mStackSize)); -    } +    std::string launch(const std::string& prefix, const callable_t& callable);      /**       * Abort a running coroutine by name. Normally, when a coroutine either @@ -138,27 +130,19 @@ public:      bool kill(const std::string& name);      /** -     * From within a coroutine, pass its @c self object to look up the -     * (tweaked) name string by which this coroutine is registered. Returns -     * the empty string if not found (e.g. if the coroutine was launched by -     * hand rather than using LLCoros::launch()). +     * From within a coroutine, look up the (tweaked) name string by which +     * this coroutine is registered. Returns the empty string if not found +     * (e.g. if the coroutine was launched by hand rather than using +     * LLCoros::launch()).       */ -    template <typename COROUTINE_SELF> -    std::string getName(const COROUTINE_SELF& self) const -    { -        return getNameByID(self.get_id()); -    } - -    /// getName() by self.get_id() -    std::string getNameByID(const void* self_id) const; +    std::string getName() const;      /// for delayed initialization      void setStackSize(S32 stacksize);  private: -    friend class LLSingleton<LLCoros>;      LLCoros(); -    std::string launchImpl(const std::string& prefix, coro* newCoro); +    friend class LLSingleton<LLCoros>;      std::string generateDistinctName(const std::string& prefix) const;      bool cleanup(const LLSD&); @@ -167,4 +151,24 @@ private:      CoroMap mCoros;  }; +namespace llcoro +{ + +/// get the current coro::self& for those who really really care +LLCoros::coro::self& get_self(); + +/// Instantiate one of these in a block surrounding any leaf point when +/// control literally switches away from this coroutine. +class Suspending +{ +public: +    Suspending(); +    ~Suspending(); + +private: +    LLCoros::coro::self* mSuspended; +}; + +} // namespace llcoro +  #endif /* ! defined(LL_LLCOROS_H) */ diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 63040e1772..b1b5e9be7d 100755 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -354,6 +354,7 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;  #define LL_WARNS(...)	lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__)  #define LL_ERRS(...)	lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__)  // alternative to llassert_always that prints explanatory message +#define LL_WARNS_IF(exp, ...)	if (exp) LL_WARNS(##__VA_ARGS__) << "(" #exp ")"  #define LL_ERRS_IF(exp, ...)	if (exp) LL_ERRS(##__VA_ARGS__) << "(" #exp ")"  // Only print the log message once (good for warnings or infos that would otherwise diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 81cc33fbba..ad02e139b8 100755 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -34,38 +34,63 @@  #include <map>  // std headers  // external library headers +#include <boost/dcoroutine/coroutine.hpp> +#include <boost/dcoroutine/future.hpp>  // other Linden headers  #include "llsdserialize.h"  #include "llerror.h"  #include "llcoros.h" -std::string LLEventDetail::listenerNameForCoroImpl(const void* self_id) +namespace  { -    // First, if this coroutine was launched by LLCoros::launch(), find that name. -    std::string name(LLCoros::instance().getNameByID(self_id)); + +/** + * waitForEventOn() permits a coroutine to temporarily listen on an + * LLEventPump any number of times. We don't really want to have to ask + * the caller to label each such call with a distinct string; the whole + * point of waitForEventOn() is to present a nice sequential interface to + * the underlying LLEventPump-with-named-listeners machinery. So we'll use + * LLEventPump::inventName() to generate a distinct name for each + * temporary listener. On the other hand, because a given coroutine might + * call waitForEventOn() any number of times, we don't really want to + * consume an arbitrary number of generated inventName()s: that namespace, + * though large, is nonetheless finite. So we memoize an invented name for + * each distinct coroutine instance. + */ +std::string listenerNameForCoro() +{ +    // If this coroutine was launched by LLCoros::launch(), find that name. +    std::string name(LLCoros::instance().getName());      if (! name.empty())      {          return name;      } -    // Apparently this coroutine wasn't launched by LLCoros::launch(). Check -    // whether we have a memo for this self_id. -    typedef std::map<const void*, std::string> MapType; -    static MapType memo; -    MapType::const_iterator found = memo.find(self_id); -    if (found != memo.end()) -    { -        // this coroutine instance has called us before, reuse same name -        return found->second; -    }      // this is the first time we've been called for this coroutine instance      name = LLEventPump::inventName("coro"); -    memo[self_id] = name; -    LL_INFOS("LLEventCoro") << "listenerNameForCoroImpl(" << self_id << "): inventing coro name '" +    LL_INFOS("LLEventCoro") << "listenerNameForCoro(): inventing coro name '"                              << name << "'" << LL_ENDL;      return name;  } -void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value) +/** + * Implement behavior described for postAndWait()'s @a replyPumpNamePath + * parameter: + * + * * If <tt>path.isUndefined()</tt>, do nothing. + * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value + *   into <tt>dest[path.asString()]</tt>. + * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a + *   value into <tt>dest[path.asInteger()]</tt>. + * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step + *   down through the structure of @a dest. The last array entry in @a + *   path specifies the entry in the lowest-level structure in @a dest + *   into which to store @a value. + * + * @note + * In the degenerate case in which @a path is an empty array, @a dest will + * @em become @a value rather than @em containing it. + */ +void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)  {      if (rawPath.isUndefined())      { @@ -118,6 +143,155 @@ void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD&      *pdest = value;  } +} // anonymous + +void llcoro::yield() +{ +    // By viewer convention, we post an event on the "mainloop" LLEventPump +    // each iteration of the main event-handling loop. So waiting for a single +    // event on "mainloop" gives us a one-frame yield. +    waitForEventOn("mainloop"); +} + +LLSD llcoro::postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, +                         const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath) +{ +    // declare the future +    boost::dcoroutines::future<LLSD> future(llcoro::get_self()); +    // make a callback that will assign a value to the future, and listen on +    // the specified LLEventPump with that callback +    std::string listenerName(listenerNameForCoro()); +    LLTempBoundListener connection( +        replyPump.getPump().listen(listenerName, +                                   voidlistener(boost::dcoroutines::make_callback(future)))); +    // skip the "post" part if requestPump is default-constructed +    if (requestPump) +    { +        // If replyPumpNamePath is non-empty, store the replyPump name in the +        // request event. +        LLSD modevent(event); +        storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName()); +        LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName +                                 << " posting to " << requestPump.getPump().getName() +                                 << LL_ENDL; + +        // *NOTE:Mani - Removed because modevent could contain user's hashed passwd. +        //                         << ": " << modevent << LL_ENDL; +        requestPump.getPump().post(modevent); +    } +    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName +                             << " about to wait on LLEventPump " << replyPump.getPump().getName() +                             << LL_ENDL; +    // trying to dereference ("resolve") the future makes us wait for it +    LLSD value; +    { +        // instantiate Suspending to manage the "current" coroutine +        llcoro::Suspending suspended; +        value = *future; +    } // destroy Suspending as soon as we're back +    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName +                             << " resuming with " << value << LL_ENDL; +    // returning should disconnect the connection +    return value; +} + +namespace +{ + +/** + * This helper is specifically for the two-pump version of waitForEventOn(). + * We use a single future object, but we want to listen on two pumps with it. + * Since we must still adapt from (the callable constructed by) + * boost::dcoroutines::make_callback() (void return) to provide an event + * listener (bool return), we've adapted VoidListener for the purpose. The + * basic idea is that we construct a distinct instance of WaitForEventOnHelper + * -- binding different instance data -- for each of the pumps. Then, when a + * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine + * that LLSD with its discriminator to feed the future object. + */ +template <typename LISTENER> +class WaitForEventOnHelper +{ +public: +    WaitForEventOnHelper(const LISTENER& listener, int discriminator): +        mListener(listener), +        mDiscrim(discriminator) +    {} +    // this signature is required for an LLEventPump listener +    bool operator()(const LLSD& event) +    { +        // our future object is defined to accept LLEventWithID +        mListener(LLEventWithID(event, mDiscrim)); +        // don't swallow the event, let other listeners see it +        return false; +    } +private: +    LISTENER mListener; +    const int mDiscrim; +}; + +/// WaitForEventOnHelper type-inference helper +template <typename LISTENER> +WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator) +{ +    return WaitForEventOnHelper<LISTENER>(listener, discriminator); +} + +} // anonymous + +namespace llcoro +{ + +LLEventWithID postAndWait2(const LLSD& event, +                           const LLEventPumpOrPumpName& requestPump, +                           const LLEventPumpOrPumpName& replyPump0, +                           const LLEventPumpOrPumpName& replyPump1, +                           const LLSD& replyPump0NamePath, +                           const LLSD& replyPump1NamePath) +{ +    // declare the future +    boost::dcoroutines::future<LLEventWithID> future(llcoro::get_self()); +    // either callback will assign a value to this future; listen on +    // each specified LLEventPump with a callback +    std::string name(listenerNameForCoro()); +    LLTempBoundListener connection0( +        replyPump0.getPump().listen(name + "a", +                                    wfeoh(boost::dcoroutines::make_callback(future), 0))); +    LLTempBoundListener connection1( +        replyPump1.getPump().listen(name + "b", +                                    wfeoh(boost::dcoroutines::make_callback(future), 1))); +    // skip the "post" part if requestPump is default-constructed +    if (requestPump) +    { +        // If either replyPumpNamePath is non-empty, store the corresponding +        // replyPump name in the request event. +        LLSD modevent(event); +        storeToLLSDPath(modevent, replyPump0NamePath, +                        replyPump0.getPump().getName()); +        storeToLLSDPath(modevent, replyPump1NamePath, +                        replyPump1.getPump().getName()); +        LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name +                                 << " posting to " << requestPump.getPump().getName() +                                 << ": " << modevent << LL_ENDL; +        requestPump.getPump().post(modevent); +    } +    LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name +                             << " about to wait on LLEventPumps " << replyPump0.getPump().getName() +                             << ", " << replyPump1.getPump().getName() << LL_ENDL; +    // trying to dereference ("resolve") the future makes us wait for it +    LLEventWithID value; +    { +        // instantiate Suspending to manage "current" coroutine +        llcoro::Suspending suspended; +        value = *future; +    } // destroy Suspending as soon as we're back +    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name +                             << " resuming with (" << value.first << ", " << value.second << ")" +                             << LL_ENDL; +    // returning should disconnect both connections +    return value; +} +  LLSD errorException(const LLEventWithID& result, const std::string& desc)  {      // If the result arrived on the error pump (pump 1), instead of @@ -144,3 +318,5 @@ LLSD errorLog(const LLEventWithID& result, const std::string& desc)      // A simple return must therefore be from the reply pump (pump 0).      return result.first;  } + +} // namespace llcoro diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index abbeeaa373..e2ce4bb193 100755 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -29,8 +29,6 @@  #if ! defined(LL_LLEVENTCORO_H)  #define LL_LLEVENTCORO_H -#include <boost/dcoroutine/coroutine.hpp> -#include <boost/dcoroutine/future.hpp>  #include <boost/optional.hpp>  #include <string>  #include <stdexcept> @@ -74,13 +72,16 @@ private:      boost::optional<LLEventPump&> mPump;  }; +namespace llcoro +{ +  /// This is an adapter for a signature like void LISTENER(const LLSD&), which  /// isn't a valid LLEventPump listener: such listeners should return bool.  template <typename LISTENER> -class LLVoidListener +class VoidListener  {  public: -    LLVoidListener(const LISTENER& listener): +    VoidListener(const LISTENER& listener):          mListener(listener)      {}      bool operator()(const LLSD& event) @@ -93,65 +94,19 @@ private:      LISTENER mListener;  }; -/// LLVoidListener helper function to infer the type of the LISTENER +/// VoidListener helper function to infer the type of the LISTENER  template <typename LISTENER> -LLVoidListener<LISTENER> voidlistener(const LISTENER& listener) +VoidListener<LISTENER> voidlistener(const LISTENER& listener)  { -    return LLVoidListener<LISTENER>(listener); +    return VoidListener<LISTENER>(listener);  } -namespace LLEventDetail -{ -    /// Implementation for listenerNameForCoro(), see below -    LL_COMMON_API std::string listenerNameForCoroImpl(const void* self_id); - -    /** -     * waitForEventOn() permits a coroutine to temporarily listen on an -     * LLEventPump any number of times. We don't really want to have to ask -     * the caller to label each such call with a distinct string; the whole -     * point of waitForEventOn() is to present a nice sequential interface to -     * the underlying LLEventPump-with-named-listeners machinery. So we'll use -     * LLEventPump::inventName() to generate a distinct name for each -     * temporary listener. On the other hand, because a given coroutine might -     * call waitForEventOn() any number of times, we don't really want to -     * consume an arbitrary number of generated inventName()s: that namespace, -     * though large, is nonetheless finite. So we memoize an invented name for -     * each distinct coroutine instance (each different 'self' object). We -     * can't know the type of 'self', because it depends on the coroutine -     * body's signature. So we cast its address to void*, looking for distinct -     * pointer values. Yes, that means that an early coroutine could cache a -     * value here, then be destroyed, only to be supplanted by a later -     * coroutine (of the same or different type), and we'll end up -     * "recognizing" the second one and reusing the listener name -- but -     * that's okay, since it won't collide with any listener name used by the -     * earlier coroutine since that earlier coroutine no longer exists. -     */ -    template <typename COROUTINE_SELF> -    std::string listenerNameForCoro(COROUTINE_SELF& self) -    { -        return listenerNameForCoroImpl(self.get_id()); -    } - -    /** -     * Implement behavior described for postAndWait()'s @a replyPumpNamePath -     * parameter: -     * -     * * If <tt>path.isUndefined()</tt>, do nothing. -     * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value -     *   into <tt>dest[path.asString()]</tt>. -     * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a -     *   value into <tt>dest[path.asInteger()]</tt>. -     * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step -     *   down through the structure of @a dest. The last array entry in @a -     *   path specifies the entry in the lowest-level structure in @a dest -     *   into which to store @a value. -     * -     * @note -     * In the degenerate case in which @a path is an empty array, @a dest will -     * @em become @a value rather than @em containing it. -     */ -    LL_COMMON_API void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value); -} // namespace LLEventDetail +/** + * Yield control from a coroutine for one "mainloop" tick. If your coroutine + * runs without suspending for nontrivial time, sprinkle in calls to this + * function to avoid stalling the rest of the viewer processing. + */ +void yield();  /**   * Post specified LLSD event on the specified LLEventPump, then wait for a @@ -159,7 +114,7 @@ namespace LLEventDetail   * convenience: the difference between this function and the sequence   * @code   * requestPump.post(myEvent); - * LLSD reply = waitForEventOn(self, replyPump); + * LLSD reply = waitForEventOn(replyPump);   * @endcode   * is that the sequence above fails if the reply is posted immediately on   * @a replyPump, that is, before <tt>requestPump.post()</tt> returns. In the @@ -201,97 +156,25 @@ namespace LLEventDetail   *   @a replyPumpNamePath specifies the entry in the lowest-level structure in   *   @a event into which to store <tt>replyPump.getName()</tt>.   */ -template <typename SELF> -LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump, -                 const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD()) -{ -    // declare the future -    boost::dcoroutines::future<LLSD> future(self); -    // make a callback that will assign a value to the future, and listen on -    // the specified LLEventPump with that callback -    std::string listenerName(LLEventDetail::listenerNameForCoro(self)); -    LLTempBoundListener connection( -        replyPump.getPump().listen(listenerName, -                                   voidlistener(boost::dcoroutines::make_callback(future)))); -    // skip the "post" part if requestPump is default-constructed -    if (requestPump) -    { -        // If replyPumpNamePath is non-empty, store the replyPump name in the -        // request event. -        LLSD modevent(event); -        LLEventDetail::storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName()); -		LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName -                                 << " posting to " << requestPump.getPump().getName() -								 << LL_ENDL; - -		// *NOTE:Mani - Removed because modevent could contain user's hashed passwd. -		//                         << ": " << modevent << LL_ENDL; -        requestPump.getPump().post(modevent); -    } -    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName -                             << " about to wait on LLEventPump " << replyPump.getPump().getName() -                             << LL_ENDL; -    // trying to dereference ("resolve") the future makes us wait for it -    LLSD value(*future); -    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName -                             << " resuming with " << value << LL_ENDL; -    // returning should disconnect the connection -    return value; -} +LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, +                 const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD());  /// Wait for the next event on the specified LLEventPump. Pass either the  /// LLEventPump& or its string name. -template <typename SELF> -LLSD waitForEventOn(SELF& self, const LLEventPumpOrPumpName& pump) +inline +LLSD waitForEventOn(const LLEventPumpOrPumpName& pump)  {      // This is now a convenience wrapper for postAndWait(). -    return postAndWait(self, LLSD(), LLEventPumpOrPumpName(), pump); +    return postAndWait(LLSD(), LLEventPumpOrPumpName(), pump);  } +} // namespace llcoro +  /// return type for two-pump variant of waitForEventOn()  typedef std::pair<LLSD, int> LLEventWithID; -namespace LLEventDetail +namespace llcoro  { -    /** -     * This helper is specifically for the two-pump version of waitForEventOn(). -     * We use a single future object, but we want to listen on two pumps with it. -     * Since we must still adapt from (the callable constructed by) -     * boost::dcoroutines::make_callback() (void return) to provide an event -     * listener (bool return), we've adapted LLVoidListener for the purpose. The -     * basic idea is that we construct a distinct instance of WaitForEventOnHelper -     * -- binding different instance data -- for each of the pumps. Then, when a -     * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine -     * that LLSD with its discriminator to feed the future object. -     */ -    template <typename LISTENER> -    class WaitForEventOnHelper -    { -    public: -        WaitForEventOnHelper(const LISTENER& listener, int discriminator): -            mListener(listener), -            mDiscrim(discriminator) -        {} -        // this signature is required for an LLEventPump listener -        bool operator()(const LLSD& event) -        { -            // our future object is defined to accept LLEventWithID -            mListener(LLEventWithID(event, mDiscrim)); -            // don't swallow the event, let other listeners see it -            return false; -        } -    private: -        LISTENER mListener; -        const int mDiscrim; -    }; - -    /// WaitForEventOnHelper type-inference helper -    template <typename LISTENER> -    WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator) -    { -        return WaitForEventOnHelper<LISTENER>(listener, discriminator); -    } -} // namespace LLEventDetail  /**   * This function waits for a reply on either of two specified LLEventPumps. @@ -313,7 +196,7 @@ namespace LLEventDetail   * I'd have preferred to overload the name postAndWait() for both signatures.   * But consider the following ambiguous call:   * @code - * postAndWait(self, LLSD(), requestPump, replyPump, "someString"); + * postAndWait(LLSD(), requestPump, replyPump, "someString");   * @endcode   * "someString" could be converted to either LLSD (@a replyPumpNamePath for   * the single-pump function) or LLEventOrPumpName (@a replyPump1 for two-pump @@ -322,69 +205,29 @@ namespace LLEventDetail   * It seems less burdensome to write postAndWait2() than to write either   * LLSD("someString") or LLEventOrPumpName("someString").   */ -template <typename SELF> -LLEventWithID postAndWait2(SELF& self, const LLSD& event, +LLEventWithID postAndWait2(const LLSD& event,                             const LLEventPumpOrPumpName& requestPump,                             const LLEventPumpOrPumpName& replyPump0,                             const LLEventPumpOrPumpName& replyPump1,                             const LLSD& replyPump0NamePath=LLSD(), -                           const LLSD& replyPump1NamePath=LLSD()) -{ -    // declare the future -    boost::dcoroutines::future<LLEventWithID> future(self); -    // either callback will assign a value to this future; listen on -    // each specified LLEventPump with a callback -    std::string name(LLEventDetail::listenerNameForCoro(self)); -    LLTempBoundListener connection0( -        replyPump0.getPump().listen(name + "a", -                               LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 0))); -    LLTempBoundListener connection1( -        replyPump1.getPump().listen(name + "b", -                               LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 1))); -    // skip the "post" part if requestPump is default-constructed -    if (requestPump) -    { -        // If either replyPumpNamePath is non-empty, store the corresponding -        // replyPump name in the request event. -        LLSD modevent(event); -        LLEventDetail::storeToLLSDPath(modevent, replyPump0NamePath, -                                       replyPump0.getPump().getName()); -        LLEventDetail::storeToLLSDPath(modevent, replyPump1NamePath, -                                       replyPump1.getPump().getName()); -        LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name -                                 << " posting to " << requestPump.getPump().getName() -                                 << ": " << modevent << LL_ENDL; -        requestPump.getPump().post(modevent); -    } -    LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name -                             << " about to wait on LLEventPumps " << replyPump0.getPump().getName() -                             << ", " << replyPump1.getPump().getName() << LL_ENDL; -    // trying to dereference ("resolve") the future makes us wait for it -    LLEventWithID value(*future); -    LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name -                             << " resuming with (" << value.first << ", " << value.second << ")" -                             << LL_ENDL; -    // returning should disconnect both connections -    return value; -} +                           const LLSD& replyPump1NamePath=LLSD());  /**   * Wait for the next event on either of two specified LLEventPumps.   */ -template <typename SELF> +inline  LLEventWithID -waitForEventOn(SELF& self, -               const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1) +waitForEventOn(const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName& pump1)  {      // This is now a convenience wrapper for postAndWait2(). -    return postAndWait2(self, LLSD(), LLEventPumpOrPumpName(), pump0, pump1); +    return postAndWait2(LLSD(), LLEventPumpOrPumpName(), pump0, pump1);  }  /**   * Helper for the two-pump variant of waitForEventOn(), e.g.:   *   * @code - * LLSD reply = errorException(waitForEventOn(self, replyPump, errorPump), + * LLSD reply = errorException(waitForEventOn(replyPump, errorPump),   *                             "error response from login.cgi");   * @endcode   * @@ -400,6 +243,8 @@ waitForEventOn(SELF& self,   */  LLSD errorException(const LLEventWithID& result, const std::string& desc); +} // namespace llcoro +  /**   * Exception thrown by errorException(). We don't call this LLEventError   * because it's not an error in event processing: rather, this exception @@ -420,12 +265,17 @@ private:      LLSD mData;  }; +namespace llcoro +{ +  /**   * Like errorException(), save that this trips a fatal error using LL_ERRS   * rather than throwing an exception.   */  LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc); +} // namespace llcoro +  /**   * Certain event APIs require the name of an LLEventPump on which they should   * post results. While it works to invent a distinct name and let @@ -454,26 +304,16 @@ public:      /**       * Wait for an event on this LLEventPump. -     * -     * @note -     * The other major usage pattern we considered was to bind @c self at -     * LLCoroEventPump construction time, which would avoid passing the -     * parameter to each wait() call. But if we were going to bind @c self as -     * a class member, we'd need to specify a class template parameter -     * indicating its type. The big advantage of passing it to the wait() call -     * is that the type can be implicit.       */ -    template <typename SELF> -    LLSD wait(SELF& self) +    LLSD wait()      { -        return waitForEventOn(self, mPump); +        return llcoro::waitForEventOn(mPump);      } -    template <typename SELF> -    LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& requestPump, +    LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump,                       const LLSD& replyPumpNamePath=LLSD())      { -        return ::postAndWait(self, event, requestPump, mPump, replyPumpNamePath); +        return llcoro::postAndWait(event, requestPump, mPump, replyPumpNamePath);      }  private: @@ -509,57 +349,51 @@ public:      /// request pump 1      LLEventPump& getPump1() { return mPump1; } -    /// waitForEventOn(self, either of our two LLEventPumps) -    template <typename SELF> -    LLEventWithID wait(SELF& self) +    /// waitForEventOn(either of our two LLEventPumps) +    LLEventWithID wait()      { -        return waitForEventOn(self, mPump0, mPump1); +        return llcoro::waitForEventOn(mPump0, mPump1);      } -    /// errorException(wait(self)) -    template <typename SELF> -    LLSD waitWithException(SELF& self) +    /// errorException(wait()) +    LLSD waitWithException()      { -        return errorException(wait(self), std::string("Error event on ") + getName1()); +        return llcoro::errorException(wait(), std::string("Error event on ") + getName1());      } -    /// errorLog(wait(self)) -    template <typename SELF> -    LLSD waitWithLog(SELF& self) +    /// errorLog(wait()) +    LLSD waitWithLog()      { -        return errorLog(wait(self), std::string("Error event on ") + getName1()); +        return llcoro::errorLog(wait(), std::string("Error event on ") + getName1());      } -    template <typename SELF> -    LLEventWithID postAndWait(SELF& self, const LLSD& event, +    LLEventWithID postAndWait(const LLSD& event,                                const LLEventPumpOrPumpName& requestPump,                                const LLSD& replyPump0NamePath=LLSD(),                                const LLSD& replyPump1NamePath=LLSD())      { -        return postAndWait2(self, event, requestPump, mPump0, mPump1, -                            replyPump0NamePath, replyPump1NamePath); +        return llcoro::postAndWait2(event, requestPump, mPump0, mPump1, +                                    replyPump0NamePath, replyPump1NamePath);      } -    template <typename SELF> -    LLSD postAndWaitWithException(SELF& self, const LLSD& event, +    LLSD postAndWaitWithException(const LLSD& event,                                    const LLEventPumpOrPumpName& requestPump,                                    const LLSD& replyPump0NamePath=LLSD(),                                    const LLSD& replyPump1NamePath=LLSD())      { -        return errorException(postAndWait(self, event, requestPump, -                                          replyPump0NamePath, replyPump1NamePath), -                              std::string("Error event on ") + getName1()); +        return llcoro::errorException(postAndWait(event, requestPump, +                                                  replyPump0NamePath, replyPump1NamePath), +                                      std::string("Error event on ") + getName1());      } -    template <typename SELF> -    LLSD postAndWaitWithLog(SELF& self, const LLSD& event, +    LLSD postAndWaitWithLog(const LLSD& event,                              const LLEventPumpOrPumpName& requestPump,                              const LLSD& replyPump0NamePath=LLSD(),                              const LLSD& replyPump1NamePath=LLSD())      { -        return errorLog(postAndWait(self, event, requestPump, -                                    replyPump0NamePath, replyPump1NamePath), -                        std::string("Error event on ") + getName1()); +        return llcoro::errorLog(postAndWait(event, requestPump, +                                            replyPump0NamePath, replyPump1NamePath), +                                std::string("Error event on ") + getName1());      }  private: diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 3836a9b5fb..1107973569 100755 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -144,14 +144,9 @@ private:  };  /** - * intrusive pointer support - * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type - */ -/**   * intrusive pointer support for LLThreadSafeRefCount   * this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type   */ -  inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)   {  	p->ref(); @@ -162,6 +157,10 @@ inline void intrusive_ptr_release(LLThreadSafeRefCount* p)  	p->unref();   } +/** + * intrusive pointer support + * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type + */  inline void intrusive_ptr_add_ref(LLRefCount* p)   {  	p->ref(); diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp new file mode 100644 index 0000000000..2afdba388a --- /dev/null +++ b/indra/llcommon/llsdjson.cpp @@ -0,0 +1,78 @@ +/**  + * @file llsdjson.cpp + * @brief LLSD flexible data system + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2015, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +// Must turn on conditional declarations in header file so definitions end up +// with proper linkage. +#define LLSD_DEBUG_INFO +#include "linden_common.h" + +#include "llsdjson.h" + +#include "llerror.h" +#include "../llmath/llmath.h" + +//========================================================================= +LLSD LlsdFromJson(const Json::Value &val) +{ +    LLSD result; + +    switch (val.type()) +    { +    default: +    case Json::nullValue: +        break; +    case Json::intValue: +        result = LLSD(static_cast<LLSD::Integer>(val.asInt())); +        break; +    case Json::uintValue: +        result = LLSD(static_cast<LLSD::Integer>(val.asUInt())); +        break; +    case Json::realValue: +        result = LLSD(static_cast<LLSD::Real>(val.asDouble())); +        break; +    case Json::stringValue: +        result = LLSD(static_cast<LLSD::String>(val.asString())); +        break; +    case Json::booleanValue: +        result = LLSD(static_cast<LLSD::Boolean>(val.asBool())); +        break; +    case Json::arrayValue: +        result = LLSD::emptyArray(); +        for (Json::ValueConstIterator it = val.begin(); it != val.end(); ++it) +        { +            result.append(LlsdFromJson((*it))); +        } +        break; +    case Json::objectValue: +        result = LLSD::emptyMap(); +        for (Json::ValueConstIterator it = val.begin(); it != val.end(); ++it) +        { +            result[it.memberName()] = LlsdFromJson((*it)); +        } +        break; +    } +    return result; +} diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h new file mode 100644 index 0000000000..cdf9fed500 --- /dev/null +++ b/indra/llcommon/llsdjson.h @@ -0,0 +1,59 @@ +/**  + * @file llsdjson.cpp + * @brief LLSD flexible data system + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2015, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLSDJSON_H +#define LL_LLSDJSON_H + +#include <map> +#include <string> +#include <vector> + +#include "stdtypes.h" + +#include "llsd.h" +#include "value.h" + +/// Convert a parsed JSON structure into LLSD maintaining member names and  +/// array indexes. +/// JSON/JavaScript types are converted as follows: +///  +/// JSON Type     | LLSD Type +/// --------------+-------------- +///  null         |  undefined +///  integer      |  LLSD::Integer +///  unsigned     |  LLSD::Integer +///  real/numeric |  LLSD::Real +///  string       |  LLSD::String +///  boolean      |  LLSD::Boolean +///  array        |  LLSD::Array +///  object       |  LLSD::Map +///   +/// For maps and arrays child entries will be converted and added to the structure. +/// Order is preserved for an array but not for objects. +LLSD LlsdFromJson(const Json::Value &val); + + +#endif // LL_LLSDJSON_H diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 0177f48bf5..393f6d7a8c 100755 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1394,6 +1394,7 @@ BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)  	return rv;  } +// *TODO: reimplement in terms of algorithm   //static  template<class T>   void LLStringUtilBase<T>::stripNonprintable(string_type& string) @@ -1427,6 +1428,7 @@ void LLStringUtilBase<T>::stripNonprintable(string_type& string)  	delete []c_string;  } +// *TODO: reimplement in terms of algorithm   template<class T>  std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,  												const string_type& triggers, diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 2096807e53..00be5035f2 100755 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -59,17 +59,20 @@  //  http://www.boost.org/LICENSE_1_0.txt)  /*****************************************************************************/ +#define BOOST_RESULT_OF_USE_TR1 1  // On some platforms, Boost.Coroutine must #define magic symbols before  // #including platform-API headers. Naturally, that's ineffective unless the  // Boost.Coroutine #include is the *first* #include of the platform header.  // That means that client code must generally #include Boost.Coroutine headers  // before anything else. +#define BOOST_RESULT_OF_USE_TR1 1  #include <boost/dcoroutine/coroutine.hpp>  // Normally, lleventcoro.h obviates future.hpp. We only include this because  // we implement a "by hand" test of future functionality.  #include <boost/dcoroutine/future.hpp>  #include <boost/bind.hpp>  #include <boost/range.hpp> +#include <boost/utility.hpp>  #include "linden_common.h" @@ -82,9 +85,12 @@  #include "llevents.h"  #include "tests/wrapllerrs.h"  #include "stringize.h" +#include "llcoros.h"  #include "lleventcoro.h"  #include "../test/debug.h" +using namespace llcoro; +  /*****************************************************************************  *   from the banana.cpp example program borrowed for test<1>()  *****************************************************************************/ @@ -121,9 +127,6 @@ typedef coroutine<std::string::iterator(void)> match_coroutine_type;  /*****************************************************************************  *   Test helpers  *****************************************************************************/ -// I suspect this will be typical of coroutines used in Linden software -typedef boost::dcoroutines::coroutine<void()> coroutine_type; -  /// Simulate an event API whose response is immediate: sent on receipt of the  /// initial request, rather than after some delay. This is the case that  /// distinguishes postAndWait() from calling post(), then calling @@ -162,306 +165,7 @@ private:  *****************************************************************************/  namespace tut  { -    struct coroutine_data -    { -        // Define coroutine bodies as methods here so they can use ensure*() - -        void explicit_wait(coroutine_type::self& self) -        { -            BEGIN -            { -                // ... do whatever preliminary stuff must happen ... - -                // declare the future -                boost::dcoroutines::future<LLSD> future(self); -                // tell the future what to wait for -                LLTempBoundListener connection( -                    LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::dcoroutines::make_callback(future)))); -                ensure("Not yet", ! future); -                // attempting to dereference ("resolve") the future causes the calling -                // coroutine to wait for it -                debug("about to wait"); -                result = *future; -                ensure("Got it", future); -            } -            END -        } - -        void waitForEventOn1(coroutine_type::self& self) -        { -            BEGIN -            { -                result = waitForEventOn(self, "source"); -            } -            END -        } - -        void waitForEventOn2(coroutine_type::self& self) -        { -            BEGIN -            { -                LLEventWithID pair = waitForEventOn(self, "reply", "error"); -                result = pair.first; -                which  = pair.second; -                debug(STRINGIZE("result = " << result << ", which = " << which)); -            } -            END -        } - -        void postAndWait1(coroutine_type::self& self) -        { -            BEGIN -            { -                result = postAndWait(self, -                                     LLSDMap("value", 17),       // request event -                                     immediateAPI.getPump(),     // requestPump -                                     "reply1",                   // replyPump -                                     "reply");                   // request["reply"] = name -            } -            END -        } - -        void postAndWait2(coroutine_type::self& self) -        { -            BEGIN -            { -                LLEventWithID pair = ::postAndWait2(self, -                                                    LLSDMap("value", 18), -                                                    immediateAPI.getPump(), -                                                    "reply2", -                                                    "error2", -                                                    "reply", -                                                    "error"); -                result = pair.first; -                which  = pair.second; -                debug(STRINGIZE("result = " << result << ", which = " << which)); -            } -            END -        } - -        void postAndWait2_1(coroutine_type::self& self) -        { -            BEGIN -            { -                LLEventWithID pair = ::postAndWait2(self, -                                                    LLSDMap("value", 18)("fail", LLSD()), -                                                    immediateAPI.getPump(), -                                                    "reply2", -                                                    "error2", -                                                    "reply", -                                                    "error"); -                result = pair.first; -                which  = pair.second; -                debug(STRINGIZE("result = " << result << ", which = " << which)); -            } -            END -        } - -        void coroPump(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPump waiter; -                replyName = waiter.getName(); -                result = waiter.wait(self); -            } -            END -        } - -        void coroPumpPost(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPump waiter; -                result = waiter.postAndWait(self, LLSDMap("value", 17), -                                            immediateAPI.getPump(), "reply"); -            } -            END -        } - -        void coroPumps(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                replyName = waiter.getName0(); -                errorName = waiter.getName1(); -                LLEventWithID pair(waiter.wait(self)); -                result = pair.first; -                which  = pair.second; -            } -            END -        } - -        void coroPumpsNoEx(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                replyName = waiter.getName0(); -                errorName = waiter.getName1(); -                result = waiter.waitWithException(self); -            } -            END -        } - -        void coroPumpsEx(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                replyName = waiter.getName0(); -                errorName = waiter.getName1(); -                try -                { -                    result = waiter.waitWithException(self); -                    debug("no exception"); -                } -                catch (const LLErrorEvent& e) -                { -                    debug(STRINGIZE("exception " << e.what())); -                    errordata = e.getData(); -                } -            } -            END -        } - -        void coroPumpsNoLog(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                replyName = waiter.getName0(); -                errorName = waiter.getName1(); -                result = waiter.waitWithLog(self); -            } -            END -        } - -        void coroPumpsLog(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                replyName = waiter.getName0(); -                errorName = waiter.getName1(); -                WrapLLErrs capture; -                try -                { -                    result = waiter.waitWithLog(self); -                    debug("no exception"); -                } -                catch (const WrapLLErrs::FatalException& e) -                { -                    debug(STRINGIZE("exception " << e.what())); -                    threw = e.what(); -                } -            } -            END -        } - -        void coroPumpsPost(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                LLEventWithID pair(waiter.postAndWait(self, LLSDMap("value", 23), -                                                      immediateAPI.getPump(), "reply", "error")); -                result = pair.first; -                which  = pair.second; -            } -            END -        } - -        void coroPumpsPost_1(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                LLEventWithID pair( -                    waiter.postAndWait(self, LLSDMap("value", 23)("fail", LLSD()), -                                       immediateAPI.getPump(), "reply", "error")); -                result = pair.first; -                which  = pair.second; -            } -            END -        } - -        void coroPumpsPostNoEx(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                result = waiter.postAndWaitWithException(self, LLSDMap("value", 8), -                                                         immediateAPI.getPump(), "reply", "error"); -            } -            END -        } - -        void coroPumpsPostEx(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                try -                { -                    result = waiter.postAndWaitWithException(self, -                        LLSDMap("value", 9)("fail", LLSD()), -                        immediateAPI.getPump(), "reply", "error"); -                    debug("no exception"); -                } -                catch (const LLErrorEvent& e) -                { -                    debug(STRINGIZE("exception " << e.what())); -                    errordata = e.getData(); -                } -            } -            END -        } - -        void coroPumpsPostNoLog(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                result = waiter.postAndWaitWithLog(self, LLSDMap("value", 30), -                                                   immediateAPI.getPump(), "reply", "error"); -            } -            END -        } - -        void coroPumpsPostLog(coroutine_type::self& self) -        { -            BEGIN -            { -                LLCoroEventPumps waiter; -                WrapLLErrs capture; -                try -                { -                    result = waiter.postAndWaitWithLog(self, -                        LLSDMap("value", 31)("fail", LLSD()), -                        immediateAPI.getPump(), "reply", "error"); -                    debug("no exception"); -                } -                catch (const WrapLLErrs::FatalException& e) -                { -                    debug(STRINGIZE("exception " << e.what())); -                    threw = e.what(); -                } -            } -            END -        } - -        void ensure_done(coroutine_type& coro) -        { -            ensure("coroutine complete", ! coro); -        } - -        ImmediateAPI immediateAPI; -        std::string replyName, errorName, threw; -        LLSD result, errordata; -        int which; -    }; +    struct coroutine_data {};      typedef test_group<coroutine_data> coroutine_group;      typedef coroutine_group::object object;      coroutine_group coroutinegrp("coroutine"); @@ -511,16 +215,56 @@ namespace tut          ensure("done", ! matcher);      } +    // use static data so we can intersperse coroutine functions with the +    // tests that engage them +    ImmediateAPI immediateAPI; +    std::string replyName, errorName, threw; +    LLSD result, errordata; +    int which; + +    // reinit vars at the start of each test +    void clear() +    { +        replyName.clear(); +        errorName.clear(); +        threw.clear(); +        result = LLSD(); +        errordata = LLSD(); +        which = 0; +    } + +    void explicit_wait(boost::dcoroutines::coroutine<void()>::self& self) +    { +        BEGIN +        { +            // ... do whatever preliminary stuff must happen ... + +            // declare the future +            boost::dcoroutines::future<LLSD> future(self); +            // tell the future what to wait for +            LLTempBoundListener connection( +                LLEventPumps::instance().obtain("source").listen("coro", voidlistener(boost::dcoroutines::make_callback(future)))); +            ensure("Not yet", ! future); +            // attempting to dereference ("resolve") the future causes the calling +            // coroutine to wait for it +            debug("about to wait"); +            result = *future; +            ensure("Got it", future); +        } +        END +    } +      template<> template<>      void object::test<2>()      { +        clear();          set_test_name("explicit_wait");          DEBUG;          // Construct the coroutine instance that will run explicit_wait.          // Pass the ctor a callable that accepts the coroutine_type::self          // param passed by the library. -        coroutine_type coro(boost::bind(&coroutine_data::explicit_wait, this, _1)); +        boost::dcoroutines::coroutine<void()> coro(explicit_wait);          // Start the coroutine          coro(std::nothrow);          // When the coroutine waits for the event pump, it returns here. @@ -528,37 +272,56 @@ namespace tut          // Satisfy the wait.          LLEventPumps::instance().obtain("source").post("received");          // Now wait for the coroutine to complete. -        ensure_done(coro); +        ensure("coroutine complete", ! coro);          // ensure the coroutine ran and woke up again with the intended result          ensure_equals(result.asString(), "received");      } +    void waitForEventOn1() +    { +        BEGIN +        { +            result = waitForEventOn("source"); +        } +        END +    } +      template<> template<>      void object::test<3>()      { +        clear();          set_test_name("waitForEventOn1");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn1, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<3>", waitForEventOn1);          debug("about to send");          LLEventPumps::instance().obtain("source").post("received");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "received");      } +    void waitForEventOn2() +    { +        BEGIN +        { +            LLEventWithID pair = waitForEventOn("reply", "error"); +            result = pair.first; +            which  = pair.second; +            debug(STRINGIZE("result = " << result << ", which = " << which)); +        } +        END +    } +      template<> template<>      void object::test<4>()      { +        clear();          set_test_name("waitForEventOn2 reply");          {          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<4>", waitForEventOn2);          debug("about to send");          LLEventPumps::instance().obtain("reply").post("received");          debug("back from send"); -        ensure_done(coro);          }          ensure_equals(result.asString(), "received");          ensure_equals("which pump", which, 0); @@ -567,43 +330,65 @@ namespace tut      template<> template<>      void object::test<5>()      { +        clear();          set_test_name("waitForEventOn2 error");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::waitForEventOn2, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<5>", waitForEventOn2);          debug("about to send");          LLEventPumps::instance().obtain("error").post("badness");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "badness");          ensure_equals("which pump", which, 1);      } +    void coroPump() +    { +        BEGIN +        { +            LLCoroEventPump waiter; +            replyName = waiter.getName(); +            result = waiter.wait(); +        } +        END +    } +      template<> template<>      void object::test<6>()      { +        clear();          set_test_name("coroPump");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPump, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<6>", coroPump);          debug("about to send");          LLEventPumps::instance().obtain(replyName).post("received");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "received");      } +    void coroPumps() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            replyName = waiter.getName0(); +            errorName = waiter.getName1(); +            LLEventWithID pair(waiter.wait()); +            result = pair.first; +            which  = pair.second; +        } +        END +    } +      template<> template<>      void object::test<7>()      { +        clear();          set_test_name("coroPumps reply");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<7>", coroPumps);          debug("about to send");          LLEventPumps::instance().obtain(replyName).post("received");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "received");          ensure_equals("which pump", which, 0);      } @@ -611,188 +396,389 @@ namespace tut      template<> template<>      void object::test<8>()      { +        clear();          set_test_name("coroPumps error");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumps, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<8>", coroPumps);          debug("about to send");          LLEventPumps::instance().obtain(errorName).post("badness");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "badness");          ensure_equals("which pump", which, 1);      } +    void coroPumpsNoEx() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            replyName = waiter.getName0(); +            errorName = waiter.getName1(); +            result = waiter.waitWithException(); +        } +        END +    } +      template<> template<>      void object::test<9>()      { +        clear();          set_test_name("coroPumpsNoEx");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoEx, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<9>", coroPumpsNoEx);          debug("about to send");          LLEventPumps::instance().obtain(replyName).post("received");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "received");      } +    void coroPumpsEx() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            replyName = waiter.getName0(); +            errorName = waiter.getName1(); +            try +            { +                result = waiter.waitWithException(); +                debug("no exception"); +            } +            catch (const LLErrorEvent& e) +            { +                debug(STRINGIZE("exception " << e.what())); +                errordata = e.getData(); +            } +        } +        END +    } +      template<> template<>      void object::test<10>()      { +        clear();          set_test_name("coroPumpsEx");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsEx, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<10>", coroPumpsEx);          debug("about to send");          LLEventPumps::instance().obtain(errorName).post("badness");          debug("back from send"); -        ensure_done(coro);          ensure("no result", result.isUndefined());          ensure_equals("got error", errordata.asString(), "badness");      } +    void coroPumpsNoLog() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            replyName = waiter.getName0(); +            errorName = waiter.getName1(); +            result = waiter.waitWithLog(); +        } +        END +    } +      template<> template<>      void object::test<11>()      { +        clear();          set_test_name("coroPumpsNoLog");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsNoLog, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<11>", coroPumpsNoLog);          debug("about to send");          LLEventPumps::instance().obtain(replyName).post("received");          debug("back from send"); -        ensure_done(coro);          ensure_equals(result.asString(), "received");      } +    void coroPumpsLog() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            replyName = waiter.getName0(); +            errorName = waiter.getName1(); +            WrapLLErrs capture; +            try +            { +                result = waiter.waitWithLog(); +                debug("no exception"); +            } +            catch (const WrapLLErrs::FatalException& e) +            { +                debug(STRINGIZE("exception " << e.what())); +                threw = e.what(); +            } +        } +        END +    } +      template<> template<>      void object::test<12>()      { +        clear();          set_test_name("coroPumpsLog");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsLog, this, _1)); -        coro(std::nothrow); +        LLCoros::instance().launch("test<12>", coroPumpsLog);          debug("about to send");          LLEventPumps::instance().obtain(errorName).post("badness");          debug("back from send"); -        ensure_done(coro);          ensure("no result", result.isUndefined());          ensure_contains("got error", threw, "badness");      } +    void postAndWait1() +    { +        BEGIN +        { +            result = postAndWait(LLSDMap("value", 17),       // request event +                                 immediateAPI.getPump(),     // requestPump +                                 "reply1",                   // replyPump +                                 "reply");                   // request["reply"] = name +        } +        END +    } +      template<> template<>      void object::test<13>()      { +        clear();          set_test_name("postAndWait1");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::postAndWait1, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<13>", postAndWait1);          ensure_equals(result.asInteger(), 18);      } +    void postAndWait2() +    { +        BEGIN +        { +            LLEventWithID pair = ::postAndWait2(LLSDMap("value", 18), +                                                immediateAPI.getPump(), +                                                "reply2", +                                                "error2", +                                                "reply", +                                                "error"); +            result = pair.first; +            which  = pair.second; +            debug(STRINGIZE("result = " << result << ", which = " << which)); +        } +        END +    } +      template<> template<>      void object::test<14>()      { +        clear();          set_test_name("postAndWait2");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::postAndWait2, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<14>", postAndWait2);          ensure_equals(result.asInteger(), 19);          ensure_equals(which, 0);      } +    void postAndWait2_1() +    { +        BEGIN +        { +            LLEventWithID pair = ::postAndWait2(LLSDMap("value", 18)("fail", LLSD()), +                                                immediateAPI.getPump(), +                                                "reply2", +                                                "error2", +                                                "reply", +                                                "error"); +            result = pair.first; +            which  = pair.second; +            debug(STRINGIZE("result = " << result << ", which = " << which)); +        } +        END +    } +      template<> template<>      void object::test<15>()      { +        clear();          set_test_name("postAndWait2_1");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::postAndWait2_1, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<15>", postAndWait2_1);          ensure_equals(result.asInteger(), 19);          ensure_equals(which, 1);      } +    void coroPumpPost() +    { +        BEGIN +        { +            LLCoroEventPump waiter; +            result = waiter.postAndWait(LLSDMap("value", 17), +                                        immediateAPI.getPump(), "reply"); +        } +        END +    } +      template<> template<>      void object::test<16>()      { +        clear();          set_test_name("coroPumpPost");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpPost, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<16>", coroPumpPost);          ensure_equals(result.asInteger(), 18);      } +    void coroPumpsPost() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            LLEventWithID pair(waiter.postAndWait(LLSDMap("value", 23), +                                                  immediateAPI.getPump(), "reply", "error")); +            result = pair.first; +            which  = pair.second; +        } +        END +    } +      template<> template<>      void object::test<17>()      { +        clear();          set_test_name("coroPumpsPost reply");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<17>", coroPumpsPost);          ensure_equals(result.asInteger(), 24);          ensure_equals("which pump", which, 0);      } +    void coroPumpsPost_1() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            LLEventWithID pair( +                waiter.postAndWait(LLSDMap("value", 23)("fail", LLSD()), +                                   immediateAPI.getPump(), "reply", "error")); +            result = pair.first; +            which  = pair.second; +        } +        END +    } +      template<> template<>      void object::test<18>()      { +        clear();          set_test_name("coroPumpsPost error");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPost_1, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<18>", coroPumpsPost_1);          ensure_equals(result.asInteger(), 24);          ensure_equals("which pump", which, 1);      } +    void coroPumpsPostNoEx() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            result = waiter.postAndWaitWithException(LLSDMap("value", 8), +                                                     immediateAPI.getPump(), "reply", "error"); +        } +        END +    } +      template<> template<>      void object::test<19>()      { +        clear();          set_test_name("coroPumpsPostNoEx");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoEx, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<19>", coroPumpsPostNoEx);          ensure_equals(result.asInteger(), 9);      } +    void coroPumpsPostEx() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            try +            { +                result = waiter.postAndWaitWithException( +                    LLSDMap("value", 9)("fail", LLSD()), +                    immediateAPI.getPump(), "reply", "error"); +                debug("no exception"); +            } +            catch (const LLErrorEvent& e) +            { +                debug(STRINGIZE("exception " << e.what())); +                errordata = e.getData(); +            } +        } +        END +    } +      template<> template<>      void object::test<20>()      { +        clear();          set_test_name("coroPumpsPostEx");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostEx, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<20>", coroPumpsPostEx);          ensure("no result", result.isUndefined());          ensure_equals("got error", errordata.asInteger(), 10);      } +    void coroPumpsPostNoLog() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            result = waiter.postAndWaitWithLog(LLSDMap("value", 30), +                                               immediateAPI.getPump(), "reply", "error"); +        } +        END +    } +      template<> template<>      void object::test<21>()      { +        clear();          set_test_name("coroPumpsPostNoLog");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostNoLog, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<21>", coroPumpsPostNoLog);          ensure_equals(result.asInteger(), 31);      } +    void coroPumpsPostLog() +    { +        BEGIN +        { +            LLCoroEventPumps waiter; +            WrapLLErrs capture; +            try +            { +                result = waiter.postAndWaitWithLog( +                    LLSDMap("value", 31)("fail", LLSD()), +                    immediateAPI.getPump(), "reply", "error"); +                debug("no exception"); +            } +            catch (const WrapLLErrs::FatalException& e) +            { +                debug(STRINGIZE("exception " << e.what())); +                threw = e.what(); +            } +        } +        END +    } +      template<> template<>      void object::test<22>()      { +        clear();          set_test_name("coroPumpsPostLog");          DEBUG; -        coroutine_type coro(boost::bind(&coroutine_data::coroPumpsPostLog, this, _1)); -        coro(std::nothrow); -        ensure_done(coro); +        LLCoros::instance().launch("test<22>", coroPumpsPostLog);          ensure("no result", result.isUndefined());          ensure_contains("got error", threw, "32");      } diff --git a/indra/llcorehttp/_httpinternal.h b/indra/llcorehttp/_httpinternal.h index a2a60ca056..79c89d6c92 100755 --- a/indra/llcorehttp/_httpinternal.h +++ b/indra/llcorehttp/_httpinternal.h @@ -104,8 +104,9 @@ namespace LLCore  {  // Maxium number of policy classes that can be defined. -// *TODO:  Currently limited to the default class + 1, extend. -const int HTTP_POLICY_CLASS_LIMIT = 8; +// *TODO:  Currently limited to the default class + 1, extend.  +// (TSN: should this be more dynamically sized.  Is there a reason to hard limit the number of policies?) +const int HTTP_POLICY_CLASS_LIMIT = 32;  // Debug/informational tracing.  Used both  // as a global option and in per-request traces. diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index b9632a7921..799587ff22 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -139,7 +139,8 @@ HttpOpRequest::HttpOpRequest()  	  mPolicyRetries(0),  	  mPolicy503Retries(0),  	  mPolicyRetryAt(HttpTime(0)), -	  mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT) +	  mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT), +	  mCallbackSSLVerify(NULL)  {  	// *NOTE:  As members are added, retry initialization/cleanup  	// may need to be extended in @see prepareRequest(). @@ -259,7 +260,9 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)  		response->setStatus(mStatus);  		response->setBody(mReplyBody);  		response->setHeaders(mReplyHeaders); -		if (mReplyOffset || mReplyLength) +        response->setRequestURL(mReqURL); + +        if (mReplyOffset || mReplyLength)  		{  			// Got an explicit offset/length in response  			response->setRange(mReplyOffset, mReplyLength, mReplyFullLength); @@ -267,6 +270,14 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)  		response->setContentType(mReplyConType);  		response->setRetries(mPolicyRetries, mPolicy503Retries); +		HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats); + +		curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload); +		curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime); +		curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload); + +		response->setTransferStats(stats); +  		mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);  		response->release(); @@ -346,6 +357,46 @@ HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,  } +HttpStatus HttpOpRequest::setupDelete(HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    HttpOptions * options, +    HttpHeaders * headers) +{ +    setupCommon(policy_id, priority, url, NULL, options, headers); +    mReqMethod = HOR_DELETE; + +    return HttpStatus(); +} + + +HttpStatus HttpOpRequest::setupPatch(HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    BufferArray * body, +    HttpOptions * options, +    HttpHeaders * headers) +{ +    setupCommon(policy_id, priority, url, body, options, headers); +    mReqMethod = HOR_PATCH; + +    return HttpStatus(); +} + + +HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    HttpOptions * options, +    HttpHeaders * headers) +{ +    setupCommon(policy_id, priority, url, NULL, options, headers); +    mReqMethod = HOR_COPY; + +    return HttpStatus(); +} + +  void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,  								HttpRequest::priority_t priority,  								const std::string & url, @@ -452,18 +503,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");  	check_curl_easy_code(code, CURLOPT_ENCODING); -	// The Linksys WRT54G V5 router has an issue with frequent -	// DNS lookups from LAN machines.  If they happen too often, -	// like for every HTTP request, the router gets annoyed after -	// about 700 or so requests and starts issuing TCP RSTs to -	// new connections.  Reuse the DNS lookups for even a few -	// seconds and no RSTs. -	code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15); -	check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);  	code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);  	check_curl_easy_code(code, CURLOPT_AUTOREFERER); -	code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1); -	check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);  	code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);  	check_curl_easy_code(code, CURLOPT_MAXREDIRS);  	code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback); @@ -474,11 +515,57 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	check_curl_easy_code(code, CURLOPT_READFUNCTION);  	code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this);  	check_curl_easy_code(code, CURLOPT_READDATA); -	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1); +    code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback); +    check_curl_easy_code(code, CURLOPT_SEEKFUNCTION); +    code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, this); +    check_curl_easy_code(code, CURLOPT_SEEKDATA); + +	code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, ""); +	check_curl_easy_code(code, CURLOPT_COOKIEFILE); + +	if (gpolicy.mSslCtxCallback) +	{ +		code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback); +		check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION); +		code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, this); +		check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA); +		mCallbackSSLVerify = gpolicy.mSslCtxCallback; +	} + +	long follow_redirect(1L); +	long sslPeerV(0L); +	long sslHostV(0L); +    long dnsCacheTimeout(-1L); +    long nobody(0L); + +	if (mReqOptions) +	{ +		follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L; +		sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L; +		sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L; +		dnsCacheTimeout = mReqOptions->getDNSCacheTimeout(); +        nobody = mReqOptions->getHeadersOnly() ? 1L : 0L; +	} +	code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect); +	check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION); + +	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);  	check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER); -	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0); +	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);  	check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST); +    code = curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody); +    check_curl_easy_code(code, CURLOPT_NOBODY); + +	// The Linksys WRT54G V5 router has an issue with frequent +	// DNS lookups from LAN machines.  If they happen too often, +	// like for every HTTP request, the router gets annoyed after +	// about 700 or so requests and starts issuing TCP RSTs to +	// new connections.  Reuse the DNS lookups for even a few +	// seconds and no RSTs. +	code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout); +	check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT); +  	if (gpolicy.mUseLLProxy)  	{  		// Use the viewer-based thread-safe API which has a @@ -509,10 +596,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  	switch (mReqMethod)  	{  	case HOR_GET: -		code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1); +        if (nobody == 0) +            code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);  		check_curl_easy_code(code, CURLOPT_HTTPGET); -		mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); -		mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		break;  	case HOR_POST: @@ -531,12 +617,14 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  			code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);  			check_curl_easy_code(code, CURLOPT_POSTFIELDSIZE);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); -			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); -			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		}  		break; -	case HOR_PUT: +    case HOR_PATCH: +        code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); +        check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); +        // fall through.  The rest is the same as PUT +    case HOR_PUT:  		{  			code = curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);  			check_curl_easy_code(code, CURLOPT_UPLOAD); @@ -547,15 +635,20 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  			}  			code = curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);  			check_curl_easy_code(code, CURLOPT_INFILESIZE); -			code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL); -			check_curl_easy_code(code, CURLOPT_POSTFIELDS);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); -			// *TODO: Should this be 'Keep-Alive' ? -			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); -			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		}  		break; +    case HOR_DELETE: +        code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); +        check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); +        break; + +    case HOR_COPY: +        code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "COPY"); +        check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST); +        break; +  	default:  		LL_ERRS(LOG_CORE) << "Invalid HTTP method in request:  "  						  << int(mReqMethod)  << ".  Can't recover." @@ -563,6 +656,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  		break;  	} + +    // *TODO: Should this be 'Keep-Alive' ? +    mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive"); +    mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300"); +  	// Tracing  	if (mTracing >= HTTP_TRACE_CURL_HEADERS)  	{ @@ -723,6 +821,37 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void  	return read_size;  } + +int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin) +{ +    HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); + +    if (!op->mReqBody) +    { +        return 0; +    } + +    size_t newPos = 0; +    if (origin == SEEK_SET) +        newPos = offset; +    else if (origin == SEEK_END) +        newPos = static_cast<curl_off_t>(op->mReqBody->size()) + offset; +    else if (origin == SEEK_CUR) +        newPos = static_cast<curl_off_t>(op->mCurlBodyPos) + offset; +    else +        return 2; + +    if (newPos >= op->mReqBody->size()) +    { +        LL_WARNS(LOG_CORE) << "Attempt to seek to position outside post body." << LL_ENDL; +        return 2; +    } + +    op->mCurlBodyPos = (size_t)newPos; + +    return 0; +} +  size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata)  { @@ -873,6 +1002,35 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi  } +CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata) +{ +	HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); + +	if (op->mCallbackSSLVerify) +	{ +		SSL_CTX * ctx = (SSL_CTX *)sslctx; +		// disable any default verification for server certs +		SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); +		// set the verification callback. +		SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata); +		// the calls are void +	} + +	return CURLE_OK; +} + +int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) +{ +	HttpOpRequest * op(static_cast<HttpOpRequest *>(param)); + +	if (op->mCallbackSSLVerify) +	{ +		op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx); +	} + +	return (op->mStatus) ? 1 : 0; +} +  int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)  {  	HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata)); diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h index 2f628b5aba..b1bb101bea 100755 --- a/indra/llcorehttp/_httpoprequest.h +++ b/indra/llcorehttp/_httpoprequest.h @@ -33,6 +33,9 @@  #include <string>  #include <curl/curl.h> +#include <openssl/x509_vfy.h> +#include <openssl/ssl.h> +  #include "httpcommon.h"  #include "httprequest.h"  #include "_httpoperation.h" @@ -77,7 +80,10 @@ public:  	{  		HOR_GET,  		HOR_POST, -		HOR_PUT +		HOR_PUT, +        HOR_DELETE, +        HOR_PATCH, +        HOR_COPY  	};  	virtual void stageFromRequest(HttpService *); @@ -123,7 +129,26 @@ public:  						HttpOptions * options,  						HttpHeaders * headers); -	// Internal method used to setup the libcurl options for a request. +    HttpStatus setupDelete(HttpRequest::policy_t policy_id, +                        HttpRequest::priority_t priority, +                        const std::string & url, +                        HttpOptions * options, +                        HttpHeaders * headers); + +    HttpStatus setupPatch(HttpRequest::policy_t policy_id, +                        HttpRequest::priority_t priority, +                        const std::string & url, +                        BufferArray * body, +                        HttpOptions * options, +                        HttpHeaders * headers); + +    HttpStatus setupCopy(HttpRequest::policy_t policy_id, +                        HttpRequest::priority_t priority, +                        const std::string & url, +                        HttpOptions * options, +                        HttpHeaders * headers); + +    // Internal method used to setup the libcurl options for a request.  	// Does all the libcurl handle setup in one place.  	//  	// Threading:  called by worker thread @@ -150,7 +175,11 @@ protected:  	//  	static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata);  	static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata); +    static int seekCallback(void *data, curl_off_t offset, int origin);  	static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata); +	static CURLcode curlSslCtxCallback(CURL *curl, void *ssl_ctx, void *userptr); +	static int sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param); +  	static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata);  protected: @@ -159,6 +188,8 @@ protected:  	static const unsigned int	PF_SAVE_HEADERS = 0x00000002U;  	static const unsigned int	PF_USE_RETRY_AFTER = 0x00000004U; +	HttpRequest::policyCallback_t	mCallbackSSLVerify; +  public:  	// Request data  	EMethod				mReqMethod; diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp index 1dc95f3dce..3d0df96ade 100755 --- a/indra/llcorehttp/_httppolicyglobal.cpp +++ b/indra/llcorehttp/_httppolicyglobal.cpp @@ -106,6 +106,20 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::stri  	return HttpStatus();  } +HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value) +{ +	switch (opt) +	{ +	case HttpRequest::PO_SSL_VERIFY_CALLBACK: +		mSslCtxCallback = value; +		break; + +	default: +		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); +	} + +	return HttpStatus(); +}  HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const  { @@ -154,4 +168,20 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * v  	return HttpStatus();  } + +HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const +{ +	switch (opt) +	{ +	case HttpRequest::PO_SSL_VERIFY_CALLBACK: +		*value = mSslCtxCallback; +		break; + +	default: +		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG); +	} + +	return HttpStatus(); +} +  }  // end namespace LLCore diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h index 67c4ba9481..e02da4386a 100755 --- a/indra/llcorehttp/_httppolicyglobal.h +++ b/indra/llcorehttp/_httppolicyglobal.h @@ -60,8 +60,10 @@ private:  public:  	HttpStatus set(HttpRequest::EPolicyOption opt, long value);  	HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value); +	HttpStatus set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t value);  	HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;  	HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const; +	HttpStatus get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback_t * value) const;  public:  	long				mConnectionLimit; @@ -70,6 +72,7 @@ public:  	std::string			mHttpProxy;  	long				mTrace;  	long				mUseLLProxy; +	HttpRequest::policyCallback_t	mSslCtxCallback;  };  // end class HttpPolicyGlobal  }  // end namespace LLCore diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index c673e1be1d..252db78c89 100755 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -53,15 +53,16 @@ namespace LLCore  const HttpService::OptionDescriptor HttpService::sOptionDesc[] =  { //    isLong     isDynamic  isGlobal    isClass -	{	true,		true,		true,		true	},		// PO_CONNECTION_LIMIT -	{	true,		true,		false,		true	},		// PO_PER_HOST_CONNECTION_LIMIT -	{	false,		false,		true,		false	},		// PO_CA_PATH -	{	false,		false,		true,		false	},		// PO_CA_FILE -	{	false,		true,		true,		false	},		// PO_HTTP_PROXY -	{	true,		true,		true,		false	},		// PO_LLPROXY -	{	true,		true,		true,		false	},		// PO_TRACE -	{	true,		true,		false,		true	},		// PO_ENABLE_PIPELINING -	{	true,		true,		false,		true	}		// PO_THROTTLE_RATE +	{	true,		true,		true,		true,		false	},		// PO_CONNECTION_LIMIT +	{	true,		true,		false,		true,		false	},		// PO_PER_HOST_CONNECTION_LIMIT +	{	false,		false,		true,		false,		false	},		// PO_CA_PATH +	{	false,		false,		true,		false,		false	},		// PO_CA_FILE +	{	false,		true,		true,		false,		false	},		// PO_HTTP_PROXY +	{	true,		true,		true,		false,		false	},		// PO_LLPROXY +	{	true,		true,		true,		false,		false	},		// PO_TRACE +	{	true,		true,		false,		true,		false	},		// PO_ENABLE_PIPELINING +	{	true,		true,		false,		true,		false	},		// PO_THROTTLE_RATE +	{   false,		false,		true,		false,		true	}		// PO_SSL_VERIFY_CALLBACK  };  HttpService * HttpService::sInstance(NULL);  volatile HttpService::EState HttpService::sState(NOT_INITIALIZED); @@ -413,6 +414,34 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ  	return status;  } +HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, +	HttpRequest::policyCallback_t * ret_value) +{ +	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG); + +	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range +		|| opt >= HttpRequest::PO_LAST													// ditto +		|| (sOptionDesc[opt].mIsLong)													// datatype is string +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range +		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal)	// global setting permitted +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass))	// class setting permitted +		// can always get, no dynamic check +	{ +		return status; +	} + +	// Only global has callback values +	if (pclass == HttpRequest::GLOBAL_POLICY_ID) +	{ +		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); + +		status = opts.get(opt, ret_value); +	} + +	return status; +} + +  HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,  										long value, long * ret_value) @@ -489,6 +518,37 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ  	return status;  } -	 + +HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass, +	HttpRequest::policyCallback_t value, HttpRequest::policyCallback_t * ret_value) +{ +	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG); + +	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range +		|| opt >= HttpRequest::PO_LAST													// ditto +		|| (sOptionDesc[opt].mIsLong)													// datatype is string +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range +		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal)	// global setting permitted +		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass)		// class setting permitted +		|| (RUNNING == sState && !sOptionDesc[opt].mIsDynamic))						// dynamic setting permitted +	{ +		return status; +	} + +	// Callbacks values are always global (at this time). +	if (pclass == HttpRequest::GLOBAL_POLICY_ID) +	{ +		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions()); + +		status = opts.set(opt, value); +		if (status && ret_value) +		{ +			status = opts.get(opt, ret_value); +		} +	} + +	return status; +} +  }  // end namespace LLCore diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h index cf23f3ab61..ac518a5de7 100755 --- a/indra/llcorehttp/_httpservice.h +++ b/indra/llcorehttp/_httpservice.h @@ -201,17 +201,24 @@ protected:  		bool		mIsDynamic;  		bool		mIsGlobal;  		bool		mIsClass; +		bool		mIsCallback;  	};  	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,  							   long * ret_value);  	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,  							   std::string * ret_value); +	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, +								HttpRequest::policyCallback_t * ret_value); +  	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,  							   long value, long * ret_value);  	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,  							   const std::string & value, std::string * ret_value); -	 +	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t, +								HttpRequest::policyCallback_t value,  +								HttpRequest::policyCallback_t * ret_value); +  protected:  	static const OptionDescriptor		sOptionDesc[HttpRequest::PO_LAST];  	static HttpService *				sInstance; diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h index 402e725152..7f713f2298 100755 --- a/indra/llcorehttp/_refcounted.h +++ b/indra/llcorehttp/_refcounted.h @@ -32,6 +32,7 @@  #include "fix_macros.h"  #include <boost/thread.hpp> +#include <boost/intrusive_ptr.hpp>  #include "llapr.h" @@ -120,7 +121,36 @@ inline void RefCounted::destroySelf()  	delete this;  } +/** + * boost::intrusive_ptr may be used to manage RefCounted classes. + * Unfortunately RefCounted and boost::intrusive_ptr use different conventions + * for the initial refcount value. To avoid leaky (immortal) objects, you + * should really construct boost::intrusive_ptr<RefCounted*>(rawptr, false). + * IntrusivePtr<T> encapsulates that for you. + */ +template <typename T> +struct IntrusivePtr: public boost::intrusive_ptr<T> +{ +	IntrusivePtr(): +		boost::intrusive_ptr<T>() +	{} +	IntrusivePtr(T* p): +		boost::intrusive_ptr<T>(p, false) +	{} +}; + +inline void intrusive_ptr_add_ref(RefCounted* p) +{ +	p->addRef(); +} + +inline void intrusive_ptr_release(RefCounted* p) +{ +	p->release(); +} +  } // end namespace LLCoreInt +  #endif	// LLCOREINT__REFCOUNTED_H_ diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h index 1094a435b4..320adf2b8b 100755 --- a/indra/llcorehttp/bufferarray.h +++ b/indra/llcorehttp/bufferarray.h @@ -30,6 +30,7 @@  #include <cstdlib>  #include <vector> +#include "boost/intrusive_ptr.hpp"  #include "_refcounted.h" @@ -73,6 +74,8 @@ public:  	BufferArray(); +	typedef LLCoreInt::IntrusivePtr<BufferArray> ptr_t; +  protected:  	virtual ~BufferArray();						// Use release() @@ -129,6 +132,7 @@ protected:  	container_t			mBlocks;  	size_t				mLen; +  };  // end class BufferArray diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 7907e958a4..99238ea920 100755 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -42,7 +42,7 @@ HttpStatus::operator unsigned long() const  {  	static const int shift(sizeof(unsigned long) * 4); -	unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus); +	unsigned long result(((unsigned long)mDetails->mType) << shift | (unsigned long)(int)mDetails->mStatus);  	return result;  } @@ -131,30 +131,34 @@ std::string HttpStatus::toString() const  	{  		return std::string("");  	} -	switch (mType) +	switch (getType())  	{  	case EXT_CURL_EASY: -		return std::string(curl_easy_strerror(CURLcode(mStatus))); +		return std::string(curl_easy_strerror(CURLcode(getStatus())));  	case EXT_CURL_MULTI: -		return std::string(curl_multi_strerror(CURLMcode(mStatus))); +		return std::string(curl_multi_strerror(CURLMcode(getStatus())));  	case LLCORE: -		if (mStatus >= 0 && mStatus < llcore_errors_count) +		if (getStatus() >= 0 && getStatus() < llcore_errors_count)  		{ -			return std::string(llcore_errors[mStatus]); +			return std::string(llcore_errors[getStatus()]);  		}  		break;  	default:  		if (isHttpStatus())  		{ +			// special handling for status 499 "Linden Catchall" +			if ((getType() == 499) && (!getMessage().empty())) +				return getMessage(); +  			// Binary search for the error code and string  			int bottom(0), top(http_errors_count);  			while (true)  			{  				int at((bottom + top) / 2); -				if (mType == http_errors[at].mCode) +				if (getType() == http_errors[at].mCode)  				{  					return std::string(http_errors[at].mText);  				} @@ -162,7 +166,7 @@ std::string HttpStatus::toString() const  				{  					break;  				} -				else if (mType < http_errors[at].mCode) +				else if (getType() < http_errors[at].mCode)  				{  					top = at;  				} @@ -182,9 +186,9 @@ std::string HttpStatus::toTerseString() const  {  	std::ostringstream result; -	unsigned int error_value((unsigned short) mStatus); +	unsigned int error_value((unsigned short)getStatus()); -	switch (mType) +	switch (getType())  	{  	case EXT_CURL_EASY:  		result << "Easy_"; @@ -202,7 +206,7 @@ std::string HttpStatus::toTerseString() const  		if (isHttpStatus())  		{  			result << "Http_"; -			error_value = mType; +			error_value = getType();  		}  		else  		{ @@ -244,7 +248,7 @@ bool HttpStatus::isRetryable() const  	// Disable the '*this == inv_status' test and look for 'Core_9'  	// failures in log files. -	return ((isHttpStatus() && mType >= 499 && mType <= 599) ||	// Include special 499 in retryables +	return ((isHttpStatus() && getType() >= 499 && getType() <= 599) ||	// Include special 499 in retryables  			*this == cant_connect ||	// Connection reset/endpoint problems  			*this == cant_res_proxy ||	// DNS problems  			*this == cant_res_host ||	// DNS problems diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index 9601f94125..898d3d47fa 100755 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -188,10 +188,12 @@  ///  #include "linden_common.h"		// Modifies curl/curl.h interfaces - +#include "boost/intrusive_ptr.hpp" +#include "boost/shared_ptr.hpp" +#include "boost/weak_ptr.hpp" +#include "boost/function.hpp"  #include <string> -  namespace LLCore  { @@ -286,52 +288,63 @@ enum HttpError  /// 5.  Construct an HTTP 301 status code to be treated as success:  ///				HttpStatus(301, HE_SUCCESS);  /// +/// 6.	Construct a failed status of HTTP Status 499 with a custom error message +///				HttpStatus(499, "Failed LLSD Response");  struct HttpStatus  {  	typedef unsigned short type_enum_t;  	HttpStatus() -		: mType(LLCORE), -		  mStatus(HE_SUCCESS) -		{} +	{ +		mDetails = boost::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS)); +    }  	HttpStatus(type_enum_t type, short status) -		: mType(type), -		  mStatus(status) -		{} +	{ +        mDetails = boost::shared_ptr<Details>(new Details(type, status)); +	}  	HttpStatus(int http_status) -		: mType(http_status), -		  mStatus(http_status >= 200 && http_status <= 299 -				  ? HE_SUCCESS -				  : HE_REPLY_ERROR) -		{ -			llassert(http_status >= 100 && http_status <= 999); -		} +	{ +        mDetails = boost::shared_ptr<Details>(new Details(http_status,  +			(http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); +		llassert(http_status >= 100 && http_status <= 999); +	} + +	HttpStatus(int http_status, const std::string &message) +	{ +        mDetails = boost::shared_ptr<Details>(new Details(http_status, +			(http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); +		llassert(http_status >= 100 && http_status <= 999); +		mDetails->mMessage = message; +	}  	HttpStatus(const HttpStatus & rhs) -		: mType(rhs.mType), -		  mStatus(rhs.mStatus) -		{} +	{ +		mDetails = rhs.mDetails; +	} + +	~HttpStatus() +	{ +	}  	HttpStatus & operator=(const HttpStatus & rhs) -		{ -			// Don't care if lhs & rhs are the same object +	{ +        mDetails = rhs.mDetails; +		return *this; +	} -			mType = rhs.mType; -			mStatus = rhs.mStatus; -			return *this; -		} +    HttpStatus & clone(const HttpStatus &rhs) +    { +        mDetails = boost::shared_ptr<Details>(new Details(*rhs.mDetails)); +        return *this; +    }  	static const type_enum_t EXT_CURL_EASY = 0;			///< mStatus is an error from a curl_easy_*() call  	static const type_enum_t EXT_CURL_MULTI = 1;		///< mStatus is an error from a curl_multi_*() call  	static const type_enum_t LLCORE = 2;				///< mStatus is an HE_* error code  														///< 100-999 directly represent HTTP status codes -	 -	type_enum_t			mType; -	short				mStatus; -  	/// Test for successful status in the code regardless  	/// of error source (internal, libcurl).  	/// @@ -339,7 +352,7 @@ struct HttpStatus  	///  	operator bool() const  	{ -		return 0 == mStatus; +		return 0 == mDetails->mStatus;  	}  	/// Inverse of previous operator. @@ -347,14 +360,14 @@ struct HttpStatus  	/// @return			'true' on any error condition  	bool operator !() const  	{ -		return 0 != mStatus; +		return 0 != mDetails->mStatus;  	}  	/// Equality and inequality tests to bypass bool conversion  	/// which will do the wrong thing in conditional expressions.  	bool operator==(const HttpStatus & rhs) const  	{ -		return mType == rhs.mType && mStatus == rhs.mStatus; +        return (*mDetails == *rhs.mDetails);   	}  	bool operator!=(const HttpStatus & rhs) const @@ -395,7 +408,7 @@ struct HttpStatus  	/// HTTP response status (100 - 999).  	bool isHttpStatus() const  	{ -		return 	mType >= type_enum_t(100) && mType <= type_enum_t(999); +		return 	mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999);  	}  	/// Returns true if the status is one that will be retried @@ -403,7 +416,78 @@ struct HttpStatus  	/// where that logic needs to be replicated.  Only applies  	/// to failed statuses, successful statuses will return false.  	bool isRetryable() const; -	 + +	/// Returns the currently set status code as a raw number +	/// +	short getStatus() const +	{ +		return mDetails->mStatus; +	} + +	/// Returns the currently set status type  +	///  +	type_enum_t getType() const +	{ +		return mDetails->mType; +	} + +	/// Returns an optional error message if one has been set. +	/// +	std::string getMessage() const +	{ +		return mDetails->mMessage; +	} + +	/// Sets an optional error message +	///  +	void setMessage(const std::string &message) +	{ +		mDetails->mMessage = message; +	} + +	/// Retrieves an optionally recorded SSL certificate. +	void * getErrorData() const +	{ +		return mDetails->mErrorData; +	} + +	/// Optionally sets an SSL certificate on this status. +	void setErrorData(void *data) +	{ +		mDetails->mErrorData = data; +	} + +private: + +	struct Details +	{ +		Details(type_enum_t type, short status): +			mType(type), +			mStatus(status), +			mMessage(), +			mErrorData(NULL) +		{} + +		Details(const Details &rhs) : +			mType(rhs.mType), +			mStatus(rhs.mStatus), +			mMessage(rhs.mMessage), +			mErrorData(rhs.mErrorData) +		{} + +        bool operator == (const Details &rhs) const +        { +            return (mType == rhs.mType) && (mStatus == rhs.mStatus); +        } + +		type_enum_t	mType; +		short		mStatus; +		std::string	mMessage; +		void *		mErrorData; +	}; + +    boost::shared_ptr<Details> mDetails; +  }; // end struct HttpStatus  }  // end namespace LLCore diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h index 9171e4e7b9..7bc9096703 100755 --- a/indra/llcorehttp/httphandler.h +++ b/indra/llcorehttp/httphandler.h @@ -45,7 +45,7 @@ class HttpResponse;  /// be shared by any number of requests and across instances  /// of HttpRequest running in the same thread.  /// -/// Threading:  HttpHandler itself is pure interface and is +/// Threading:  HttpHandler itself is interface and is  /// tread-compatible.  Most derivations, however, will have  /// different constraints.  /// @@ -53,12 +53,13 @@ class HttpResponse;  /// that is rarely a good idea.  Queued requests and replies keep  /// a naked pointer to the handler and this can result in a  /// dangling pointer if lifetimes aren't managed correctly. - -class HttpHandler +/// +/// *TODO: public std::enable_shared_from_this<HttpHandler> +class HttpHandler   {  public:  	virtual ~HttpHandler() -		{} +	{ }  	/// Method invoked during calls to @see update().  Each invocation  	/// represents the completion of some requested operation.  Caller diff --git a/indra/llcorehttp/httpheaders.cpp b/indra/llcorehttp/httpheaders.cpp index 23ebea361c..e03b1b080d 100755 --- a/indra/llcorehttp/httpheaders.cpp +++ b/indra/llcorehttp/httpheaders.cpp @@ -105,7 +105,7 @@ void HttpHeaders::appendNormal(const char * header, size_t size)  // Find from end to simulate a tradition of using single-valued  // std::map for this in the past. -const std::string * HttpHeaders::find(const char * name) const +const std::string * HttpHeaders::find(const std::string &name) const  {  	const_reverse_iterator iend(rend());  	for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) @@ -118,6 +118,24 @@ const std::string * HttpHeaders::find(const char * name) const  	return NULL;  } +void HttpHeaders::remove(const char *name) +{ +    remove(std::string(name)); +} + +void HttpHeaders::remove(const std::string &name) +{ +    iterator iend(end()); +    for (iterator iter(begin()); iend != iter; ++iter) +    { +        if ((*iter).first == name) +        { +            mHeaders.erase(iter); +            return; +        } +    } +} +  // Standard Iterators  HttpHeaders::iterator HttpHeaders::begin() diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index f70cd898f3..8f14568fa3 100755 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -28,8 +28,8 @@  #define	_LLCORE_HTTP_HEADERS_H_ +#include "httpcommon.h"  #include <string> -  #include "_refcounted.h" @@ -92,6 +92,7 @@ public:  	/// the instance.  	HttpHeaders(); +	typedef LLCoreInt::IntrusivePtr<HttpHeaders> ptr_t;  protected:  	virtual ~HttpHeaders();						// Use release() @@ -145,8 +146,16 @@ public:  	//					a pointer to a std::string in the container.  	//					Pointer is valid only for the lifetime of  	//					the container or until container is modifed. -	// -	const std::string * find(const char * name) const; +	const std::string * find(const std::string &name) const; +	const std::string * find(const char * name) const +	{ +		return find(std::string(name)); +	} + +    // Remove the header from the list if found. +    //  +    void remove(const std::string &name); +    void remove(const char *name);  	// Count of headers currently in the list.  	size_type size() const diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index 5bf1ecb4a5..3459a37aff 100755 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -25,7 +25,7 @@   */  #include "httpoptions.h" - +#include "lldefs.h"  #include "_httpinternal.h" @@ -33,14 +33,18 @@ namespace LLCore  { -HttpOptions::HttpOptions() -	: RefCounted(true), -	  mWantHeaders(false), -	  mTracing(HTTP_TRACE_OFF), -	  mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT), -	  mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT), -	  mRetries(HTTP_RETRY_COUNT_DEFAULT), -	  mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT) +HttpOptions::HttpOptions() : RefCounted(true), +    mWantHeaders(false), +    mTracing(HTTP_TRACE_OFF), +    mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT), +    mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT), +    mRetries(HTTP_RETRY_COUNT_DEFAULT), +    mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT), +    mFollowRedirects(true), +    mVerifyPeer(false), +    mVerifyHost(false), +    mDNSCacheTimeout(-1L), +    mNoBody(false)  {} @@ -82,5 +86,31 @@ void HttpOptions::setUseRetryAfter(bool use_retry)  	mUseRetryAfter = use_retry;  } +void HttpOptions::setFollowRedirects(bool follow_redirect) +{ +	mFollowRedirects = follow_redirect; +} + +void HttpOptions::setSSLVerifyPeer(bool verify) +{ +	mVerifyPeer = verify; +} + +void HttpOptions::setSSLVerifyHost(bool verify) +{ +	mVerifyHost = verify; +} + +void HttpOptions::setDNSCacheTimeout(int timeout) +{ +	mDNSCacheTimeout = timeout; +} + +void HttpOptions::setHeadersOnly(bool nobody) +{ +    mNoBody = nobody; +    if (mNoBody) +        setWantHeaders(true); +}  }   // end namespace LLCore diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 4ab5ff18c4..2fe05a65ff 100755 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -29,7 +29,6 @@  #include "httpcommon.h" -  #include "_refcounted.h" @@ -61,6 +60,8 @@ class HttpOptions : public LLCoreInt::RefCounted  public:  	HttpOptions(); +	typedef LLCoreInt::IntrusivePtr<HttpOptions> ptr_t; +  protected:  	virtual ~HttpOptions();						// Use release() @@ -68,47 +69,95 @@ protected:  	void operator=(const HttpOptions &);		// Not defined  public: +  	// Default:   false  	void				setWantHeaders(bool wanted);  	bool				getWantHeaders() const -		{ -			return mWantHeaders; -		} +	{ +		return mWantHeaders; +	}  	// Default:  0  	void				setTrace(int long);  	int					getTrace() const -		{ -			return mTracing; -		} +	{ +		return mTracing; +	}  	// Default:  30  	void				setTimeout(unsigned int timeout);  	unsigned int		getTimeout() const -		{ -			return mTimeout; -		} +	{ +		return mTimeout; +	}  	// Default:  0  	void				setTransferTimeout(unsigned int timeout);  	unsigned int		getTransferTimeout() const -		{ -			return mTransferTimeout; -		} +	{ +		return mTransferTimeout; +	} +    /// Sets the number of retries on an LLCore::HTTPRequest before the  +    /// request fails.  	// Default:  8  	void				setRetries(unsigned int retries);  	unsigned int		getRetries() const -		{ -			return mRetries; -		} +	{ +		return mRetries; +	}  	// Default:  true  	void				setUseRetryAfter(bool use_retry);  	bool				getUseRetryAfter() const -		{ -			return mUseRetryAfter; -		} +	{ +		return mUseRetryAfter; +	} + +    /// Instructs the LLCore::HTTPRequest to follow redirects  +	/// Default: false +	void				setFollowRedirects(bool follow_redirect); +	bool				getFollowRedirects() const +	{ +		return mFollowRedirects; +	} + +    /// Instructs the LLCore::HTTPRequest to verify that the exchanged security +    /// certificate is authentic.  +    /// Default: false +    void				setSSLVerifyPeer(bool verify); +	bool				getSSLVerifyPeer() const +	{ +		return mVerifyPeer; +	} + +    /// Instructs the LLCore::HTTPRequest to verify that the name in the  +    /// security certificate matches the name of the host contacted. +    /// Default: false +    void				setSSLVerifyHost(bool verify); +	bool	        	getSSLVerifyHost() const +	{ +		return mVerifyHost; +	} + +    /// Sets the time for DNS name caching in seconds.  Setting this value +    /// to 0 will disable name caching.  Setting this value to -1 causes the  +    /// name cache to never time out. +    /// Default: -1 +	void				setDNSCacheTimeout(int timeout); +	int					getDNSCacheTimeout() const +	{ +		return mDNSCacheTimeout; +	} + +    /// Retrieve only the headers and status from the request. Setting this  +    /// to true implies setWantHeaders(true) as well. +    /// Default: false +    void                setHeadersOnly(bool nobody); +    bool                getHeadersOnly() const +    { +        return mNoBody; +    }  protected:  	bool				mWantHeaders; @@ -117,6 +166,11 @@ protected:  	unsigned int		mTransferTimeout;  	unsigned int		mRetries;  	bool				mUseRetryAfter; +	bool				mFollowRedirects; +	bool				mVerifyPeer; +	bool        		mVerifyHost; +	int					mDNSCacheTimeout; +    bool                mNoBody;  }; // end class HttpOptions diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp index 7b1888e3eb..d4c60a6f14 100755 --- a/indra/llcorehttp/httprequest.cpp +++ b/indra/llcorehttp/httprequest.cpp @@ -117,6 +117,15 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass  	return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);  } +HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback_t value, policyCallback_t * ret_value) +{ +	if (HttpService::RUNNING == HttpService::instanceOf()->getState()) +	{ +		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC); +	} + +	return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value); +}  HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,  										long value, HttpHandler * handler) @@ -316,6 +325,100 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,  	return handle;  } +HttpHandle HttpRequest::requestDelete(policy_t policy_id, +    priority_t priority, +    const std::string & url, +    HttpOptions * options, +    HttpHeaders * headers, +    HttpHandler * user_handler) +{ +    HttpStatus status; +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    HttpOpRequest * op = new HttpOpRequest(); +    if (!(status = op->setupDelete(policy_id, priority, url, options, headers))) +    { +        op->release(); +        mLastReqStatus = status; +        return handle; +    } +    op->setReplyPath(mReplyQueue, user_handler); +    if (!(status = mRequestQueue->addOp(op)))			// transfers refcount +    { +        op->release(); +        mLastReqStatus = status; +        return handle; +    } + +    mLastReqStatus = status; +    handle = static_cast<HttpHandle>(op); + +    return handle; +} + +HttpHandle HttpRequest::requestPatch(policy_t policy_id, +    priority_t priority, +    const std::string & url, +    BufferArray * body, +    HttpOptions * options, +    HttpHeaders * headers, +    HttpHandler * user_handler) +{ +    HttpStatus status; +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    HttpOpRequest * op = new HttpOpRequest(); +    if (!(status = op->setupPatch(policy_id, priority, url, body, options, headers))) +    { +        op->release(); +        mLastReqStatus = status; +        return handle; +    } +    op->setReplyPath(mReplyQueue, user_handler); +    if (!(status = mRequestQueue->addOp(op)))			// transfers refcount +    { +        op->release(); +        mLastReqStatus = status; +        return handle; +    } + +    mLastReqStatus = status; +    handle = static_cast<HttpHandle>(op); + +    return handle; +} + +HttpHandle HttpRequest::requestCopy(policy_t policy_id, +    priority_t priority, +    const std::string & url, +    HttpOptions * options, +    HttpHeaders * headers, +    HttpHandler * user_handler) +{ +    HttpStatus status; +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    HttpOpRequest * op = new HttpOpRequest(); +    if (!(status = op->setupCopy(policy_id, priority, url, options, headers))) +    { +        op->release(); +        mLastReqStatus = status; +        return handle; +    } +    op->setReplyPath(mReplyQueue, user_handler); +    if (!(status = mRequestQueue->addOp(op)))			// transfers refcount +    { +        op->release(); +        mLastReqStatus = status; +        return handle; +    } + +    mLastReqStatus = status; +    handle = static_cast<HttpHandle>(op); + +    return handle; +} +  HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)  { diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index 7f23723b0b..e87a8b691a 100755 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -97,6 +97,8 @@ public:  	typedef unsigned int policy_t;  	typedef unsigned int priority_t; +	typedef boost::shared_ptr<HttpRequest> ptr_t; +    typedef boost::weak_ptr<HttpRequest>   wptr_t;  public:  	/// @name PolicyMethods  	/// @{ @@ -163,7 +165,7 @@ public:  		/// Long value that if non-zero enables the use of the  		/// traditional LLProxy code for http/socks5 support.  If -		// enabled, has priority over GP_HTTP_PROXY. +		/// enabled, has priority over GP_HTTP_PROXY.  		///  		/// Global only  		PO_LLPROXY, @@ -219,15 +221,25 @@ public:  		/// Controls whether client-side throttling should be  		/// performed on this policy class.  Positive values  		/// enable throttling and specify the request rate -		/// (requests per second) that should be targetted. +		/// (requests per second) that should be targeted.  		/// A value of zero, the default, specifies no throttling.  		///  		/// Per-class only  		PO_THROTTLE_RATE, +		/// Controls the callback function used to control SSL CTX  +		/// certificate verification. +		/// +		/// Global only +		PO_SSL_VERIFY_CALLBACK, +  		PO_LAST  // Always at end  	}; +	/// Prototype for policy based callbacks.  The callback methods will be executed +	/// on the worker thread so no modifications should be made to the HttpHandler object. +    typedef boost::function<HttpStatus(const std::string &, HttpHandler const * const, void *)> policyCallback_t; +  	/// Set a policy option for a global or class parameter at  	/// startup time (prior to thread start).  	/// @@ -243,6 +255,8 @@ public:  											long value, long * ret_value);  	static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,  											const std::string & value, std::string * ret_value); +	static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass, +											policyCallback_t value, policyCallback_t * ret_value);;  	/// Set a parameter on a class-based policy option.  Calls  	/// made after the start of the servicing thread are @@ -464,7 +478,68 @@ public:  						  HttpHandler * handler); -	/// Queue a NoOp request. +    /// Queue a full HTTP PUT.  Query arguments and body may +    /// be provided.  Caller is responsible for escaping and +    /// encoding and communicating the content types. +    /// +    /// @param	policy_id		@see requestGet() +    /// @param	priority		" +    /// @param	url				" +    /// @param	options			@see requestGet()K(optional) +    /// @param	headers			" +    /// @param	handler			" +    /// @return					" +    /// +    HttpHandle requestDelete(policy_t policy_id, +            priority_t priority, +            const std::string & url, +            HttpOptions * options, +            HttpHeaders * headers, +            HttpHandler * user_handler); + +    /// Queue a full HTTP PUT.  Query arguments and body may +    /// be provided.  Caller is responsible for escaping and +    /// encoding and communicating the content types. +    /// +    /// @param	policy_id		@see requestGet() +    /// @param	priority		" +    /// @param	url				" +    /// @param	body			Byte stream to be sent as the body.  No +    ///							further encoding or escaping will be done +    ///							to the content. +    /// @param	options			@see requestGet()K(optional) +    /// @param	headers			" +    /// @param	handler			" +    /// @return					" +    /// +    HttpHandle requestPatch(policy_t policy_id, +            priority_t priority, +            const std::string & url, +            BufferArray * body, +            HttpOptions * options, +            HttpHeaders * headers, +            HttpHandler * user_handler); + +    /// Queue a full HTTP PUT.  Query arguments and body may +    /// be provided.  Caller is responsible for escaping and +    /// encoding and communicating the content types. +    /// +    /// @param	policy_id		@see requestGet() +    /// @param	priority		" +    /// @param	url				" +    /// @param	options			@see requestGet()K(optional) +    /// @param	headers			" +    /// @param	handler			" +    /// @return					" +    /// +    HttpHandle requestCopy(policy_t policy_id, +            priority_t priority, +            const std::string & url, +            HttpOptions * options, +            HttpHeaders * headers, +            HttpHandler * user_handler); +        +    /// Queue a NoOp request.  	/// The request is queued and serviced by the working thread which  	/// immediately processes it and returns the request to the reply  	/// queue. diff --git a/indra/llcorehttp/httpresponse.cpp b/indra/llcorehttp/httpresponse.cpp index c974395b0a..7d88f02527 100755 --- a/indra/llcorehttp/httpresponse.cpp +++ b/indra/llcorehttp/httpresponse.cpp @@ -41,7 +41,8 @@ HttpResponse::HttpResponse()  	  mBufferArray(NULL),  	  mHeaders(NULL),  	  mRetries(0U), -	  m503Retries(0U) +	  m503Retries(0U), +      mRequestUrl()  {} @@ -89,5 +90,9 @@ void HttpResponse::setHeaders(HttpHeaders * headers)  	mHeaders = headers;  } +size_t HttpResponse::getBodySize() const +{ +	return (mBufferArray) ? mBufferArray->size() : 0; +}  }   // end namespace LLCore diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h index aee64e2878..6c3b4da5e6 100755 --- a/indra/llcorehttp/httpresponse.h +++ b/indra/llcorehttp/httpresponse.h @@ -69,6 +69,18 @@ protected:  	void operator=(const HttpResponse &);				// Not defined  public: +	/// Statistics for the HTTP  +	struct TransferStats +	{ +		typedef boost::shared_ptr<TransferStats> ptr_t; + +		TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {} +		F64 mSizeDownload; +		F64 mTotalTime; +		F64 mSpeedDownload; +	}; + +  	/// Returns the final status of the requested operation.  	///  	HttpStatus getStatus() const @@ -92,6 +104,10 @@ public:  			return mBufferArray;  		} +	/// Safely get the size of the body buffer.  If the body buffer is missing +	/// return 0 as the size. +	size_t getBodySize() const; +  	/// Set the response data in the instance.  Will drop the reference  	/// count to any existing data and increment the count of that passed  	/// in.  It is legal to set the data to NULL. @@ -168,6 +184,27 @@ public:  			m503Retries = retries_503;  		} +	void setTransferStats(TransferStats::ptr_t &stats)  +		{ +			mStats = stats; +		} + +	TransferStats::ptr_t getTransferStats() +		{ +			return mStats; +		} + +    void setRequestURL(const std::string &url) +        { +            mRequestUrl = url; +        } + +    const std::string &getRequestURL() const +        { +            return mRequestUrl; +        } + +  protected:  	// Response data here  	HttpStatus			mStatus; @@ -179,6 +216,9 @@ protected:  	std::string			mContentType;  	unsigned int		mRetries;  	unsigned int		m503Retries; +    std::string         mRequestUrl; + +	TransferStats::ptr_t	mStats;  }; diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp index 0b379836c9..4502d32fe1 100755 --- a/indra/llcorehttp/tests/test_httpstatus.hpp +++ b/indra/llcorehttp/tests/test_httpstatus.hpp @@ -55,77 +55,68 @@ void HttpStatusTestObjectType::test<1>()  	// auto allocation fine for this  	HttpStatus status; -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = 0; + +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);  	ensure(bool(status));  	ensure(false == !(status)); -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = 0; +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0);  	ensure(bool(status));  	ensure(false == !(status)); -	 -	status.mType = HttpStatus::LLCORE; -	status.mStatus = HE_SUCCESS; + +	status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS);  	ensure(bool(status));  	ensure(false == !(status)); -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = -1; +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1);  	ensure(false == bool(status));  	ensure(!(status)); -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = CURLE_BAD_DOWNLOAD_RESUME; +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_DOWNLOAD_RESUME);  	ensure(false == bool(status));  	ensure(!(status));  } -template <> template <> -void HttpStatusTestObjectType::test<2>() -{ -	set_test_name("HttpStatus memory structure"); - -	// Require that an HttpStatus object can be trivially -	// returned as a function return value in registers. -	// One should fit in an int on all platforms. - -	ensure(sizeof(HttpStatus) <= sizeof(int)); -} +// template <> template <> +// void HttpStatusTestObjectType::test<2>() +// { +// 	set_test_name("HttpStatus memory structure"); +//  +// 	// Require that an HttpStatus object can be trivially +// 	// returned as a function return value in registers. +// 	// One should fit in an int on all platforms. +//  +// 	//ensure(sizeof(HttpStatus) <= sizeof(int)); +// }  template <> template <> -void HttpStatusTestObjectType::test<3>() +void HttpStatusTestObjectType::test<2>()  {  	set_test_name("HttpStatus valid status string conversion"); -	HttpStatus status; -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = 0; +	HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);  	std::string msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(msg.empty()); -	 -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT; + +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = CURLM_OUT_OF_MEMORY; +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	status.mType = HttpStatus::LLCORE; -	status.mStatus = HE_SHUTTING_DOWN; +	status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); @@ -133,32 +124,28 @@ void HttpStatusTestObjectType::test<3>()  template <> template <> -void HttpStatusTestObjectType::test<4>() +void HttpStatusTestObjectType::test<3>()  {  	set_test_name("HttpStatus invalid status string conversion"); -	HttpStatus status; -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = 32726; +	HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726);  	std::string msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	 -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = -470; + +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	status.mType = HttpStatus::LLCORE; -	status.mStatus = 923; +	status = HttpStatus(HttpStatus::LLCORE, 923);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty());  }  template <> template <> -void HttpStatusTestObjectType::test<5>() +void HttpStatusTestObjectType::test<4>()  {  	set_test_name("HttpStatus equality/inequality testing"); @@ -170,62 +157,55 @@ void HttpStatusTestObjectType::test<5>()  	HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);  	ensure(status1 != status2); -	status1.mType = HttpStatus::LLCORE; -	status1.mStatus = HE_REPLY_ERROR; -	status2.mType = HttpStatus::LLCORE; -	status2.mStatus= HE_SHUTTING_DOWN; +	status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR); +	status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); +  	ensure(status1 != status2);  }  template <> template <> -void HttpStatusTestObjectType::test<6>() +void HttpStatusTestObjectType::test<5>()  {  	set_test_name("HttpStatus basic HTTP status encoding");  	HttpStatus status; -	status.mType = 200; -	status.mStatus = HE_SUCCESS; + +	status = HttpStatus(200, HE_SUCCESS);  	std::string msg = status.toString();  	ensure(msg.empty());  	ensure(bool(status));  	// Normally a success but application says error -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(200, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(! msg.empty());  	ensure(! bool(status));  	ensure(status.toULong() > 1UL);				// Biggish number, not a bool-to-ulong  	// Same statuses with distinct success/fail are distinct -	status.mType = 200; -	status.mStatus = HE_SUCCESS; +	status = HttpStatus(200, HE_SUCCESS);  	HttpStatus status2(200, HE_REPLY_ERROR);  	ensure(status != status2);  	// Normally an error but application says okay -	status.mType = 406; -	status.mStatus = HE_SUCCESS; +	status = HttpStatus(406, HE_SUCCESS);  	msg = status.toString();  	ensure(msg.empty());  	ensure(bool(status));  	// Different statuses but both successful are distinct -	status.mType = 200; -	status.mStatus = HE_SUCCESS; -	status2.mType = 201; -	status2.mStatus = HE_SUCCESS; +	status = HttpStatus(200, HE_SUCCESS); +	status2 = HttpStatus(201, HE_SUCCESS);  	ensure(status != status2);  	// Different statuses but both failed are distinct -	status.mType = 200; -	status.mStatus = HE_REPLY_ERROR; -	status2.mType = 201; -	status2.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(200, HE_REPLY_ERROR); +	status2 = HttpStatus(201, HE_REPLY_ERROR);  	ensure(status != status2);  }  template <> template <> -void HttpStatusTestObjectType::test<7>() +void HttpStatusTestObjectType::test<6>()  {  	set_test_name("HttpStatus HTTP status text strings"); @@ -234,34 +214,30 @@ void HttpStatusTestObjectType::test<7>()  	ensure(! msg.empty());				// Should be something  	ensure(msg == "Continue"); -	status.mStatus = HE_SUCCESS; +	status = HttpStatus(200, HE_SUCCESS);  	msg = status.toString();  	ensure(msg.empty());				// Success is empty -	status.mType = 199; -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(199, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "Unknown error"); -	status.mType = 505;					// Last defined string -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(505, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "HTTP Version not supported"); -	status.mType = 506;					// One beyond -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(506, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "Unknown error"); -	status.mType = 999;					// Last HTTP status -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(999, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "Unknown error");  }  template <> template <> -void HttpStatusTestObjectType::test<8>() +void HttpStatusTestObjectType::test<7>()  {  	set_test_name("HttpStatus toHex() nominal function"); @@ -273,7 +249,7 @@ void HttpStatusTestObjectType::test<8>()  template <> template <> -void HttpStatusTestObjectType::test<9>() +void HttpStatusTestObjectType::test<8>()  {  	set_test_name("HttpStatus toTerseString() nominal function"); diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt index ba4e34d92b..da23b46b7b 100755 --- a/indra/llcrashlogger/CMakeLists.txt +++ b/indra/llcrashlogger/CMakeLists.txt @@ -3,6 +3,7 @@  project(llcrashlogger)  include(00-Common) +include(LLCoreHttp)  include(LLCommon)  include(LLMath)  include(LLMessage) @@ -10,6 +11,7 @@ include(LLVFS)  include(LLXML)  include_directories( +    ${LLCOREHTTP_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS}      ${LLMESSAGE_INCLUDE_DIRS} diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 7a97c16ea7..cb05c4ff03 100755 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -40,38 +40,45 @@  #include "lldir.h"  #include "llfile.h"  #include "llsdserialize.h" -#include "lliopipe.h" -#include "llpumpio.h" -#include "llhttpclient.h"  #include "llsdserialize.h"  #include "llproxy.h" -  -LLPumpIO* gServicePump = NULL; +#include "llcorehttputil.h" +#include "llhttpsdhandler.h" +#include "httpcommon.h" +#include "httpresponse.h" + +#include <curl/curl.h> +#include <openssl/crypto.h> +  BOOL gBreak = false;  BOOL gSent = false; -class LLCrashLoggerResponder : public LLHTTPClient::Responder +int LLCrashLogger::ssl_mutex_count = 0; +LLCoreInt::HttpMutex ** LLCrashLogger::ssl_mutex_list = NULL; + +class LLCrashLoggerHandler : public LLHttpSDHandler  { -	LOG_CLASS(LLCrashLoggerResponder); +    LOG_CLASS(LLCrashLoggerHandler);  public: -	LLCrashLoggerResponder()  -	{ -	} +    LLCrashLoggerHandler() {}  protected: -	virtual void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -		gBreak = true; -	} +    virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +    virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); -	virtual void httpSuccess() -	{ -		gBreak = true; -		gSent = true; -	}  }; +void LLCrashLoggerHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) +{ +    gBreak = true; +    gSent = true; +} + +void LLCrashLoggerHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) +{ +    gBreak = true; +} +  LLCrashLogger::LLCrashLogger() :  	mCrashBehavior(CRASH_BEHAVIOR_ALWAYS_SEND),  	mCrashInPreviousExec(false), @@ -389,14 +396,23 @@ bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior)  bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout)  { +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); +  	gBreak = false; +    httpOpts->setTimeout(timeout); +  	for(int i = 0; i < retries; ++i)  	{  		updateApplication(llformat("%s, try %d...", msg.c_str(), i+1)); -		LLHTTPClient::post(host, data, new LLCrashLoggerResponder(), timeout); -		while(!gBreak) + +        LLCoreHttpUtil::requestPostWithLLSD(httpRequest.get(), LLCore::HttpRequest::DEFAULT_POLICY_ID, 0, +            host, data, httpOpts.get(), NULL, new LLCrashLoggerHandler); + +        while(!gBreak)  		{  			updateApplication(); // No new message, just pump the IO +            httpRequest->update(0L);  		}  		if(gSent)  		{ @@ -510,8 +526,6 @@ bool LLCrashLogger::sendCrashLogs()  void LLCrashLogger::updateApplication(const std::string& message)  { -	gServicePump->pump(); -    gServicePump->callback();  	if (!message.empty()) LL_INFOS() << message << LL_ENDL;  } @@ -576,16 +590,74 @@ bool LLCrashLogger::init()  		return false;  	} -	gServicePump = new LLPumpIO(gAPRPoolp); -	gServicePump->prime(gAPRPoolp); -	LLHTTPClient::setPump(*gServicePump); - 	 +    init_curl(); +    LLCore::HttpRequest::createService(); +    LLCore::HttpRequest::startThread(); +  	return true;  }  // For cleanup code common to all platforms.  void LLCrashLogger::commonCleanup()  { +    term_curl();  	LLError::logToFile("");   //close crashreport.log  	LLProxy::cleanupClass();  } + +void LLCrashLogger::init_curl() +{ +    curl_global_init(CURL_GLOBAL_ALL); + +    ssl_mutex_count = CRYPTO_num_locks(); +    if (ssl_mutex_count > 0) +    { +        ssl_mutex_list = new LLCoreInt::HttpMutex *[ssl_mutex_count]; + +        for (int i(0); i < ssl_mutex_count; ++i) +        { +            ssl_mutex_list[i] = new LLCoreInt::HttpMutex; +        } + +        CRYPTO_set_locking_callback(ssl_locking_callback); +        CRYPTO_set_id_callback(ssl_thread_id_callback); +    } +} + + +void LLCrashLogger::term_curl() +{ +    CRYPTO_set_locking_callback(NULL); +    for (int i(0); i < ssl_mutex_count; ++i) +    { +        delete ssl_mutex_list[i]; +    } +    delete[] ssl_mutex_list; +} + + +unsigned long LLCrashLogger::ssl_thread_id_callback(void) +{ +#if LL_WINDOWS +    return (unsigned long)GetCurrentThread(); +#else +    return (unsigned long)pthread_self(); +#endif +} + + +void LLCrashLogger::ssl_locking_callback(int mode, int type, const char * /* file */, int /* line */) +{ +    if (type >= 0 && type < ssl_mutex_count) +    { +        if (mode & CRYPTO_LOCK) +        { +            ssl_mutex_list[type]->lock(); +        } +        else +        { +            ssl_mutex_list[type]->unlock(); +        } +    } +} + diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h index a06bf1d6ac..f5383daefc 100755 --- a/indra/llcrashlogger/llcrashlogger.h +++ b/indra/llcrashlogger/llcrashlogger.h @@ -34,6 +34,7 @@  #include "llsd.h"  #include "llcontrol.h"  #include "llcrashlock.h" +#include "_mutex.h"  // Crash reporter behavior  const S32 CRASH_BEHAVIOR_ASK = 0; @@ -66,6 +67,11 @@ public:  	bool readMinidump(std::string minidump_path);  protected: +    static void init_curl(); +    static void term_curl(); +    static unsigned long ssl_thread_id_callback(void); +    static void ssl_locking_callback(int mode, int type, const char * file, int line); +  	S32 mCrashBehavior;  	BOOL mCrashInPreviousExec;  	std::map<std::string, std::string> mFileMap; @@ -78,6 +84,10 @@ protected:  	LLSD mDebugLog;  	bool mSentCrashLogs;      LLCrashLock mKeyMaster; + +    static int ssl_mutex_count; +    static LLCoreInt::HttpMutex ** ssl_mutex_list; +  };  #endif //LLCRASHLOGGER_H diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 0a308fbf10..fc51d147a6 100755 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -14,6 +14,7 @@ include(LLAddBuildTest)  include(Python)  include(Tut)  include(Python) +include(JsonCpp)  include_directories (${CMAKE_CURRENT_SOURCE_DIR}) @@ -23,6 +24,7 @@ include_directories(      ${LLMATH_INCLUDE_DIRS}      ${LLMESSAGE_INCLUDE_DIRS}      ${LLVFS_INCLUDE_DIRS} +    ${JSONCPP_INCLUDE_DIR}      )  set(llmessage_SOURCE_FILES @@ -47,9 +49,9 @@ set(llmessage_SOURCE_FILES      llhost.cpp      llhttpassetstorage.cpp      llhttpclient.cpp -    llhttpclientadapter.cpp      llhttpconstants.cpp      llhttpnode.cpp +    llhttpsdhandler.cpp      llhttpsender.cpp      llinstantmessage.cpp      lliobuffer.cpp @@ -74,7 +76,6 @@ set(llmessage_SOURCE_FILES      llpumpio.cpp      llsdappservices.cpp      llsdhttpserver.cpp -    llsdmessage.cpp      llsdmessagebuilder.cpp      llsdmessagereader.cpp      llsdrpcclient.cpp @@ -142,10 +143,10 @@ set(llmessage_HEADER_FILES      llhttpassetstorage.h      llhttpclient.h      llhttpclientinterface.h -    llhttpclientadapter.h      llhttpconstants.h      llhttpnode.h      llhttpnodeadapter.h +    llhttpsdhandler.h      llhttpsender.h      llinstantmessage.h      llinvite.h @@ -176,7 +177,6 @@ set(llmessage_HEADER_FILES      llregionhandle.h      llsdappservices.h      llsdhttpserver.h -    llsdmessage.h      llsdmessagebuilder.h      llsdmessagereader.h      llsdrpcclient.h @@ -226,9 +226,10 @@ target_link_libraries(    llmessage    ${CURL_LIBRARIES}    ${LLCOMMON_LIBRARIES} -  ${LLVFS_LIBRARES} +  ${LLVFS_LIBRARIES}    ${LLMATH_LIBRARIES}    ${CARES_LIBRARIES} +  ${JSONCPP_LIBRARIES}    ${OPENSSL_LIBRARIES}    ${CRYPTO_LIBRARIES}    ${XMLRPCEPI_LIBRARIES} @@ -243,36 +244,25 @@ if (LL_TESTS)      )    LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}") +      #    set(TEST_DEBUG on) +      set(test_libs -    ${CURL_LIBRARIES} -    ${LLMESSAGE_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} +    ${CURL_LIBRARIES}      ${LLCOMMON_LIBRARIES} -      ${GOOGLEMOCK_LIBRARIES} -    ) - -  LL_ADD_INTEGRATION_TEST( -    llsdmessage -    "llsdmessage.cpp" -    "${test_libs}" -    ${PYTHON_EXECUTABLE} -    "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py" -    ) - -  LL_ADD_INTEGRATION_TEST( -    llhttpclient -    "llhttpclient.cpp" -    "${test_libs}" -    ${PYTHON_EXECUTABLE} -    "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py" +    ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES} +    ${JSONCPP_LIBRARIES} +    ${BOOST_COROUTINE_LIBRARY} +    ${BOOST_CONTEXT_LIBRARY} +    ${GOOGLEMOCK_LIBRARIES}      ) -  LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}") +  #LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}") -  LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")  endif (LL_TESTS) diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 549708097a..d262862c80 100755 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -30,12 +30,20 @@  #include "llcachename.h"		// we wrap this system  #include "llframetimer.h" -#include "llhttpclient.h"  #include "llsd.h"  #include "llsdserialize.h" - +#include "httpresponse.h" +#include "llhttpsdhandler.h"  #include <boost/tokenizer.hpp> +#include "httpcommon.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +  #include <map>  #include <set> @@ -90,6 +98,12 @@ namespace LLAvatarNameCache  	// Time-to-live for a temp cache entry.  	const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; +    LLCore::HttpRequest::ptr_t		sHttpRequest; +    LLCore::HttpHeaders::ptr_t		sHttpHeaders; +    LLCore::HttpOptions::ptr_t		sHttpOptions; +    LLCore::HttpRequest::policy_t	sHttpPolicy; +    LLCore::HttpRequest::priority_t	sHttpPriority; +  	//-----------------------------------------------------------------------  	// Internal methods  	//----------------------------------------------------------------------- @@ -121,7 +135,12 @@ namespace LLAvatarNameCache  	// Erase expired names from cache  	void eraseUnrefreshed(); -	bool expirationFromCacheControl(const LLSD& headers, F64 *expires); +    bool expirationFromCacheControl(const LLSD& headers, F64 *expires); + +    // This is a coroutine. +    void requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds); + +    void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult);  }  /* Sample response: @@ -163,94 +182,117 @@ namespace LLAvatarNameCache  </llsd>  */ -class LLAvatarNameResponder : public LLHTTPClient::Responder +// Coroutine for sending and processing avatar name cache requests.   +// Do not call directly.  See documentation in lleventcoro.h and llcoro.h for +// further explanation. +void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLUUID> agentIds)  { -	LOG_CLASS(LLAvatarNameResponder); -private: -	// need to store agent ids that are part of this request in case of -	// an error, so we can flag them as unavailable -	std::vector<LLUUID> mAgentIDs; - -public: -	LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids) -	:	mAgentIDs(agent_ids) -	{ } -	 -protected: -	/*virtual*/ void httpSuccess() -	{ -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		// Pull expiration out of headers if available -		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders()); -		F64 now = LLFrameTimer::getTotalSeconds(); +    LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::instance().getName() +        << " with url '" << url << "', requesting " << agentIds.size() << " Agent Ids" << LL_ENDL; -		const LLSD& agents = content["agents"]; -		LLSD::array_const_iterator it = agents.beginArray(); -		for ( ; it != agents.endArray(); ++it) -		{ -			const LLSD& row = *it; -			LLUUID agent_id = row["id"].asUUID(); +    try +    { +        bool success = true; -			LLAvatarName av_name; -			av_name.fromLLSD(row); +        LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("NameCache", LLAvatarNameCache::sHttpPolicy); +        LLSD results = httpAdapter.getAndYield(sHttpRequest, url); +        LLSD httpResults; -			// Use expiration time from header -			av_name.mExpires = expires; +        LL_DEBUGS() << results << LL_ENDL; -			LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL; -			av_name.dump(); -			 -			// cache it and fire signals -			LLAvatarNameCache::processName(agent_id, av_name); -		} +        if (!results.isMap()) +        { +            LL_WARNS("AvNameCache") << " Invalid result returned from LLCoreHttpUtil::HttpCoroHandler." << LL_ENDL; +            success = false; +        } +        else +        { +            httpResults = results["http_result"]; +            success = httpResults["success"].asBoolean(); +            if (!success) +            { +                LL_WARNS("AvNameCache") << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code " +                    << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL; +            } +        } -		// Same logic as error response case -		const LLSD& unresolved_agents = content["bad_ids"]; -		S32  num_unresolved = unresolved_agents.size(); -		if (num_unresolved > 0) -		{ -            LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " -                                    << "expires in " << expires - now << " seconds" -                                    << LL_ENDL; -			it = unresolved_agents.beginArray(); -			for ( ; it != unresolved_agents.endArray(); ++it) -			{ -				const LLUUID& agent_id = *it; +        if (!success) +        {   // on any sort of failure add dummy records for any agent IDs  +            // in this request that we do not have cached already +            std::vector<LLUUID>::const_iterator it = agentIds.begin(); +            for ( ; it != agentIds.end(); ++it) +            { +                const LLUUID& agent_id = *it; +                LLAvatarNameCache::handleAgentError(agent_id); +            } +            return; +        } -				LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " -                                        << "failed id " << agent_id -                                        << LL_ENDL; +        LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults); -                LLAvatarNameCache::handleAgentError(agent_id); -			} -		} -        LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "  -                                 << LLAvatarNameCache::sCache.size() << " cached names" -                                 << LL_ENDL;      } +    catch (std::exception e) +    { +        LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL; +    } +    catch (...) +    { +        LL_WARNS() << "Caught unknown exception." << LL_ENDL; +    } +} -	/*virtual*/ void httpFailure() -	{ -		// If there's an error, it might be caused by PeopleApi, -		// or when loading textures on startup and using a very slow  -		// network, this query may time out. -		// What we should do depends on whether or not we have a cached name -		LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL; - -		// Add dummy records for any agent IDs in this request that we do not have cached already -		std::vector<LLUUID>::const_iterator it = mAgentIDs.begin(); -		for ( ; it != mAgentIDs.end(); ++it) -		{ -			const LLUUID& agent_id = *it; -			LLAvatarNameCache::handleAgentError(agent_id); -		} -	} -}; +void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult) +{ + +    LLSD headers = httpResult["headers"]; +    // Pull expiration out of headers if available +    F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(headers); +    F64 now = LLFrameTimer::getTotalSeconds(); + +    const LLSD& agents = data["agents"]; +    LLSD::array_const_iterator it = agents.beginArray(); +    for (; it != agents.endArray(); ++it) +    { +        const LLSD& row = *it; +        LLUUID agent_id = row["id"].asUUID(); + +        LLAvatarName av_name; +        av_name.fromLLSD(row); + +        // Use expiration time from header +        av_name.mExpires = expires; + +        LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL; +        av_name.dump(); + +        // cache it and fire signals +        LLAvatarNameCache::processName(agent_id, av_name); +    } + +    // Same logic as error response case +    const LLSD& unresolved_agents = data["bad_ids"]; +    S32  num_unresolved = unresolved_agents.size(); +    if (num_unresolved > 0) +    { +        LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " +            << "expires in " << expires - now << " seconds" +            << LL_ENDL; +        it = unresolved_agents.beginArray(); +        for (; it != unresolved_agents.endArray(); ++it) +        { +            const LLUUID& agent_id = *it; + +            LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " +                << "failed id " << agent_id +                << LL_ENDL; + +            LLAvatarNameCache::handleAgentError(agent_id); +        } +    } +    LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result " +        << LLAvatarNameCache::sCache.size() << " cached names" +        << LL_ENDL; +}  // Provide some fallback for agents that return errors  void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) @@ -353,10 +395,15 @@ void LLAvatarNameCache::requestNamesViaCapability()  		}  	} -	if (!url.empty()) -	{ -		LL_INFOS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability getting " << ids << " ids" << LL_ENDL; -		LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); +    if (!url.empty()) +    { +        LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " << ids << " ids" << LL_ENDL; + +        std::string coroname =  +            LLCoros::instance().launch("LLAvatarNameCache::requestAvatarNameCache_", +            boost::bind(&LLAvatarNameCache::requestAvatarNameCache_, url, agent_ids)); +        LL_DEBUGS("AvNameCache") << coroname << " with  url '" << url << "', agent_ids.size()=" << agent_ids.size() << LL_ENDL; +  	}  } @@ -419,11 +466,20 @@ void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI)  {  	sRunning = running;  	sUsePeopleAPI = usePeopleAPI; + +    sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +    sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); +    sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); +    sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; +    sHttpPriority = 0;  }  void LLAvatarNameCache::cleanupClass()  { -	sCache.clear(); +    sHttpRequest.reset(); +    sHttpHeaders.reset(); +    sHttpOptions.reset(); +    sCache.clear();  }  bool LLAvatarNameCache::importFile(std::istream& istr) @@ -698,6 +754,50 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na  	sCache[agent_id] = av_name;  } +#if 0 +F64 LLAvatarNameCache::nameExpirationFromHeaders(LLCore::HttpHeaders *headers) +{ +    F64 expires = 0.0; +    if (expirationFromCacheControl(headers, &expires)) +    { +        return expires; +    } +    else +    { +        // With no expiration info, default to an hour +        const F64 DEFAULT_EXPIRES = 60.0 * 60.0; +        F64 now = LLFrameTimer::getTotalSeconds(); +        return now + DEFAULT_EXPIRES; +    } +} + +bool LLAvatarNameCache::expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires) +{ +    bool fromCacheControl = false; +    F64 now = LLFrameTimer::getTotalSeconds(); + +    // Allow the header to override the default +    const std::string *cache_control; +     +    cache_control = headers->find(HTTP_IN_HEADER_CACHE_CONTROL); + +    if (cache_control && !cache_control->empty()) +    { +        S32 max_age = 0; +        if (max_age_from_cache_control(*cache_control, &max_age)) +        { +            *expires = now + (F64)max_age; +            fromCacheControl = true; +        } +    } +    LL_DEBUGS("AvNameCache") +        << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) +        << "in " << *expires - now << " seconds" +        << LL_ENDL; + +    return fromCacheControl; +} +#else  F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)  {  	F64 expires = 0.0; @@ -742,7 +842,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *exp  	return fromCacheControl;  } - +#endif  void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)   {  diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 5a10053a69..bd2715e956 100755 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -29,7 +29,6 @@  #define LLAVATARNAMECACHE_H  #include "llavatarname.h"	// for convenience -  #include <boost/signals2.hpp>  class LLSD; @@ -49,7 +48,7 @@ namespace LLAvatarNameCache  	bool importFile(std::istream& istr);  	void exportFile(std::ostream& ostr); -	// On the viewer, usually a simulator capabilitity. +	// On the viewer, usually a simulator capabilities.  	// If empty, name cache will fall back to using legacy name lookup system.  	void setNameLookupURL(const std::string& name_lookup_url); @@ -90,7 +89,7 @@ namespace LLAvatarNameCache  	// Compute name expiration time from HTTP Cache-Control header,  	// or return default value, in seconds from epoch. -	F64 nameExpirationFromHeaders(const LLSD& headers); +    F64 nameExpirationFromHeaders(const LLSD& headers);  	void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);  } diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index ee80b0fd94..cd3c527241 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -28,112 +28,985 @@  #include "linden_common.h"  #include <sstream> - +#include <algorithm> +#include <iterator>  #include "llcorehttputil.h" +#include "llhttpconstants.h" +#include "llsd.h" +#include "llsdjson.h"  #include "llsdserialize.h" +#include "reader.h"  +#include "llvfile.h" +#include "message.h" // for getting the port  using namespace LLCore;  namespace LLCoreHttpUtil  { +void logMessageSuccess(std::string logAuth, std::string url, std::string message) +{ +    LL_INFOS() << logAuth << " Success '" << message << "' for " << url << LL_ENDL; +} + +void logMessageFail(std::string logAuth, std::string url, std::string message) +{ +    LL_WARNS() << logAuth << " Failure '" << message << "' for " << url << LL_ENDL; +} + +//========================================================================= +/// The HttpRequestPumper is a utility class. When constructed it will poll the  +/// supplied HttpRequest once per frame until it is destroyed. +///  +class HttpRequestPumper +{ +public: +    HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request); +    ~HttpRequestPumper(); + +private: +    bool                       pollRequest(const LLSD&); +    LLTempBoundListener        mBoundListener; +    LLCore::HttpRequest::ptr_t mHttpRequest; +}; + + +//=========================================================================  // *TODO:  Currently converts only from XML content.  A mode  // to convert using fromBinary() might be useful as well.  Mesh  // headers could use it.  bool responseToLLSD(HttpResponse * response, bool log, LLSD & out_llsd)  { -	// Convert response to LLSD -	BufferArray * body(response->getBody()); -	if (! body || ! body->size()) -	{ -		return false; -	} +    // Convert response to LLSD +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return false; +    } -	LLCore::BufferArrayStream bas(body); -	LLSD body_llsd; -	S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log)); -	if (LLSDParser::PARSE_FAILURE == parse_status){ -		return false; -	} -	out_llsd = body_llsd; -	return true; +    LLCore::BufferArrayStream bas(body); +    LLSD body_llsd; +    S32 parse_status(LLSDSerialize::fromXML(body_llsd, bas, log)); +    if (LLSDParser::PARSE_FAILURE == parse_status){ +        return false; +    } +    out_llsd = body_llsd; +    return true;  }  HttpHandle requestPostWithLLSD(HttpRequest * request, -							   HttpRequest::policy_t policy_id, -							   HttpRequest::priority_t priority, -							   const std::string & url, -							   const LLSD & body, -							   HttpOptions * options, -							   HttpHeaders * headers, -							   HttpHandler * handler) +    HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    HttpOptions * options, +    HttpHeaders * headers, +    HttpHandler * handler)  { -	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); -	BufferArray * ba = new BufferArray(); -	BufferArrayStream bas(ba); -	LLSDSerialize::toXML(body, bas); +    BufferArray * ba = new BufferArray(); +    BufferArrayStream bas(ba); +    LLSDSerialize::toXML(body, bas); -	handle = request->requestPost(policy_id, -								  priority, -								  url, -								  ba, -								  options, -								  headers, -								  handler); -	ba->release(); -	return handle; +    handle = request->requestPost(policy_id, +        priority, +        url, +        ba, +        options, +        headers, +        handler); +    ba->release(); +    return handle; +} + + +HttpHandle requestPutWithLLSD(HttpRequest * request, +    HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    HttpOptions * options, +    HttpHeaders * headers, +    HttpHandler * handler) +{ +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    BufferArray * ba = new BufferArray(); +    BufferArrayStream bas(ba); +    LLSDSerialize::toXML(body, bas); + +    handle = request->requestPut(policy_id, +        priority, +        url, +        ba, +        options, +        headers, +        handler); +    ba->release(); +    return handle; +} + +HttpHandle requestPatchWithLLSD(HttpRequest * request, +    HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    HttpOptions * options, +    HttpHeaders * headers, +    HttpHandler * handler) +{ +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    BufferArray * ba = new BufferArray(); +    BufferArrayStream bas(ba); +    LLSDSerialize::toXML(body, bas); + +    handle = request->requestPatch(policy_id, +        priority, +        url, +        ba, +        options, +        headers, +        handler); +    ba->release(); +    return handle;  }  std::string responseToString(LLCore::HttpResponse * response)  { -	static const std::string empty("[Empty]"); - -	if (! response) -	{ -		return empty; -	} - -	BufferArray * body(response->getBody()); -	if (! body || ! body->size()) -	{ -		return empty; -	} - -	// Attempt to parse as LLSD regardless of content-type -	LLSD body_llsd; -	if (responseToLLSD(response, false, body_llsd)) -	{ -		std::ostringstream tmp; - -		LLSDSerialize::toPrettyNotation(body_llsd, tmp); -		std::size_t temp_len(tmp.tellp()); -		 -		if (temp_len) -		{ -			return tmp.str().substr(0, std::min(temp_len, std::size_t(1024))); -		} -	} -	else -	{ -		// *TODO:  More elaborate forms based on Content-Type as needed. -		char content[1024]; - -		size_t len(body->read(0, content, sizeof(content))); -		if (len) -		{ -			return std::string(content, 0, len); -		} -	} - -	// Default -	return empty; +    static const std::string empty("[Empty]"); + +    if (!response) +    { +        return empty; +    } + +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return empty; +    } + +    // Attempt to parse as LLSD regardless of content-type +    LLSD body_llsd; +    if (responseToLLSD(response, false, body_llsd)) +    { +        std::ostringstream tmp; + +        LLSDSerialize::toPrettyNotation(body_llsd, tmp); +        std::size_t temp_len(tmp.tellp()); + +        if (temp_len) +        { +            return tmp.str().substr(0, std::min(temp_len, std::size_t(1024))); +        } +    } +    else +    { +        // *TODO:  More elaborate forms based on Content-Type as needed. +        char content[1024]; + +        size_t len(body->read(0, content, sizeof(content))); +        if (len) +        { +            return std::string(content, 0, len); +        } +    } + +    // Default +    return empty; +} + +//======================================================================== + +HttpCoroHandler::HttpCoroHandler(LLEventStream &reply) : +    mReplyPump(reply) +{ +} + +void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +    LLSD result; + +    LLCore::HttpStatus status = response->getStatus(); + +    if (status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_HANDLE_NOT_FOUND)) +    {   // A response came in for a canceled request and we have not processed the  +        // cancel yet.  Patience! +        return; +    } + +    if (!status) +    { +        result = LLSD::emptyMap(); +        LL_WARNS() +            << "\n--------------------------------------------------------------------------\n" +            << " Error[" << status.getType() << "] cannot access url '" << response->getRequestURL() +            << "' because " << status.toString() +            << "\n--------------------------------------------------------------------------" +            << LL_ENDL; +    } +    else +    { +        result = this->handleSuccess(response, status); +    } + +    buildStatusEntry(response, status, result); + +#if 1 +    // commenting out, but keeping since this can be useful for debugging +    if (!status) +    { +        LLSD &httpStatus = result[HttpCoroutineAdapter::HTTP_RESULTS]; + +        LLCore::BufferArray *body = response->getBody(); +        LLCore::BufferArrayStream bas(body); +        LLSD::String bodyData; +        bodyData.reserve(response->getBodySize()); +        bas >> std::noskipws; +        bodyData.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); +        httpStatus["error_body"] = LLSD(bodyData); + +        LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL; +    } +#endif + +    mReplyPump.post(result); +} + +void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) +{ +    LLSD httpresults = LLSD::emptyMap(); + +    writeStatusCodes(status, response->getRequestURL(), httpresults); + +    LLSD httpHeaders = LLSD::emptyMap(); +    LLCore::HttpHeaders * hdrs = response->getHeaders(); + +    if (hdrs) +    { +        for (LLCore::HttpHeaders::iterator it = hdrs->begin(); it != hdrs->end(); ++it) +        { +            if (!(*it).second.empty()) +            { +                httpHeaders[(*it).first] = (*it).second; +            } +            else +            { +                httpHeaders[(*it).first] = static_cast<LLSD::Boolean>(true); +            } +        } +    } + +    httpresults[HttpCoroutineAdapter::HTTP_RESULTS_HEADERS] = httpHeaders; +    result[HttpCoroutineAdapter::HTTP_RESULTS] = httpresults; +} + +void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result) +{ +    result[HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS] = static_cast<LLSD::Boolean>(status); +    result[HttpCoroutineAdapter::HTTP_RESULTS_TYPE] = static_cast<LLSD::Integer>(status.getType()); +    result[HttpCoroutineAdapter::HTTP_RESULTS_STATUS] = static_cast<LLSD::Integer>(status.getStatus()); +    result[HttpCoroutineAdapter::HTTP_RESULTS_MESSAGE] = static_cast<LLSD::String>(status.getMessage()); +    result[HttpCoroutineAdapter::HTTP_RESULTS_URL] = static_cast<LLSD::String>(url); + +} + +//========================================================================= +/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines. When the request is completed the response  +/// will be posted onto the supplied Event Pump. +///  +/// If the LLSD retrieved from through the HTTP connection is not in the form +/// of a LLSD::map it will be returned as in an llsd["content"] element. +///  +/// The LLSD posted back to the coroutine will have the following additions: +/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status +///                      +- ["status"]  - The status code associated with the HTTP call +///                      +- ["success"] - Success of failure of the HTTP call and LLSD parsing. +///                      +- ["type"]    - The LLCore::HttpStatus type associted with the HTTP call +///                      +- ["url"]     - The URL used to make the call. +///                      +- ["headers"] - A map of name name value pairs with the HTTP headers. +///                       +class HttpCoroLLSDHandler : public HttpCoroHandler +{ +public: +    HttpCoroLLSDHandler(LLEventStream &reply); + +protected: +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); +}; + +//------------------------------------------------------------------------- +HttpCoroLLSDHandler::HttpCoroLLSDHandler(LLEventStream &reply): +    HttpCoroHandler(reply) +{ +} +     + +LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +{ +    LLSD result; + +    const bool emit_parse_errors = false; + +    bool parsed = !((response->getBodySize() == 0) || +        !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result)); + +    if (!parsed) +    { +        // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' +        LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); +        const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; + +        if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) +        { +            std::string thebody = LLCoreHttpUtil::responseToString(response); +            LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " +                << " body: " << thebody << LL_ENDL; + +            // Replace the status with a new one indicating the failure. +            status = LLCore::HttpStatus(499, "Failed to deserialize LLSD."); +        } +    } + +    if (result.isUndefined()) +    {   // If we've gotten to this point and the result LLSD is still undefined  +        // either there was an issue deserializing the body or the response was +        // blank.  Create an empty map to hold the result either way. +        result = LLSD::emptyMap(); +    } +    else if (!result.isMap()) +    {   // The results are not themselves a map.  Move them down so that  +        // this method can return a map to the caller. +        // *TODO: Should it always do this? +        LLSD newResult = LLSD::emptyMap(); +        newResult[HttpCoroutineAdapter::HTTP_RESULTS_CONTENT] = result; +        result = newResult; +    } + +    return result; +} + +//======================================================================== +/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines.  +///  +/// In addition to the normal "http_results" the returned LLSD will contain  +/// an entry keyed with "raw" containing the unprocessed results of the HTTP +/// call. +///                       +class HttpCoroRawHandler : public HttpCoroHandler +{ +public: +    HttpCoroRawHandler(LLEventStream &reply); + +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); +}; + +//------------------------------------------------------------------------- +HttpCoroRawHandler::HttpCoroRawHandler(LLEventStream &reply): +    HttpCoroHandler(reply) +{  } +LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +{ +    LLSD result = LLSD::emptyMap(); + +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return result; +    } + +    size_t size = body->size(); + +    LLCore::BufferArrayStream bas(body); + +#if 1 +    // This is the slower implementation.  It is safe vis-a-vi the const_cast<> and modification +    // of a LLSD managed array but contains an extra (potentially large) copy. +    //  +    // *TODO: https://jira.secondlife.com/browse/MAINT-5221 +     +    LLSD::Binary data; +    data.reserve(size); +    bas >> std::noskipws; +    data.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); + +    result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = data; + +#else +    // This is disabled because it's dangerous.  See the other case for an  +    // alternate implementation. +    // We create a new LLSD::Binary object and assign it to the result map. +    // The LLSD has created it's own copy so we retrieve it asBinary and const cast  +    // the reference so that we can modify it. +    // *TODO: This is potentially dangerous... but I am trying to avoid a potentially  +    // large copy. +    result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = LLSD::Binary(); +    LLSD::Binary &data = const_cast<LLSD::Binary &>( result[HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary() ); + +    data.reserve(size); +    bas >> std::noskipws; +    data.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); +#endif + +    return result; +} + +//======================================================================== +/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines.  +///  +/// In addition to the normal "http_results" the returned LLSD will contain  +/// JSON entries will be converted into an LLSD map.  All results are considered  +/// strings +///                       +class HttpCoroJSONHandler : public HttpCoroHandler +{ +public: +    HttpCoroJSONHandler(LLEventStream &reply); + +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); +}; + +//------------------------------------------------------------------------- +HttpCoroJSONHandler::HttpCoroJSONHandler(LLEventStream &reply) : +    HttpCoroHandler(reply) +{ +} + +LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +{ +    LLSD result = LLSD::emptyMap(); + +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return result; +    } + +    LLCore::BufferArrayStream bas(body); +    Json::Value jsonRoot; + +    try +    { +        bas >> jsonRoot; +    } +    catch (std::runtime_error e) +    {   // deserialization failed.  Record the reason and pass back an empty map for markup. +        status = LLCore::HttpStatus(499, std::string(e.what())); +        return result; +    } + +    // Convert the JSON structure to LLSD +    result = LlsdFromJson(jsonRoot); + +    return result; +} + + +//======================================================================== +HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) : +    mHttpRequest(request) +{ +    mBoundListener = LLEventPumps::instance().obtain("mainloop"). +        listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1)); +} + +HttpRequestPumper::~HttpRequestPumper() +{ +    if (mBoundListener.connected()) +    { +        mBoundListener.disconnect(); +    } +} + +bool HttpRequestPumper::pollRequest(const LLSD&) +{ +    if (mHttpRequest->getStatus() != HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED)) +    { +        mHttpRequest->update(0L); +    } +    return false; +} + +//======================================================================== +const std::string HttpCoroutineAdapter::HTTP_RESULTS("http_result"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS("success"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_TYPE("type"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_STATUS("status"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_MESSAGE("message"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_URL("url"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_HEADERS("headers"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_CONTENT("content"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_RAW("raw"); + +HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name, +    LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) : +    mAdapterName(name), +    mPolicyId(policyId), +    mPriority(priority), +    mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID), +    mWeakRequest(), +    mWeakHandler() +{ +} + +HttpCoroutineAdapter::~HttpCoroutineAdapter() +{ +    cancelYieldingOperation(); +} + +LLSD HttpCoroutineAdapter::postAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, const LLSD & body, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName, true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    return postAndYield_(request, url, body, options, headers, httpHandler); +} + +LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, const LLSD & body, +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    LLCore::HttpHandle hhandle = requestPostWithLLSD(request, +        mPolicyId, mPriority, url, body, options, headers, +        handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); + +    return results; +} + +LLSD HttpCoroutineAdapter::postAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, LLCore::BufferArray::ptr_t rawbody, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName, true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    return postAndYield_(request, url, rawbody, options, headers, httpHandler); +} + +LLSD HttpCoroutineAdapter::postRawAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, LLCore::BufferArray::ptr_t rawbody, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName, true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroRawHandler(replyPump)); + +    return postAndYield_(request, url, rawbody, options, headers, httpHandler); +} + +// *TODO: This functionality could be moved into the LLCore::Http library itself  +// by having the CURL layer read the file directly. +LLSD HttpCoroutineAdapter::postFileAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, std::string fileName, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLCore::BufferArray::ptr_t fileData(new LLCore::BufferArray); + +    // scoping for our streams so that they go away when we no longer need them. +    { +        LLCore::BufferArrayStream outs(fileData.get()); +        llifstream ins(fileName.c_str(), std::iostream::binary | std::iostream::out); + +        if (ins.is_open()) +        { + +            ins.seekg(0, std::ios::beg); +            ins >> std::noskipws; + +            std::copy(std::istream_iterator<U8>(ins), std::istream_iterator<U8>(), +                    std::ostream_iterator<U8>(outs)); + +            ins.close(); +        } +    } + +    return postAndYield(request, url, fileData, options, headers); +} + +// *TODO: This functionality could be moved into the LLCore::Http library itself  +// by having the CURL layer read the file directly. +LLSD HttpCoroutineAdapter::postFileAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, LLUUID assetId, LLAssetType::EType assetType, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLCore::BufferArray::ptr_t fileData(new LLCore::BufferArray); + +    // scoping for our streams so that they go away when we no longer need them. +    { +        LLCore::BufferArrayStream outs(fileData.get()); +        LLVFile vfile(gVFS, assetId, assetType, LLVFile::READ); + +        S32 fileSize = vfile.getSize(); +        U8* fileBuffer; +        fileBuffer = new U8[fileSize]; +        vfile.read(fileBuffer, fileSize); +         +        outs.write((char*)fileBuffer, fileSize); +        delete[] fileBuffer; +    } + +    return postAndYield(request, url, fileData, options, headers); +} + + +LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, LLCore::BufferArray::ptr_t &rawbody, +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    LLCore::HttpHandle hhandle = request->requestPost(mPolicyId, mPriority, url, rawbody.get(), +        options.get(), headers.get(), handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); + +    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL; +    return results; +} + +LLSD HttpCoroutineAdapter::putAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, const LLSD & body, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    return putAndYield_(request, url, body, options, headers, httpHandler); +} + +LLSD HttpCoroutineAdapter::putAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, const LLSD & body, +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    LLCore::HttpHandle hhandle = requestPutWithLLSD(request, +        mPolicyId, mPriority, url, body, options, headers, +        handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); +    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL; +    return results; +} + +LLSD HttpCoroutineAdapter::getAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    return getAndYield_(request, url, options, headers, httpHandler); +} + +LLSD HttpCoroutineAdapter::getRawAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroRawHandler(replyPump)); + +    return getAndYield_(request, url, options, headers, httpHandler); +} + +LLSD HttpCoroutineAdapter::getJsonAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroJSONHandler(replyPump)); + +    return getAndYield_(request, url, options, headers, httpHandler); +} + + +LLSD HttpCoroutineAdapter::getAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,  +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    LLCore::HttpHandle hhandle = request->requestGet(mPolicyId, mPriority, +        url, options.get(), headers.get(), handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); +    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL; +    return results; +} + + +LLSD HttpCoroutineAdapter::deleteAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    return deleteAndYield_(request, url, options, headers, httpHandler); +} + +LLSD HttpCoroutineAdapter::deleteAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, LLCore::HttpOptions::ptr_t &options,  +    LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    LLCore::HttpHandle hhandle = request->requestDelete(mPolicyId, mPriority, +        url, options.get(), headers.get(), handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); +    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL; +    return results; +} + +void HttpCoroutineAdapter::checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers) +{ +    if (!headers) +        headers.reset(new LLCore::HttpHeaders); +    if (!headers->find(HTTP_OUT_HEADER_ACCEPT)) +    { +        headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); +    } + +    if (!headers->find("X-SecondLife-UDP-Listen-Port") && gMessageSystem) +    { +        headers->append("X-SecondLife-UDP-Listen-Port", llformat("%d", gMessageSystem->mPort)); +    } +} + + +void HttpCoroutineAdapter::cancelYieldingOperation() +{ +    LLCore::HttpRequest::ptr_t request = mWeakRequest.lock(); +    HttpCoroHandler::ptr_t handler = mWeakHandler.lock(); +    if ((request) && (handler) && (mYieldingHandle != LLCORE_HTTP_HANDLE_INVALID)) +    { +        cleanState(); +        LL_INFOS() << "Canceling yielding request!" << LL_ENDL; +        request->requestCancel(mYieldingHandle, handler.get()); +    } +} + +void HttpCoroutineAdapter::saveState(LLCore::HttpHandle yieldingHandle,  +    LLCore::HttpRequest::ptr_t &request, HttpCoroHandler::ptr_t &handler) +{ +    mWeakRequest = request; +    mWeakHandler = handler; +    mYieldingHandle = yieldingHandle; +} + +void HttpCoroutineAdapter::cleanState() +{ +    mWeakRequest.reset(); +    mWeakHandler.reset(); +    mYieldingHandle = LLCORE_HTTP_HANDLE_INVALID; +} + +/*static*/ +LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request,  +    const std::string &url)  +{ +    LLCore::HttpStatus status = request->getStatus(); +    LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() << +        " message = " << status.getMessage() << LL_ENDL; + +    // Mimic the status results returned from an http error that we had  +    // to wait on  +    LLSD httpresults = LLSD::emptyMap(); + +    HttpCoroHandler::writeStatusCodes(status, url, httpresults); + +    LLSD errorres = LLSD::emptyMap(); +    errorres["http_result"] = httpresults; + +    return errorres; +} + +/*static*/ +LLCore::HttpStatus HttpCoroutineAdapter::getStatusFromLLSD(const LLSD &httpResults) +{ +    LLCore::HttpStatus::type_enum_t type = static_cast<LLCore::HttpStatus::type_enum_t>(httpResults[HttpCoroutineAdapter::HTTP_RESULTS_TYPE].asInteger()); +    short code = static_cast<short>(httpResults[HttpCoroutineAdapter::HTTP_RESULTS_STATUS].asInteger()); + +    return LLCore::HttpStatus(type, code); +} + +/*static*/ +void HttpCoroutineAdapter::callbackHttpGet(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure) +{ +    LLCoros::instance().launch("HttpCoroutineAdapter::genericGetCoro", +        boost::bind(&HttpCoroutineAdapter::trivialGetCoro, url, policyId, success, failure)); +} + +/*static*/ +void HttpCoroutineAdapter::messageHttpGet(const std::string &url, const std::string &success, const std::string &failure) +{ +    completionCallback_t cbSuccess = (success.empty()) ? NULL :  +        static_cast<completionCallback_t>(boost::bind(&logMessageSuccess, "HttpCoroutineAdapter", url, success)); +    completionCallback_t cbFailure = (failure.empty()) ? NULL : +        static_cast<completionCallback_t>(boost::bind(&logMessageFail, "HttpCoroutineAdapter", url, failure)); +    callbackHttpGet(url, cbSuccess, cbFailure); +} + +/*static*/ +void HttpCoroutineAdapter::trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure) +{ +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericGetCoro", policyId)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); + +    LL_INFOS("HttpCoroutineAdapter", "genericGetCoro") << "Generic GET for " << url << LL_ENDL; + +    LLSD result = httpAdapter->getAndYield(httpRequest, url, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    {    +        if (failure) +        { +            failure(httpResults); +        } +    } +    else +    { +        if (success) +        { +            success(result); +        } +    } +} + +/*static*/ +void HttpCoroutineAdapter::callbackHttpPost(const std::string &url, LLCore::HttpRequest::policy_t policyId, const LLSD &postData, completionCallback_t success, completionCallback_t failure) +{ +    LLCoros::instance().launch("HttpCoroutineAdapter::genericPostCoro", +        boost::bind(&HttpCoroutineAdapter::trivialPostCoro, url, policyId, postData, success, failure)); +} + +/*static*/ +void HttpCoroutineAdapter::messageHttpPost(const std::string &url, const LLSD &postData, const std::string &success, const std::string &failure) +{ +    completionCallback_t cbSuccess = (success.empty()) ? NULL : +        static_cast<completionCallback_t>(boost::bind(&logMessageSuccess, "HttpCoroutineAdapter", url, success)); +    completionCallback_t cbFailure = (failure.empty()) ? NULL : +        static_cast<completionCallback_t>(boost::bind(&logMessageFail, "HttpCoroutineAdapter", url, failure)); + +    callbackHttpPost(url, postData, cbSuccess, cbFailure); +} + +/*static*/ +void HttpCoroutineAdapter::trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure) +{ +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", policyId)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); + +    LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        // If a failure routine is provided do it. +        if (failure) +        { +            failure(httpResults); +        } +    } +    else +    { +        // If a success routine is provided do it. +        if (success) +        { +            success(result); +        } +    } +} + +  } // end namespace LLCoreHttpUtil diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index d40172bc7a..cf35177e48 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -36,9 +36,15 @@  #include "httpheaders.h"  #include "httpoptions.h"  #include "httphandler.h" +#include "llhttpconstants.h" // *TODO: move to llcorehttp  #include "bufferarray.h"  #include "bufferstream.h"  #include "llsd.h" +#include "llevents.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llassettype.h" +#include "lluuid.h"  ///  /// The base llcorehttp library implements many HTTP idioms @@ -109,7 +115,415 @@ LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request,  									   LLCore::HttpHeaders * headers,  									   LLCore::HttpHandler * handler); -} // end namespace LLCoreHttpUtil +inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	LLCore::HttpOptions::ptr_t & options, +	LLCore::HttpHeaders::ptr_t & headers, +	LLCore::HttpHandler * handler) +{ +    return requestPostWithLLSD(request.get(), policy_id, priority, +        url, body, options.get(), headers.get(), handler); +} + +inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpHandler * handler) +{ +    return requestPostWithLLSD(request.get(), policy_id, priority, +        url, body, NULL, NULL, handler); +} + + +/// Issue a standard HttpRequest::requestPut() call but using +/// and LLSD object as the request body.  Conventions are the +/// same as with that method.  Caller is expected to provide +/// an HttpHeaders object with a correct 'Content-Type:' header. +/// One will not be provided by this call. +/// +/// @return				If request is successfully issued, the +///						HttpHandle representing the request. +///						On error, LLCORE_HTTP_HANDLE_INVALID +///						is returned and caller can fetch detailed +///						status with the getStatus() method on the +///						request object.  In case of error, no +///						request is queued and caller may need to +///						perform additional cleanup such as freeing +///						a now-useless HttpHandler object. +/// +LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	LLCore::HttpOptions * options, +	LLCore::HttpHeaders * headers, +	LLCore::HttpHandler * handler); + +inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	LLCore::HttpOptions::ptr_t & options, +	LLCore::HttpHeaders::ptr_t & headers, +	LLCore::HttpHandler * handler) +{ +    return requestPutWithLLSD(request.get(), policy_id, priority, +        url, body, options.get(), headers.get(), handler); +} + +inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpHandler * handler) +{ +    return requestPutWithLLSD(request.get(), policy_id, priority, +        url, body, NULL, NULL, handler); +} + +/// Issue a standard HttpRequest::requestPatch() call but using +/// and LLSD object as the request body.  Conventions are the +/// same as with that method.  Caller is expected to provide +/// an HttpHeaders object with a correct 'Content-Type:' header. +/// One will not be provided by this call. +/// +/// @return				If request is successfully issued, the +///						HttpHandle representing the request. +///						On error, LLCORE_HTTP_HANDLE_INVALID +///						is returned and caller can fetch detailed +///						status with the getStatus() method on the +///						request object.  In case of error, no +///						request is queued and caller may need to +///						perform additional cleanup such as freeing +///						a now-useless HttpHandler object. +/// +LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpOptions * options, +    LLCore::HttpHeaders * headers, +    LLCore::HttpHandler * handler); + +inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpOptions::ptr_t & options, +    LLCore::HttpHeaders::ptr_t & headers, +    LLCore::HttpHandler * handler) +{ +    return requestPatchWithLLSD(request.get(), policy_id, priority, +        url, body, options.get(), headers.get(), handler); +} + +inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpHandler * handler) +{ +    return requestPatchWithLLSD(request.get(), policy_id, priority, +        url, body, NULL, NULL, handler); +} + +//========================================================================= +/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines. When the request is completed the response  +/// will be posted onto the supplied Event Pump. +///  +/// The LLSD posted back to the coroutine will have the following additions: +/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status +///                      +- ["status"]  - The status code associated with the HTTP call +///                      +- ["success"] - Success of failure of the HTTP call and LLSD parsing. +///                      +- ["type"]    - The LLCore::HttpStatus type associted with the HTTP call +///                      +- ["url"]     - The URL used to make the call. +///                      +- ["headers"] - A map of name name value pairs with the HTTP headers. +///                       +class HttpCoroHandler : public LLCore::HttpHandler +{ +public: + +    typedef boost::shared_ptr<HttpCoroHandler>  ptr_t; +    typedef boost::weak_ptr<HttpCoroHandler>    wptr_t; +    HttpCoroHandler(LLEventStream &reply); + +    static void writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result); + +    virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +    inline LLEventStream &getReplyPump() +    { +        return mReplyPump; +    } + +protected: +    /// this method may modify the status value +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) = 0; + +private: +    void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result); + +    LLEventStream &mReplyPump; +}; + +//========================================================================= +/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine  +/// interaction. +///  +/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After  +/// any application specific setup call the post, put or get method.  The request  +/// will be automatically pumped and the method will return with an LLSD describing +/// the result of the operation.  See HttpCoroHandler for a description of the  +/// decoration done to the returned LLSD. +///  +/// Posting through the adapter will automatically add the following headers to  +/// the request if they have not been previously specified in a supplied  +/// HttpHeaders object: +///     "Accept=application/llsd+xml" +///     "X-SecondLife-UDP-Listen-Port=###" +///      +class HttpCoroutineAdapter +{ +public: +    static const std::string HTTP_RESULTS; +    static const std::string HTTP_RESULTS_SUCCESS; +    static const std::string HTTP_RESULTS_TYPE; +    static const std::string HTTP_RESULTS_STATUS; +    static const std::string HTTP_RESULTS_MESSAGE; +    static const std::string HTTP_RESULTS_URL; +    static const std::string HTTP_RESULTS_HEADERS; +    static const std::string HTTP_RESULTS_CONTENT; +    static const std::string HTTP_RESULTS_RAW; + +    typedef boost::shared_ptr<HttpCoroutineAdapter> ptr_t; +    typedef boost::weak_ptr<HttpCoroutineAdapter>   wptr_t; + +    HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId, +        LLCore::HttpRequest::priority_t priority = 0L); +    ~HttpCoroutineAdapter(); + +    /// Execute a Post transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available.  +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD postAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, const LLSD & body, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD postAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, LLCore::BufferArray::ptr_t rawbody, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD postAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, const LLSD & body, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return postAndYield(request, url, body, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + +    LLSD postAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::BufferArray::ptr_t &rawbody, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return postAndYield(request, url, rawbody, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + +    LLSD postRawAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, LLCore::BufferArray::ptr_t rawbody, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); + +    LLSD postRawAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::BufferArray::ptr_t &rawbody, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return postRawAndYield(request, url, rawbody, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + +    LLSD postFileAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, std::string fileName, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); + +    LLSD postFileAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, std::string fileName, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return postFileAndYield(request, url, fileName, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + + +    LLSD postFileAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, LLUUID assetId, LLAssetType::EType assetType, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); + +    LLSD postFileAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, LLUUID assetId, LLAssetType::EType assetType, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return postFileAndYield(request, url, assetId, assetType, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + + +    /// Execute a Put transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available. +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD putAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, const LLSD & body, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); + +    /// Execute a Get transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available. +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD getAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD getAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::HttpHeaders::ptr_t &headers) +    { +        return getAndYield(request, url, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +            headers); +    } + +    LLSD getRawAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD getRawAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::HttpHeaders::ptr_t &headers) +    { +        return getRawAndYield(request, url, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +            headers); +    } + +    LLSD getJsonAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD getJsonndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::HttpHeaders::ptr_t &headers) +    { +        return getJsonAndYield(request, url, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +            headers); +    } + + +    /// Execute a DELETE transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available. +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD deleteAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); + +    /// +    void cancelYieldingOperation(); + +    static LLCore::HttpStatus getStatusFromLLSD(const LLSD &httpResults); + +    /// The convenience routines below can be provided with callback functors  +    /// which will be invoked in the case of success or failure.  These callbacks +    /// should match this form. +    /// @sa callbackHttpGet +    /// @sa callbackHttpPost +    typedef boost::function<void(const LLSD &)> completionCallback_t; + +    static void callbackHttpGet(const std::string &url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success = NULL, completionCallback_t failure = NULL); +    static void callbackHttpGet(const std::string &url, completionCallback_t success = NULL, completionCallback_t failure = NULL) +    { +        callbackHttpGet(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, success, failure); +    } +    static void callbackHttpPost(const std::string &url, LLCore::HttpRequest::policy_t policyId, const LLSD &postData, completionCallback_t success = NULL, completionCallback_t failure = NULL); +    static void callbackHttpPost(const std::string &url, const LLSD &postData, completionCallback_t success = NULL, completionCallback_t failure = NULL) +    { +        callbackHttpPost(url, LLCore::HttpRequest::DEFAULT_POLICY_ID, postData, success, failure); +    } + +    /// Generic Get and post routines for HTTP via coroutines. +    /// These static methods do all required setup for the GET or POST operation. +    /// When the operation completes successfully they will put the success message in the log at INFO level,  +    /// If the operation fails the failure message is written to the log at WARN level. +    ///  +    static void messageHttpGet(const std::string &url, const std::string &success = std::string(), const std::string &failure = std::string()); +    static void messageHttpPost(const std::string &url, const LLSD &postData, const std::string &success, const std::string &failure); + + +private: +    static LLSD buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, const std::string &url); + +    void saveState(LLCore::HttpHandle yieldingHandle, LLCore::HttpRequest::ptr_t &request, +            HttpCoroHandler::ptr_t &handler); +    void cleanState(); + +    LLSD postAndYield_(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, const LLSD & body, +        LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +        HttpCoroHandler::ptr_t &handler); + +    LLSD postAndYield_(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::BufferArray::ptr_t &rawbody, +        LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +        HttpCoroHandler::ptr_t &handler); + +    LLSD putAndYield_(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, const LLSD & body, +        LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +        HttpCoroHandler::ptr_t &handler); + +    LLSD getAndYield_(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::HttpOptions::ptr_t &options,  +        LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler); + +    LLSD deleteAndYield_(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, LLCore::HttpOptions::ptr_t &options, +        LLCore::HttpHeaders::ptr_t &headers, HttpCoroHandler::ptr_t &handler); + +    static void trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure); +    static void trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure); + +    void checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers); + +    std::string                     mAdapterName; +    LLCore::HttpRequest::priority_t mPriority; +    LLCore::HttpRequest::policy_t   mPolicyId; + +    LLCore::HttpHandle              mYieldingHandle; +    LLCore::HttpRequest::wptr_t     mWeakRequest; +    HttpCoroHandler::wptr_t         mWeakHandler; +}; + + +} // end namespace LLCoreHttpUtil  #endif // LL_LLCOREHTTPUTIL_H diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 73df47b933..ef28a4d211 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -69,13 +69,15 @@  	do this.   */ +// *TODO: TSN remove the commented code from this file  //////////////////////////////////////////////////////////////////////////////  static const U32 EASY_HANDLE_POOL_SIZE		= 5;  static const S32 MULTI_PERFORM_CALL_REPEAT	= 5;  static const S32 CURL_REQUEST_TIMEOUT = 120; // seconds per operation  static const S32 CURL_CONNECT_TIMEOUT = 30; //seconds to wait for a connection -static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; + +//static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;  // DEBUG //  S32 gCurlEasyCount = 0; @@ -676,6 +678,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  }  //////////////////////////////////////////////////////////////////////////// +#if 1  LLCurl::Multi::Multi(F32 idle_time_out)  	: mQueued(0),  	  mErrorCount(0), @@ -1056,6 +1059,7 @@ void LLCurl::Multi::removeEasy(Easy* easy)  	easyFree(easy);  } +#endif  //------------------------------------------------------------  //LLCurlThread  LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) : @@ -1176,428 +1180,428 @@ std::string LLCurl::strerror(CURLcode errorcode)  // For generating a simple request for data  // using one multi and one easy per request  -LLCurlRequest::LLCurlRequest() : -	mActiveMulti(NULL), -	mActiveRequestCount(0) -{ -	mProcessing = FALSE; -} - -LLCurlRequest::~LLCurlRequest() -{ -	//stop all Multi handle background threads -	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter) -	{ -		LLCurl::getCurlThread()->killMulti(*iter) ; -	} -	mMultiSet.clear() ; -} - -void LLCurlRequest::addMulti() -{ -	LLCurl::Multi* multi = new LLCurl::Multi(); -	if(!multi->isValid()) -	{ -		LLCurl::getCurlThread()->killMulti(multi) ; -		mActiveMulti = NULL ; -		mActiveRequestCount = 0 ; -		return; -	} -	 -	mMultiSet.insert(multi); -	mActiveMulti = multi; -	mActiveRequestCount = 0; -} - -LLCurl::Easy* LLCurlRequest::allocEasy() -{ -	if (!mActiveMulti || -		mActiveRequestCount	>= MAX_ACTIVE_REQUEST_COUNT || -		mActiveMulti->mErrorCount > 0) -	{ -		addMulti(); -	} -	if(!mActiveMulti) -	{ -		return NULL ; -	} - -	//llassert_always(mActiveMulti); -	++mActiveRequestCount; -	LLCurl::Easy* easy = mActiveMulti->allocEasy(); -	return easy; -} - -bool LLCurlRequest::addEasy(LLCurl::Easy* easy) -{ -	llassert_always(mActiveMulti); -	 -	if (mProcessing) -	{ -		LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL; -	} -	bool res = mActiveMulti->addEasy(easy); -	return res; -} - -void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder) -{ -	getByteRange(url, headers_t(), 0, -1, responder); -} - -// Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or -// the remainder of the file if not. -bool LLCurlRequest::getByteRange(const std::string& url, -								 const headers_t& headers, -								 S32 offset, S32 length, -								 LLCurl::ResponderPtr responder) -{ -	llassert(LLCurl::sNotQuitting); -	LLCurl::Easy* easy = allocEasy(); -	if (!easy) -	{ -		return false; -	} -	easy->prepRequest(url, headers, responder); -	easy->setopt(CURLOPT_HTTPGET, 1); -	if (length > 0) -	{ -		std::string range = llformat("bytes=%d-%d", offset,offset+length-1); -		easy->slist_append(HTTP_OUT_HEADER_RANGE, range); -	} -	else if (offset > 0) -	{ -		std::string range = llformat("bytes=%d-", offset); -		easy->slist_append(HTTP_OUT_HEADER_RANGE, range); -	} -	easy->setHeaders(); -	bool res = addEasy(easy); -	return res; -} - -bool LLCurlRequest::post(const std::string& url, -						 const headers_t& headers, -						 const LLSD& data, -						 LLCurl::ResponderPtr responder, S32 time_out) -{ -	llassert(LLCurl::sNotQuitting); -	LLCurl::Easy* easy = allocEasy(); -	if (!easy) -	{ -		return false; -	} -	easy->prepRequest(url, headers, responder, time_out); - -	LLSDSerialize::toXML(data, easy->getInput()); -	S32 bytes = easy->getInput().str().length(); -	 -	easy->setopt(CURLOPT_POST, 1); -	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); -	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - -	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); -	easy->setHeaders(); - -	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; -	bool res = addEasy(easy); -	return res; -} - -bool LLCurlRequest::post(const std::string& url, -						 const headers_t& headers, -						 const std::string& data, -						 LLCurl::ResponderPtr responder, S32 time_out) -{ -	llassert(LLCurl::sNotQuitting); -	LLCurl::Easy* easy = allocEasy(); -	if (!easy) -	{ -		return false; -	} -	easy->prepRequest(url, headers, responder, time_out); - -	easy->getInput().write(data.data(), data.size()); -	S32 bytes = easy->getInput().str().length(); -	 -	easy->setopt(CURLOPT_POST, 1); -	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); -	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - -	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); -	easy->setHeaders(); - -	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; -	bool res = addEasy(easy); -	return res; -} - -// Note: call once per frame -S32 LLCurlRequest::process() -{ -	S32 res = 0; - -	mProcessing = TRUE; -	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); -		 iter != mMultiSet.end(); ) -	{ -		curlmulti_set_t::iterator curiter = iter++; -		LLCurl::Multi* multi = *curiter; - -		if(!multi->isValid()) -		{ -			if(multi == mActiveMulti) -			{				 -				mActiveMulti = NULL ; -				mActiveRequestCount = 0 ; -			} -			mMultiSet.erase(curiter) ; -			LLCurl::getCurlThread()->killMulti(multi) ; -			continue ; -		} - -		S32 tres = multi->process(); -		res += tres; -		if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0) -		{ -			mMultiSet.erase(curiter); -			LLCurl::getCurlThread()->killMulti(multi); -		} -	} -	mProcessing = FALSE; -	return res; -} - -S32 LLCurlRequest::getQueued() -{ -	S32 queued = 0; -	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); -		 iter != mMultiSet.end(); ) -	{ -		curlmulti_set_t::iterator curiter = iter++; -		LLCurl::Multi* multi = *curiter; -		 -		if(!multi->isValid()) -		{ -			if(multi == mActiveMulti) -			{				 -				mActiveMulti = NULL ; -				mActiveRequestCount = 0 ; -			} -			LLCurl::getCurlThread()->killMulti(multi); -			mMultiSet.erase(curiter) ; -			continue ; -		} - -		queued += multi->mQueued; -		if (multi->getState() != LLCurl::Multi::STATE_READY) -		{ -			++queued; -		} -	} -	return queued; -} - -LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :  -	LLCurlRequest(),  -	mConcurrency(concurrency), -	mInQueue(0), -	mMutex(NULL), -	mHandleCounter(1), -	mTotalIssuedRequests(0), -	mTotalReceivedBits(0) -{ -	mGlobalTimer.reset(); -} - -LLCurlTextureRequest::~LLCurlTextureRequest() -{ -	mRequestMap.clear(); - -	for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter) -	{ -		delete *iter; -	} -	mCachedRequests.clear(); -} - -//return 0: success -// > 0: cached handle -U32 LLCurlTextureRequest::getByteRange(const std::string& url, -								 const headers_t& headers, -								 S32 offset, S32 length, U32 pri, -								 LLCurl::ResponderPtr responder, F32 delay_time) -{ -	U32 ret_val = 0; -	bool success = false;	 - -	if(mInQueue < mConcurrency && delay_time < 0.f) -	{ -		success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);		 -	} - -	LLMutexLock lock(&mMutex); - -	if(success) -	{ -		mInQueue++; -		mTotalIssuedRequests++; -	} -	else -	{ -		request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder); -		if(delay_time > 0.f) -		{ -			request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time; -		} - -		mCachedRequests.insert(request); -		mRequestMap[mHandleCounter] = request; -		ret_val = mHandleCounter; -		mHandleCounter++; - -		if(!mHandleCounter) -		{ -			mHandleCounter = 1; -		} -	} - -	return ret_val; -} - -void LLCurlTextureRequest::completeRequest(S32 received_bytes) -{ -	LLMutexLock lock(&mMutex); - -	llassert_always(mInQueue > 0); - -	mInQueue--; -	mTotalReceivedBits += received_bytes * 8; -} - -void LLCurlTextureRequest::nextRequests() -{ -	if(mCachedRequests.empty() || mInQueue >= mConcurrency) -	{ -		return; -	} - -	F32 cur_time = mGlobalTimer.getElapsedTimeF32(); - -	req_queue_t::iterator iter;	 -	{ -		LLMutexLock lock(&mMutex); -		iter = mCachedRequests.begin(); -	} -	while(1) -	{ -		request_t* request = *iter; -		if(request->mStartTime < cur_time) -		{ -			if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder)) -			{ -				break; -			} - -			LLMutexLock lock(&mMutex); -			++iter; -			mInQueue++; -			mTotalIssuedRequests++; -			mCachedRequests.erase(request); -			mRequestMap.erase(request->mHandle); -			delete request; - -			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) -			{ -				break; -			} -		} -		else -		{ -			LLMutexLock lock(&mMutex); -			++iter; -			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) -			{ -				break; -			} -		} -	} - -	return; -} - -void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri) -{ -	if(!handle) -	{ -		return; -	} - -	LLMutexLock lock(&mMutex); - -	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); -	if(iter != mRequestMap.end()) -	{ -		request_t* req = iter->second; -		 -		if(req->mPriority != pri) -		{ -			mCachedRequests.erase(req); -			req->mPriority = pri; -			mCachedRequests.insert(req); -		} -	} -} - -void LLCurlTextureRequest::removeRequest(U32 handle) -{ -	if(!handle) -	{ -		return; -	} - -	LLMutexLock lock(&mMutex); - -	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); -	if(iter != mRequestMap.end()) -	{ -		request_t* req = iter->second; -		mRequestMap.erase(iter); -		mCachedRequests.erase(req); -		delete req; -	} -} - -bool LLCurlTextureRequest::isWaiting(U32 handle) -{ -	if(!handle) -	{ -		return false; -	} - -	LLMutexLock lock(&mMutex); -	return mRequestMap.find(handle) != mRequestMap.end(); -} - -U32 LLCurlTextureRequest::getTotalReceivedBits() -{ -	LLMutexLock lock(&mMutex); - -	U32 bits = mTotalReceivedBits; -	mTotalReceivedBits = 0; -	return bits; -} - -U32 LLCurlTextureRequest::getTotalIssuedRequests() -{ -	LLMutexLock lock(&mMutex); -	return mTotalIssuedRequests; -} - -S32 LLCurlTextureRequest::getNumRequests() -{ -	LLMutexLock lock(&mMutex); -	return mInQueue; -} +// LLCurlRequest::LLCurlRequest() : +// 	mActiveMulti(NULL), +// 	mActiveRequestCount(0) +// { +// 	mProcessing = FALSE; +// } +//  +// LLCurlRequest::~LLCurlRequest() +// { +// 	//stop all Multi handle background threads +// 	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter) +// 	{ +// 		LLCurl::getCurlThread()->killMulti(*iter) ; +// 	} +// 	mMultiSet.clear() ; +// } +//  +// void LLCurlRequest::addMulti() +// { +// 	LLCurl::Multi* multi = new LLCurl::Multi(); +// 	if(!multi->isValid()) +// 	{ +// 		LLCurl::getCurlThread()->killMulti(multi) ; +// 		mActiveMulti = NULL ; +// 		mActiveRequestCount = 0 ; +// 		return; +// 	} +// 	 +// 	mMultiSet.insert(multi); +// 	mActiveMulti = multi; +// 	mActiveRequestCount = 0; +// } +//  +// LLCurl::Easy* LLCurlRequest::allocEasy() +// { +// 	if (!mActiveMulti || +// 		mActiveRequestCount	>= MAX_ACTIVE_REQUEST_COUNT || +// 		mActiveMulti->mErrorCount > 0) +// 	{ +// 		addMulti(); +// 	} +// 	if(!mActiveMulti) +// 	{ +// 		return NULL ; +// 	} +//  +// 	//llassert_always(mActiveMulti); +// 	++mActiveRequestCount; +// 	LLCurl::Easy* easy = mActiveMulti->allocEasy(); +// 	return easy; +// } +//  +// bool LLCurlRequest::addEasy(LLCurl::Easy* easy) +// { +// 	llassert_always(mActiveMulti); +// 	 +// 	if (mProcessing) +// 	{ +// 		LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL; +// 	} +// 	bool res = mActiveMulti->addEasy(easy); +// 	return res; +// } +//  +// void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder) +// { +// 	getByteRange(url, headers_t(), 0, -1, responder); +// } +//  +// // Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or +// // the remainder of the file if not. +// bool LLCurlRequest::getByteRange(const std::string& url, +// 								 const headers_t& headers, +// 								 S32 offset, S32 length, +// 								 LLCurl::ResponderPtr responder) +// { +// 	llassert(LLCurl::sNotQuitting); +// 	LLCurl::Easy* easy = allocEasy(); +// 	if (!easy) +// 	{ +// 		return false; +// 	} +// 	easy->prepRequest(url, headers, responder); +// 	easy->setopt(CURLOPT_HTTPGET, 1); +// 	if (length > 0) +// 	{ +// 		std::string range = llformat("bytes=%d-%d", offset,offset+length-1); +// 		easy->slist_append(HTTP_OUT_HEADER_RANGE, range); +// 	} +// 	else if (offset > 0) +// 	{ +// 		std::string range = llformat("bytes=%d-", offset); +// 		easy->slist_append(HTTP_OUT_HEADER_RANGE, range); +// 	} +// 	easy->setHeaders(); +// 	bool res = addEasy(easy); +// 	return res; +// } +//  +// bool LLCurlRequest::post(const std::string& url, +// 						 const headers_t& headers, +// 						 const LLSD& data, +// 						 LLCurl::ResponderPtr responder, S32 time_out) +// { +// 	llassert(LLCurl::sNotQuitting); +// 	LLCurl::Easy* easy = allocEasy(); +// 	if (!easy) +// 	{ +// 		return false; +// 	} +// 	easy->prepRequest(url, headers, responder, time_out); +//  +// 	LLSDSerialize::toXML(data, easy->getInput()); +// 	S32 bytes = easy->getInput().str().length(); +// 	 +// 	easy->setopt(CURLOPT_POST, 1); +// 	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); +// 	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); +//  +// 	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); +// 	easy->setHeaders(); +//  +// 	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; +// 	bool res = addEasy(easy); +// 	return res; +// } +//  +// bool LLCurlRequest::post(const std::string& url, +// 						 const headers_t& headers, +// 						 const std::string& data, +// 						 LLCurl::ResponderPtr responder, S32 time_out) +// { +// 	llassert(LLCurl::sNotQuitting); +// 	LLCurl::Easy* easy = allocEasy(); +// 	if (!easy) +// 	{ +// 		return false; +// 	} +// 	easy->prepRequest(url, headers, responder, time_out); +//  +// 	easy->getInput().write(data.data(), data.size()); +// 	S32 bytes = easy->getInput().str().length(); +// 	 +// 	easy->setopt(CURLOPT_POST, 1); +// 	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); +// 	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); +//  +// 	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); +// 	easy->setHeaders(); +//  +// 	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; +// 	bool res = addEasy(easy); +// 	return res; +// } +//  +// // Note: call once per frame +// S32 LLCurlRequest::process() +// { +// 	S32 res = 0; +//  +// 	mProcessing = TRUE; +// 	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); +// 		 iter != mMultiSet.end(); ) +// 	{ +// 		curlmulti_set_t::iterator curiter = iter++; +// 		LLCurl::Multi* multi = *curiter; +//  +// 		if(!multi->isValid()) +// 		{ +// 			if(multi == mActiveMulti) +// 			{				 +// 				mActiveMulti = NULL ; +// 				mActiveRequestCount = 0 ; +// 			} +// 			mMultiSet.erase(curiter) ; +// 			LLCurl::getCurlThread()->killMulti(multi) ; +// 			continue ; +// 		} +//  +// 		S32 tres = multi->process(); +// 		res += tres; +// 		if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0) +// 		{ +// 			mMultiSet.erase(curiter); +// 			LLCurl::getCurlThread()->killMulti(multi); +// 		} +// 	} +// 	mProcessing = FALSE; +// 	return res; +// } +//  +// S32 LLCurlRequest::getQueued() +// { +// 	S32 queued = 0; +// 	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); +// 		 iter != mMultiSet.end(); ) +// 	{ +// 		curlmulti_set_t::iterator curiter = iter++; +// 		LLCurl::Multi* multi = *curiter; +// 		 +// 		if(!multi->isValid()) +// 		{ +// 			if(multi == mActiveMulti) +// 			{				 +// 				mActiveMulti = NULL ; +// 				mActiveRequestCount = 0 ; +// 			} +// 			LLCurl::getCurlThread()->killMulti(multi); +// 			mMultiSet.erase(curiter) ; +// 			continue ; +// 		} +//  +// 		queued += multi->mQueued; +// 		if (multi->getState() != LLCurl::Multi::STATE_READY) +// 		{ +// 			++queued; +// 		} +// 	} +// 	return queued; +// } + +// LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) :  +// 	LLCurlRequest(),  +// 	mConcurrency(concurrency), +// 	mInQueue(0), +// 	mMutex(NULL), +// 	mHandleCounter(1), +// 	mTotalIssuedRequests(0), +// 	mTotalReceivedBits(0) +// { +// 	mGlobalTimer.reset(); +// } +//  +// LLCurlTextureRequest::~LLCurlTextureRequest() +// { +// 	mRequestMap.clear(); +//  +// 	for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter) +// 	{ +// 		delete *iter; +// 	} +// 	mCachedRequests.clear(); +// } +//  +// //return 0: success +// // > 0: cached handle +// U32 LLCurlTextureRequest::getByteRange(const std::string& url, +// 								 const headers_t& headers, +// 								 S32 offset, S32 length, U32 pri, +// 								 LLCurl::ResponderPtr responder, F32 delay_time) +// { +// 	U32 ret_val = 0; +// 	bool success = false;	 +//  +// 	if(mInQueue < mConcurrency && delay_time < 0.f) +// 	{ +// 		success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);		 +// 	} +//  +// 	LLMutexLock lock(&mMutex); +//  +// 	if(success) +// 	{ +// 		mInQueue++; +// 		mTotalIssuedRequests++; +// 	} +// 	else +// 	{ +// 		request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder); +// 		if(delay_time > 0.f) +// 		{ +// 			request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time; +// 		} +//  +// 		mCachedRequests.insert(request); +// 		mRequestMap[mHandleCounter] = request; +// 		ret_val = mHandleCounter; +// 		mHandleCounter++; +//  +// 		if(!mHandleCounter) +// 		{ +// 			mHandleCounter = 1; +// 		} +// 	} +//  +// 	return ret_val; +// } +//  +// void LLCurlTextureRequest::completeRequest(S32 received_bytes) +// { +// 	LLMutexLock lock(&mMutex); +//  +// 	llassert_always(mInQueue > 0); +//  +// 	mInQueue--; +// 	mTotalReceivedBits += received_bytes * 8; +// } +//  +// void LLCurlTextureRequest::nextRequests() +// { +// 	if(mCachedRequests.empty() || mInQueue >= mConcurrency) +// 	{ +// 		return; +// 	} +//  +// 	F32 cur_time = mGlobalTimer.getElapsedTimeF32(); +//  +// 	req_queue_t::iterator iter;	 +// 	{ +// 		LLMutexLock lock(&mMutex); +// 		iter = mCachedRequests.begin(); +// 	} +// 	while(1) +// 	{ +// 		request_t* request = *iter; +// 		if(request->mStartTime < cur_time) +// 		{ +// 			if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder)) +// 			{ +// 				break; +// 			} +//  +// 			LLMutexLock lock(&mMutex); +// 			++iter; +// 			mInQueue++; +// 			mTotalIssuedRequests++; +// 			mCachedRequests.erase(request); +// 			mRequestMap.erase(request->mHandle); +// 			delete request; +//  +// 			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) +// 			{ +// 				break; +// 			} +// 		} +// 		else +// 		{ +// 			LLMutexLock lock(&mMutex); +// 			++iter; +// 			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) +// 			{ +// 				break; +// 			} +// 		} +// 	} +//  +// 	return; +// } +//  +// void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri) +// { +// 	if(!handle) +// 	{ +// 		return; +// 	} +//  +// 	LLMutexLock lock(&mMutex); +//  +// 	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); +// 	if(iter != mRequestMap.end()) +// 	{ +// 		request_t* req = iter->second; +// 		 +// 		if(req->mPriority != pri) +// 		{ +// 			mCachedRequests.erase(req); +// 			req->mPriority = pri; +// 			mCachedRequests.insert(req); +// 		} +// 	} +// } +//  +// void LLCurlTextureRequest::removeRequest(U32 handle) +// { +// 	if(!handle) +// 	{ +// 		return; +// 	} +//  +// 	LLMutexLock lock(&mMutex); +//  +// 	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); +// 	if(iter != mRequestMap.end()) +// 	{ +// 		request_t* req = iter->second; +// 		mRequestMap.erase(iter); +// 		mCachedRequests.erase(req); +// 		delete req; +// 	} +// } +//  +// bool LLCurlTextureRequest::isWaiting(U32 handle) +// { +// 	if(!handle) +// 	{ +// 		return false; +// 	} +//  +// 	LLMutexLock lock(&mMutex); +// 	return mRequestMap.find(handle) != mRequestMap.end(); +// } +//  +// U32 LLCurlTextureRequest::getTotalReceivedBits() +// { +// 	LLMutexLock lock(&mMutex); +//  +// 	U32 bits = mTotalReceivedBits; +// 	mTotalReceivedBits = 0; +// 	return bits; +// } +//  +// U32 LLCurlTextureRequest::getTotalIssuedRequests() +// { +// 	LLMutexLock lock(&mMutex); +// 	return mTotalIssuedRequests; +// } +//  +// S32 LLCurlTextureRequest::getNumRequests() +// { +// 	LLMutexLock lock(&mMutex); +// 	return mInQueue; +// }  ////////////////////////////////////////////////////////////////////////////  // For generating one easy request @@ -1988,10 +1992,10 @@ void LLCurlFF::check_easy_code(CURLcode code)  {  	check_curl_code(code);  } -void LLCurlFF::check_multi_code(CURLMcode code) -{ -	check_curl_multi_code(code); -} +// void LLCurlFF::check_multi_code(CURLMcode code) +// { +// 	check_curl_multi_code(code); +// }  // Static diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 385d9fffa8..06b3ce45e1 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -418,100 +418,6 @@ private:  } ; -class LLCurlRequest -{ -public: -	typedef std::vector<std::string> headers_t; -	 -	LLCurlRequest(); -	~LLCurlRequest(); - -	void get(const std::string& url, LLCurl::ResponderPtr responder); -	bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder); -	bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0); -	bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0); -	 -	S32  process(); -	S32  getQueued(); - -private: -	void addMulti(); -	LLCurl::Easy* allocEasy(); -	bool addEasy(LLCurl::Easy* easy); -	 -private: -	typedef std::set<LLCurl::Multi*> curlmulti_set_t; -	curlmulti_set_t mMultiSet; -	LLCurl::Multi* mActiveMulti; -	S32 mActiveRequestCount; -	BOOL mProcessing; -}; - -//for texture fetch only -class LLCurlTextureRequest : public LLCurlRequest -{ -public: -	LLCurlTextureRequest(S32 concurrency); -	~LLCurlTextureRequest(); - -	U32 getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder, F32 delay_time = -1.f); -	void nextRequests(); -	void completeRequest(S32 received_bytes); - -	void updatePriority(U32 handle, U32 pri); -	void removeRequest(U32 handle); - -	U32 getTotalReceivedBits(); -	U32 getTotalIssuedRequests(); -	S32 getNumRequests(); -	bool isWaiting(U32 handle); -	 -private: -	LLMutex mMutex; -	S32 mConcurrency; -	S32 mInQueue; //request currently in queue. -	U32 mHandleCounter; -	U32 mTotalIssuedRequests; -	U32 mTotalReceivedBits; - -	typedef struct _request_t -	{ -		_request_t(U32 handle, const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder) : -				mHandle(handle), mUrl(url), mHeaders(headers), mOffset(offset), mLength(length), mPriority(pri), mResponder(responder), mStartTime(0.f) -				{} - -		U32  mHandle; -		std::string mUrl; -		LLCurlRequest::headers_t mHeaders; -		S32 mOffset; -		S32 mLength; -		LLCurl::ResponderPtr mResponder; -		U32 mPriority; -		F32 mStartTime; //start time to issue this request -	} request_t; - -	struct request_compare -	{ -		bool operator()(const request_t* lhs, const request_t* rhs) const -		{ -			if(lhs->mPriority != rhs->mPriority) -			{ -				return lhs->mPriority > rhs->mPriority; // higher priority in front of queue (set) -			} -			else -			{ -				return (U32)lhs < (U32)rhs; -			} -		} -	}; - -	typedef std::set<request_t*, request_compare> req_queue_t; -	req_queue_t mCachedRequests; -	std::map<S32, request_t*> mRequestMap; - -	LLFrameTimer mGlobalTimer; -}; -  class LLCurlEasyRequest  {  public: @@ -550,7 +456,7 @@ private:  namespace LLCurlFF  {  	void check_easy_code(CURLcode code); -	void check_multi_code(CURLMcode code); +	//void check_multi_code(CURLMcode code);  }  #endif // LL_LLCURL_H diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index f8db3dded2..7f70e6a3f5 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -38,6 +38,10 @@  #include "lluri.h"  #include "message.h" +#include "httpcommon.h" +#include "httprequest.h" +#include "httpoptions.h" +  #include <curl/curl.h> diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp deleted file mode 100755 index b56a804f94..0000000000 --- a/indra/llmessage/llhttpclientadapter.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/**  - * @file llhttpclientadapter.cpp - * @brief  - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llhttpclientadapter.h" -#include "llhttpclient.h" - -LLHTTPClientAdapter::~LLHTTPClientAdapter()  -{ -} - -void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder)  -{ -	LLSD empty_pragma_header; -	// Pragma is required to stop curl adding "no-cache" -	// Space is required to stop llurlrequest from turning off proxying -	empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";  -	LLHTTPClient::get(url, responder, empty_pragma_header); -} - -void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)  -{ -	LLSD empty_pragma_header = headers; -	if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA)) -	{ -		// as above -		empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " "; -	} -	LLHTTPClient::get(url, responder, empty_pragma_header); -} - -void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder)  -{ -	LLHTTPClient::put(url, body, responder); -} - -void LLHTTPClientAdapter::put( -		const std::string& url, -		const LLSD& body, -		LLCurl::ResponderPtr responder, -		const LLSD& headers) -{ -	LLHTTPClient::put(url, body, responder, headers); -} - -void LLHTTPClientAdapter::del( -	const std::string& url, -	LLCurl::ResponderPtr responder) -{ -	LLHTTPClient::del(url, responder); -} diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h deleted file mode 100755 index 270282c66f..0000000000 --- a/indra/llmessage/llhttpclientadapter.h +++ /dev/null @@ -1,51 +0,0 @@ -/**  - * @file llhttpclientadepter.h - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_HTTPCLIENTADAPTER_H -#define LL_HTTPCLIENTADAPTER_H - -#include "llhttpclientinterface.h" -#include "llsingleton.h"	// LLSingleton<> - -class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLHTTPClientAdapter> -{ -public: -	virtual ~LLHTTPClientAdapter(); -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder); -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers); -	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder); -	virtual void put( -		const std::string& url, -		const LLSD& body, -		LLCurl::ResponderPtr responder, -		const LLSD& headers); -	virtual void del( -		const std::string& url, -		LLCurl::ResponderPtr responder); -}; - -#endif - diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h index 12a3857a61..9c1c8e7c11 100755 --- a/indra/llmessage/llhttpclientinterface.h +++ b/indra/llmessage/llhttpclientinterface.h @@ -32,14 +32,14 @@  #include <string> -class LLHTTPClientInterface -{ -public: -	virtual ~LLHTTPClientInterface() {} -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0; -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0; -	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0; -}; +// class LLHTTPClientInterface +// { +// public: +// 	virtual ~LLHTTPClientInterface() {} +// 	virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0; +// 	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0; +// 	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0; +// };  #endif // LL_LLHTTPCLIENTINTERFACE_H diff --git a/indra/llmessage/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp new file mode 100644 index 0000000000..d99bdd3f66 --- /dev/null +++ b/indra/llmessage/llhttpsdhandler.cpp @@ -0,0 +1,105 @@ +/** +* @file llhttpsdhandler.h +* @brief Public-facing declarations for the HttpHandler class +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" +#include "llhttpconstants.h" + +#include "llhttpsdhandler.h" +#include "httpresponse.h" +#include "httpheaders.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "bufferstream.h" +#include "llcorehttputil.h" + +//======================================================================== +LLHttpSDHandler::LLHttpSDHandler(bool selfDelete): +    mSelfDelete(selfDelete) +{ +} + +void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +	LLCore::HttpStatus status = response->getStatus(); + +	if (!status) +	{ +		this->onFailure(response, status); +	} +	else +	{ +		LLSD resplsd; +		const bool emit_parse_errors = false; + +		bool parsed = !((response->getBodySize() == 0) || +			!LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd)); + +		if (!parsed)  +		{ +			// Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' +			LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); +			const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; + +			if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) +			{ +				std::string thebody = LLCoreHttpUtil::responseToString(response); + +				LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " +					<< " body: " << thebody << LL_ENDL; +			} +		} + +		this->onSuccess(response, resplsd); +	} + +	// The handler must destroy itself when it is done.  +	// *TODO: I'm not fond of this pattern. A class shooting itself in the head  +	// outside of a smart pointer always makes me nervous. +    if (mSelfDelete) +    	delete this; +} + +//======================================================================== +LLHttpSDGenericHandler::LLHttpSDGenericHandler(const std::string &name, bool selfDelete): +	LLHttpSDHandler(selfDelete), +	mName(name) +{ +} + +void LLHttpSDGenericHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) +{ +	LL_DEBUGS() << mName << " Success." << LL_ENDL; +} + +void LLHttpSDGenericHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) +{ +	LL_WARNS() +		<< "\n--------------------------------------------------------------------------\n" +		<< mName << " Error[" << status.toULong() << "] cannot access cap with url '"  +		<< response->getRequestURL() << "' because " << status.toString() +		<< "\n--------------------------------------------------------------------------" +		<< LL_ENDL; +} diff --git a/indra/llmessage/llhttpsdhandler.h b/indra/llmessage/llhttpsdhandler.h new file mode 100644 index 0000000000..3b81dc66b9 --- /dev/null +++ b/indra/llmessage/llhttpsdhandler.h @@ -0,0 +1,72 @@ +/** +* @file llhttpsdhandler.h +* @brief Public-facing declarations for the HttpHandler class +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#ifndef	_LLHTTPSDHANDLER_H_ +#define	_LLHTTPSDHANDLER_H_ +#include "httpcommon.h" +#include "httphandler.h" +#include "lluri.h" + +/// Handler class LLCore's HTTP library. Splitting with separate success and  +/// failure routines and parsing the result body into LLSD on success.  It  +/// is intended to be subclassed for specific capability handling. +///  +// *TODO: This class self deletes at the end of onCompleted method.  This is  +// less than ideal and should be revisited. +class LLHttpSDHandler : public LLCore::HttpHandler //, +//    public std::enable_shared_from_this<LLHttpSDHandler> +{ +public: + +	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); +	 +protected: +    LLHttpSDHandler(bool selfDelete = true); + +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0; +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0; + +private: +    bool mSelfDelete; + +}; + +/// A trivial implementation of LLHttpSDHandler. This success and failure  +/// methods log the action taken, the URI accessed and the status code returned  +/// in the response. +class LLHttpSDGenericHandler : public LLHttpSDHandler +{ +public:  +	LLHttpSDGenericHandler(const std::string &name, bool selfDelete = true); + +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + +private: +	std::string mName; +}; +#endif diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp deleted file mode 100755 index 61fcc5dd2f..0000000000 --- a/indra/llmessage/llsdmessage.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @file   llsdmessage.cpp - * @author Nat Goodspeed - * @date   2008-10-31 - * @brief  Implementation for llsdmessage. - *  - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#if LL_WINDOWS -#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want! -#endif - -// Precompiled header -#include "linden_common.h" -// associated header -#include "llsdmessage.h" -// STL headers -// std headers -// external library headers -// other Linden headers -#include "llevents.h" -#include "llsdserialize.h" -#include "llhttpclient.h" -#include "llmessageconfig.h" -#include "llhost.h" -#include "message.h" -#include "llsdutil.h" - -// Declare a static LLSDMessage instance to ensure that we have a listener as -// soon as someone tries to post on our canonical LLEventPump name. -static LLSDMessage httpListener; - -LLSDMessage::LLSDMessage(): -    // Instantiating our own local LLEventPump with a string name the -    // constructor is NOT allowed to tweak is a way of ensuring Singleton -    // semantics: attempting to instantiate a second LLSDMessage object would -    // throw LLEventPump::DupPumpName. -    mEventPump("LLHTTPClient") -{ -    mEventPump.listen("self", boost::bind(&LLSDMessage::httpListener, this, _1)); -} - -bool LLSDMessage::httpListener(const LLSD& request) -{ -    // Extract what we want from the request object. We do it all up front -    // partly to document what we expect. -    LLSD::String url(request["url"]); -    LLSD payload(request["payload"]); -    LLSD::String reply(request["reply"]); -    LLSD::String error(request["error"]); -    LLSD::Real timeout(request["timeout"]); -    // If the LLSD doesn't even have a "url" key, we doubt it was intended for -    // this listener. -    if (url.empty()) -    { -        std::ostringstream out; -        out << "request event without 'url' key to '" << mEventPump.getName() << "'"; -        throw ArgError(out.str()); -    } -    // Establish default timeout. This test relies on LLSD::asReal() returning -    // exactly 0.0 for an undef value. -    if (! timeout) -    { -        timeout = HTTP_REQUEST_EXPIRY_SECS; -    } -    LLHTTPClient::post(url, payload, -                       new LLSDMessage::EventResponder(LLEventPumps::instance(), -                                                       request, -                                                       url, "POST", reply, error), -                       LLSD(),      // headers -                       (F32)timeout); -    return false; -} - -void LLSDMessage::EventResponder::httpSuccess() -{ -    // If our caller passed an empty replyPump name, they're not -    // listening: this is a fire-and-forget message. Don't bother posting -    // to the pump whose name is "". -    if (! mReplyPump.empty()) -    { -        LLSD response(getContent()); -        mReqID.stamp(response); -        mPumps.obtain(mReplyPump).post(response); -    } -    else                            // default success handling -    { -        LL_INFOS("LLSDMessage::EventResponder") -            << "'" << mMessage << "' to '" << mTarget << "' succeeded" -            << LL_ENDL; -    } -} - -void LLSDMessage::EventResponder::httpFailure() -{ -    // If our caller passed an empty errorPump name, they're not -    // listening: "default error handling is acceptable." Only post to an -    // explicit pump name. -    if (! mErrorPump.empty()) -    { -        LLSD info(mReqID.makeResponse()); -        info["target"]  = mTarget; -        info["message"] = mMessage; -        info["status"]  = getStatus(); -        info["reason"]  = getReason(); -        info["content"] = getContent(); -        mPumps.obtain(mErrorPump).post(info); -    } -    else                        // default error handling -    { -        // convention seems to be to use LL_INFOS(), but that seems a bit casual? -        LL_WARNS("LLSDMessage::EventResponder") -            << "'" << mMessage << "' to '" << mTarget -            << "' failed " << dumpResponse() << LL_ENDL; -    } -} - -LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderPtr responder, -                                                const std::string& name): -    mResponder(responder), -    mReplyPump(name + ".reply", true), // tweak name for uniqueness -    mErrorPump(name + ".error", true) -{ -    mReplyPump.listen("self", boost::bind(&ResponderAdapter::listener, this, _1, true)); -    mErrorPump.listen("self", boost::bind(&ResponderAdapter::listener, this, _1, false)); -} - -bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) -{ -    if (success) -    { -        mResponder->successResult(payload); -    } -    else -    { -        mResponder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"]); -    } - -    /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ -    delete this; -    // Destruction of mResponder will usually implicitly free its referent as well -    /*------------------------- NOTHING AFTER THIS -------------------------*/ -    return false; -} - -void LLSDMessage::link() -{ -} diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h deleted file mode 100755 index e5d532d6a4..0000000000 --- a/indra/llmessage/llsdmessage.h +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @file   llsdmessage.h - * @author Nat Goodspeed - * @date   2008-10-30 - * @brief  API intended to unify sending capability, UDP and TCP messages: - *         https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes - *  - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLSDMESSAGE_H) -#define LL_LLSDMESSAGE_H - -#include "llerror.h"                // LOG_CLASS() -#include "llevents.h"               // LLEventPumps -#include "llhttpclient.h" -#include <string> -#include <stdexcept> - -class LLSD; - -/** - * Class managing the messaging API described in - * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes - */ -class LLSDMessage -{ -    LOG_CLASS(LLSDMessage); - -public: -    LLSDMessage(); - -    /// Exception if you specify arguments badly -    struct ArgError: public std::runtime_error -    { -        ArgError(const std::string& what): -            std::runtime_error(std::string("ArgError: ") + what) {} -    }; - -    /** -     * The response idiom used by LLSDMessage -- LLEventPump names on which to -     * post reply or error -- is designed for the case in which your -     * reply/error handlers are methods on the same class as the method -     * sending the message. Any state available to the sending method that -     * must be visible to the reply/error methods can conveniently be stored -     * on that class itself, if it's not already. -     * -     * The LLHTTPClient::Responder idiom requires a separate instance of a -     * separate class so that it can dispatch to the code of interest by -     * calling canonical virtual methods. Interesting state must be copied -     * into that new object.  -     * -     * With some trepidation, because existing response code is packaged in -     * LLHTTPClient::Responder subclasses, we provide this adapter class -     * <i>for transitional purposes only.</i> Instantiate a new heap -     * ResponderAdapter with your new LLHTTPClient::ResponderPtr. Pass -     * ResponderAdapter::getReplyName() and/or getErrorName() in your -     * LLSDMessage (or LLViewerRegion::getCapAPI()) request event. The -     * ResponderAdapter will call the appropriate Responder method, then -     * @c delete itself. -     */ -    class ResponderAdapter -    { -    public: -        /** -         * Bind the new LLHTTPClient::Responder subclass instance. -         * -         * Passing the constructor a name other than the default is only -         * interesting if you suspect some usage will lead to an exception or -         * log message. -         */ -        ResponderAdapter(LLHTTPClient::ResponderPtr responder, -                         const std::string& name="ResponderAdapter"); - -        /// EventPump name on which LLSDMessage should post reply event -        std::string getReplyName() const { return mReplyPump.getName(); } -        /// EventPump name on which LLSDMessage should post error event -        std::string getErrorName() const { return mErrorPump.getName(); } - -    private: -        // We have two different LLEventStreams, though we route them both to -        // the same listener, so that we can bind an extra flag identifying -        // which case (reply or error) reached that listener. -        bool listener(const LLSD&, bool success); - -        LLHTTPClient::ResponderPtr mResponder; -        LLEventStream mReplyPump, mErrorPump; -    }; - -    /** -     * Force our implementation file to be linked with caller. The .cpp file -     * contains a static instance of this class, which must be linked into the -     * executable to support the canonical listener. But since the primary -     * interface to that static instance is via a named LLEventPump rather -     * than by direct reference, the linker doesn't necessarily perceive the -     * necessity to bring in the translation unit. Referencing this dummy -     * method forces the issue. -     */ -    static void link(); - -private: -    friend class LLCapabilityListener; -    /// Responder used for internal purposes by LLSDMessage and -    /// LLCapabilityListener. Others should use higher-level APIs. -    class EventResponder: public LLHTTPClient::Responder -    { -        LOG_CLASS(EventResponder); -    public: -        /** -         * LLHTTPClient::Responder that dispatches via named LLEventPump instances. -         * We bind LLEventPumps, even though it's an LLSingleton, for testability. -         * We bind the string names of the desired LLEventPump instances rather -         * than actually obtain()ing them so we only obtain() the one we're going -         * to use. If the caller doesn't bother to listen() on it, the other pump -         * may never materialize at all. -         * @a target and @a message are only to clarify error processing. -         * For a capability message, @a target should be the region description, -         * @a message should be the capability name. -         * For a service with a visible URL, pass the URL as @a target and the HTTP verb -         * (e.g. "POST") as @a message. -         */ -        EventResponder(LLEventPumps& pumps, -                       const LLSD& request, -                       const std::string& target, const std::string& message, -                       const std::string& replyPump, const std::string& errorPump): -            mPumps(pumps), -            mReqID(request), -            mTarget(target), -            mMessage(message), -            mReplyPump(replyPump), -            mErrorPump(errorPump) -        {} -     -    protected: -        virtual void httpSuccess(); -        virtual void httpFailure(); -     -    private: -        LLEventPumps& mPumps; -        LLReqID mReqID; -        const std::string mTarget, mMessage, mReplyPump, mErrorPump; -    }; - -private: -    bool httpListener(const LLSD&); -    LLEventStream mEventPump; -}; - -#endif /* ! defined(LL_LLSDMESSAGE_H) */ diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index c4e0333ca3..d097ecdff7 100755 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -37,7 +37,9 @@  #include "llchainio.h"  #include "llfiltersd2xmlrpc.h"  #include "lliopipe.h" -#include "llurlrequest.h" +#if 0 +//#include "llurlrequest.h" +#endif  /**    * @class LLSDRPCClientResponse @@ -218,6 +220,7 @@ protected:  	LLIOPipe::ptr_t mResponse;  }; +#if 0  /**    * @class LLSDRPCClientFactory   * @brief Basic implementation for making an SD RPC client factory @@ -267,7 +270,9 @@ public:  protected:  	std::string mURL;  }; +#endif +#if 0  /**    * @class LLXMLSDRPCClientFactory   * @brief Basic implementation for making an XMLRPC to SD RPC client factory @@ -319,5 +324,6 @@ public:  protected:  	std::string mURL;  }; +#endif  #endif // LL_LLSDRPCCLIENT_H diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp deleted file mode 100755 index e9ce116bb3..0000000000 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/**  - * @file llhttpclientadapter_test.cpp - * @brief Tests for LLHTTPClientAdapter - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llhttpclientadapter.h" - -#include "../test/lltut.h" -#include "llhttpclient.h" -#include "llcurl_stub.cpp" - -float const HTTP_REQUEST_EXPIRY_SECS = 1.0F; - -std::vector<std::string> get_urls; -std::vector< LLCurl::ResponderPtr > get_responders; -void LLHTTPClient::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout, bool follow_redirects) -{ -	get_urls.push_back(url); -	get_responders.push_back(responder); -} - -std::vector<std::string> put_urls; -std::vector<LLSD> put_body; -std::vector<LLSD> put_headers; -std::vector<LLCurl::ResponderPtr> put_responders; - -void LLHTTPClient::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout) -{ -	put_urls.push_back(url); -	put_responders.push_back(responder); -	put_body.push_back(body); -	put_headers.push_back(headers); - -} - -std::vector<std::string> delete_urls; -std::vector<LLCurl::ResponderPtr> delete_responders; - -void LLHTTPClient::del( -	const std::string& url, -	LLCurl::ResponderPtr responder, -	const LLSD& headers, -	const F32 timeout) -{ -	delete_urls.push_back(url); -	delete_responders.push_back(responder); -} - -namespace tut -{ -	struct LLHTTPClientAdapterData -	{ -		LLHTTPClientAdapterData() -		{ -			get_urls.clear(); -			get_responders.clear(); -			put_urls.clear(); -			put_responders.clear(); -			put_body.clear(); -			put_headers.clear(); -			delete_urls.clear(); -			delete_responders.clear(); -		} -	}; - -	typedef test_group<LLHTTPClientAdapterData> factory; -	typedef factory::object object; -} - -namespace -{ -	tut::factory tf("LLHTTPClientAdapterData"); -} - -namespace tut -{ -	// Ensure we can create the object -	template<> template<> -	void object::test<1>() -	{ -		LLHTTPClientAdapter adapter; -	} - -	// Does the get pass the appropriate arguments to the LLHTTPClient -	template<> template<> -	void object::test<2>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		adapter.get("Made up URL", responder); -		ensure_equals(get_urls.size(), 1); -		ensure_equals(get_urls[0], "Made up URL"); -	} - -	// Ensure the responder matches the one passed to get -	template<> template<> -	void object::test<3>() -	{ -		LLHTTPClientAdapter adapter; -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		adapter.get("Made up URL", responder); - -		ensure_equals(get_responders.size(), 1); -		ensure_equals(get_responders[0].get(), responder.get()); -	} -	 -	// Ensure the correct url is used in the put -	template<> template<> -	void object::test<4>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body; -		body["TestBody"] = "Foobar"; - -		adapter.put("Made up URL", body, responder); -		ensure_equals(put_urls.size(), 1); -		ensure_equals(put_urls[0], "Made up URL"); -	} - -	// Ensure the correct responder is used by put -	template<> template<> -	void object::test<5>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body; -		body["TestBody"] = "Foobar"; - -		adapter.put("Made up URL", body, responder); - -		ensure_equals(put_responders.size(), 1); -		ensure_equals(put_responders[0].get(), responder.get()); -	} - -	// Ensure the message body is passed through the put properly -	template<> template<> -	void object::test<6>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body; -		body["TestBody"] = "Foobar"; - -		adapter.put("Made up URL", body, responder); - -		ensure_equals(put_body.size(), 1); -		ensure_equals(put_body[0]["TestBody"].asString(), "Foobar"); -	} - -	// Ensure that headers are passed through put properly -	template<> template<> -	void object::test<7>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body = LLSD::emptyMap(); -		body["TestBody"] = "Foobar"; - -		LLSD headers = LLSD::emptyMap(); -		headers["booger"] = "omg"; - -		adapter.put("Made up URL", body, responder, headers); - -		ensure_equals("Header count", put_headers.size(), 1); -		ensure_equals( -			"First header", -			put_headers[0]["booger"].asString(), -			"omg"); -	} - -	// Ensure that del() passes appropriate arguments to the LLHTTPClient -	template<> template<> -	void object::test<8>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		adapter.del("Made up URL", responder); - -		ensure_equals("URL count", delete_urls.size(), 1); -		ensure_equals("Received URL", delete_urls[0], "Made up URL"); - -		ensure_equals("Responder count", delete_responders.size(), 1); -		//ensure_equals("Responder", delete_responders[0], responder); -	} -} - diff --git a/indra/llmessage/tests/llsdmessage_test.cpp b/indra/llmessage/tests/llsdmessage_test.cpp deleted file mode 100755 index 44b024a83f..0000000000 --- a/indra/llmessage/tests/llsdmessage_test.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file   llsdmessage_test.cpp - * @author Nat Goodspeed - * @date   2008-12-22 - * @brief  Test of llsdmessage.h - *  - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#if LL_WINDOWS -#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want! -#endif - -// Precompiled header -#include "linden_common.h" -// associated header -#include "llsdmessage.h" -// STL headers -#include <iostream> -// std headers -#include <stdexcept> -#include <typeinfo> -// external library headers -// other Linden headers -#include "../test/lltut.h" -#include "../test/catch_and_store_what_in.h" -#include "llsdserialize.h" -#include "llevents.h" -#include "stringize.h" -#include "llhost.h" -#include "tests/networkio.h" -#include "tests/commtest.h" - -/***************************************************************************** -*   TUT -*****************************************************************************/ -namespace tut -{ -    struct llsdmessage_data: public commtest_data -    { -        LLEventPump& httpPump; - -        llsdmessage_data(): -            httpPump(pumps.obtain("LLHTTPClient")) -        { -            LLCurl::initClass(); -            LLSDMessage::link(); -        } -    }; -    typedef test_group<llsdmessage_data> llsdmessage_group; -    typedef llsdmessage_group::object llsdmessage_object; -    llsdmessage_group llsdmgr("llsdmessage"); - -    template<> template<> -    void llsdmessage_object::test<1>() -    { -        std::string threw; -        // This should fail... -        try -        { -            LLSDMessage localListener; -        } -        CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupPumpName) -        ensure("second LLSDMessage should throw", ! threw.empty()); -    } - -    template<> template<> -    void llsdmessage_object::test<2>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        bool threw = false; -        try -        { -            httpPump.post(request); -        } -        catch (const LLSDMessage::ArgError&) -        { -            threw = true; -        } -        ensure("missing URL", threw); -    } - -    template<> template<> -    void llsdmessage_object::test<3>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["url"] = server + "got-message"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        httpPump.post(request); -        ensure("got response", netio.pump()); -        ensure("success response", success); -        ensure_equals(result["reply"].asString(), "success"); - -        body["status"] = 499; -        body["reason"] = "custom error message"; -        request["url"] = server + "fail"; -        request["payload"] = body; -        httpPump.post(request); -        ensure("got response", netio.pump()); -        ensure("failure response", ! success); -        ensure_equals(result["status"].asInteger(), body["status"].asInteger()); -        ensure_equals(result["reason"].asString(),  body["reason"].asString()); -    } -} // namespace tut diff --git a/indra/llmessage/tests/lltesthttpclientadapter.cpp b/indra/llmessage/tests/lltesthttpclientadapter.cpp deleted file mode 100755 index 4539e4a540..0000000000 --- a/indra/llmessage/tests/lltesthttpclientadapter.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**  - * @file  - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ -#include "lltesthttpclientadapter.h" - -LLTestHTTPClientAdapter::LLTestHTTPClientAdapter() -{ -} - -LLTestHTTPClientAdapter::~LLTestHTTPClientAdapter() -{ -} - -void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder) -{ -	mGetUrl.push_back(url); -	mGetResponder.push_back(responder); -} - -void LLTestHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) -{ -	mPutUrl.push_back(url); -	mPutBody.push_back(body); -	mPutResponder.push_back(responder); -} - -U32 LLTestHTTPClientAdapter::putCalls() const  -{  -	return mPutUrl.size();  -} - -void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) -{ -	mGetUrl.push_back(url); -	mGetHeaders.push_back(headers); -	mGetResponder.push_back(responder); -} - - diff --git a/indra/llmessage/tests/lltesthttpclientadapter.h b/indra/llmessage/tests/lltesthttpclientadapter.h deleted file mode 100755 index c29cbb3a2a..0000000000 --- a/indra/llmessage/tests/lltesthttpclientadapter.h +++ /dev/null @@ -1,57 +0,0 @@ -/**  - * @file  - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLTESTHTTPCLIENTADAPTER_H -#define LL_LLTESTHTTPCLIENTADAPTER_H - - -#include "linden_common.h" -#include "llhttpclientinterface.h" - -class LLTestHTTPClientAdapter : public LLHTTPClientInterface -{ -public: -	LLTestHTTPClientAdapter(); -	virtual ~LLTestHTTPClientAdapter(); -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder); -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers); - -	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder); -	U32 putCalls() const; - -	std::vector<LLSD> mPutBody; -	std::vector<LLSD> mGetHeaders; -	std::vector<std::string> mPutUrl; -	std::vector<std::string> mGetUrl; -	std::vector<LLCurl::ResponderPtr> mPutResponder; -	std::vector<LLCurl::ResponderPtr> mGetResponder; -}; - - - -#endif //LL_LLSIMULATORPRESENCESENDER_H - diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt index c59645bd70..ab20388261 100755 --- a/indra/mac_crash_logger/CMakeLists.txt +++ b/indra/mac_crash_logger/CMakeLists.txt @@ -4,6 +4,7 @@ project(mac_crash_logger)  include(00-Common)  include(LLCommon) +include(LLCoreHttp)  include(LLCrashLogger)  include(LLMath)  include(LLMessage) @@ -11,8 +12,10 @@ include(LLVFS)  include(LLXML)  include(Linking)  include(LLSharedLibs) +include(Boost)  include_directories( +    ${LLCOREHTTP_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS}      ${LLCRASHLOGGER_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS} @@ -71,7 +74,10 @@ target_link_libraries(mac-crash-logger      ${LLMESSAGE_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${LLCOMMON_LIBRARIES} +    ${BOOST_CONTEXT_LIBRARY} +    ${BOOST_COROUTINE_LIBRARY}      )  add_custom_command( diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 67c00576be..7a6267251e 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -142,7 +142,6 @@ set(viewer_SOURCE_FILES      llbuycurrencyhtml.cpp      llcallbacklist.cpp      llcallingcard.cpp -    llcapabilitylistener.cpp      llcaphttpsender.cpp      llchannelmanager.cpp      llchatbar.cpp @@ -152,7 +151,6 @@ set(viewer_SOURCE_FILES      llchiclet.cpp      llchicletbar.cpp      llclassifiedinfo.cpp -    llclassifiedstatsresponder.cpp      llcofwearables.cpp      llcolorswatch.cpp      llcommanddispatcherlistener.cpp @@ -166,6 +164,7 @@ set(viewer_SOURCE_FILES      llconversationloglistitem.cpp      llconversationmodel.cpp      llconversationview.cpp +    llcoproceduremanager.cpp      llcurrencyuimanager.cpp      llcylinder.cpp      lldateutil.cpp @@ -234,7 +233,6 @@ set(viewer_SOURCE_FILES      llfloaterconversationpreview.cpp      llfloaterdeleteenvpreset.cpp      llfloaterdestinations.cpp -    llfloaterdisplayname.cpp      llfloatereditdaycycle.cpp      llfloatereditsky.cpp      llfloatereditwater.cpp @@ -333,7 +331,6 @@ set(viewer_SOURCE_FILES      llgroupmgr.cpp      llhasheduniqueid.cpp      llhints.cpp -    llhomelocationresponder.cpp      llhttpretrypolicy.cpp      llhudeffect.cpp      llhudeffectbeam.cpp @@ -604,7 +601,6 @@ set(viewer_SOURCE_FILES      lltwitterconnect.cpp      lluilistener.cpp      lluploaddialog.cpp -    lluploadfloaterobservers.cpp      llurl.cpp      llurldispatcher.cpp      llurldispatcherlistener.cpp @@ -617,6 +613,7 @@ set(viewer_SOURCE_FILES      llviewerassetstats.cpp      llviewerassetstorage.cpp      llviewerassettype.cpp +    llviewerassetupload.cpp      llviewerattachmenu.cpp      llvieweraudio.cpp      llviewercamera.cpp @@ -624,7 +621,6 @@ set(viewer_SOURCE_FILES      llviewercontrol.cpp      llviewercontrollistener.cpp      llviewerdisplay.cpp -    llviewerdisplayname.cpp      llviewerfloaterreg.cpp      llviewerfoldertype.cpp      llviewergenericmessage.cpp @@ -757,7 +753,6 @@ set(viewer_HEADER_FILES      llbuycurrencyhtml.h      llcallbacklist.h      llcallingcard.h -    llcapabilitylistener.h      llcapabilityprovider.h      llcaphttpsender.h      llchannelmanager.h @@ -768,7 +763,6 @@ set(viewer_HEADER_FILES      llchiclet.h      llchicletbar.h      llclassifiedinfo.h -    llclassifiedstatsresponder.h      llcofwearables.h      llcolorswatch.h      llcommanddispatcherlistener.h @@ -782,6 +776,7 @@ set(viewer_HEADER_FILES      llconversationloglistitem.h      llconversationmodel.h      llconversationview.h +    llcoproceduremanager.h      llcurrencyuimanager.h      llcylinder.h      lldateutil.h @@ -850,7 +845,6 @@ set(viewer_HEADER_FILES      llfloaterconversationpreview.h      llfloaterdeleteenvpreset.h      llfloaterdestinations.h -    llfloaterdisplayname.h      llfloatereditdaycycle.h      llfloatereditsky.h      llfloatereditwater.h @@ -952,7 +946,6 @@ set(viewer_HEADER_FILES      llhasheduniqueid.h      llhints.h      llhttpretrypolicy.h -    llhomelocationresponder.h      llhudeffect.h      llhudeffectbeam.h      llhudeffectlookat.h @@ -1225,6 +1218,7 @@ set(viewer_HEADER_FILES      llviewerassetstats.h      llviewerassetstorage.h      llviewerassettype.h +    llviewerassetupload.h      llviewerattachmenu.h      llvieweraudio.h      llviewercamera.h @@ -1232,7 +1226,6 @@ set(viewer_HEADER_FILES      llviewercontrol.h      llviewercontrollistener.h      llviewerdisplay.h -    llviewerdisplayname.h      llviewerfloaterreg.h      llviewerfoldertype.h      llviewergenericmessage.h @@ -2238,9 +2231,9 @@ if (LL_TESTS)    SET(viewer_TEST_SOURCE_FILES      llagentaccess.cpp      lldateutil.cpp -    llmediadataclient.cpp +#    llmediadataclient.cpp      lllogininstance.cpp -    llremoteparcelrequest.cpp +#    llremoteparcelrequest.cpp      lltranslate.cpp      llviewerhelputil.cpp      llversioninfo.cpp @@ -2271,7 +2264,7 @@ if (LL_TESTS)    set_source_files_properties(      llmediadataclient.cpp      PROPERTIES -    LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}" +    LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}"    )    set_source_files_properties( @@ -2327,7 +2320,6 @@ if (LL_TESTS)    LL_ADD_PROJECT_UNIT_TESTS(${VIEWER_BINARY_NAME} "${viewer_TEST_SOURCE_FILES}")    #set(TEST_DEBUG on) -  set(test_sources llcapabilitylistener.cpp)    ##################################################    # DISABLING PRECOMPILED HEADERS USAGE FOR TESTS    ################################################## @@ -2343,26 +2335,29 @@ if (LL_TESTS)      ${GOOGLEMOCK_LIBRARIES}      ) -  LL_ADD_INTEGRATION_TEST(llcapabilitylistener -    "${test_sources}" -    "${test_libs}" -    ${PYTHON_EXECUTABLE} -    "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py" -    ) +  if (LINUX) +    # llcommon uses `clock_gettime' which is provided by librt on linux. +    set(LIBRT_LIBRARY +      rt +      ) +  endif (LINUX)    set(test_libs -    ${LLMESSAGE_LIBRARIES} -    ${LLCOREHTTP_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES}      ${LLCOMMON_LIBRARIES} +    ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${GOOGLEMOCK_LIBRARIES}      ${OPENSSL_LIBRARIES}      ${CRYPTO_LIBRARIES} +    ${LIBRT_LIBRARY} +    ${BOOST_CONTEXT_LIBRARY} +    ${BOOST_COROUTINE_LIBRARY}    ) -    LL_ADD_INTEGRATION_TEST(llsechandler_basic +  LL_ADD_INTEGRATION_TEST(llsechandler_basic      llsechandler_basic.cpp      "${test_libs}"      ) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9d9bc43bd7..2180a7f1a1 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2370,6 +2370,17 @@        <key>Value</key>        <integer>0</integer>      </map> +  <key>DebugSlshareLogTag</key> +    <map> +      <key>Comment</key> +      <string>Request slshare-service debug logging</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>String</string> +      <key>Value</key> +      <string/> +    </map>    <key>DebugStatModeFPS</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index a42286a9e4..cd9146ea16 100755 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -27,90 +27,150 @@  #include "llviewerprecompiledheaders.h"  #include "llaccountingcostmanager.h"  #include "llagent.h" -#include "llcurl.h" -#include "llhttpclient.h" +#include "httpcommon.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +  //=============================================================================== -LLAccountingCostManager::LLAccountingCostManager() +LLAccountingCostManager::LLAccountingCostManager(): +    mHttpRequest(), +    mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID)  {	 +    mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +    //mHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; +  } -//=============================================================================== -class LLAccountingCostResponder : public LLCurl::Responder + +// Coroutine for sending and processing avatar name cache requests.   +// Do not call directly.  See documentation in lleventcoro.h and llcoro.h for +// further explanation. +void LLAccountingCostManager::accountingCostCoro(std::string url, +    eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle)  { -	LOG_CLASS(LLAccountingCostResponder); -public: -	LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle ) -	: mObjectIDs( objectIDs ), -	  mObserverHandle( observer_handle ) -	{ -		LLAccountingCostObserver* observer = mObserverHandle.get(); -		if (observer) -		{ -			mTransactionID = observer->getTransactionID(); -		} -	} +    LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName() +        << " with url '" << url << LL_ENDL; -	void clearPendingRequests ( void ) -	{ -		for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter ) -		{ -			LLAccountingCostManager::getInstance()->removePendingObject( iter->asUUID() ); -		} -	} -	 -protected: -	void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -		clearPendingRequests(); - -		LLAccountingCostObserver* observer = mObserverHandle.get(); -		if (observer && observer->getTransactionID() == mTransactionID) -		{ -			observer->setErrorStatus(getStatus(), getReason()); -		} -	} -	 -	void httpSuccess() -	{ -		const LLSD& content = getContent(); -		//Check for error -		if ( !content.isMap() || content.has("error") ) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content); -			return; -		} -		else if (content.has("selected")) -		{ -			F32 physicsCost		= 0.0f; -			F32 networkCost		= 0.0f; -			F32 simulationCost	= 0.0f; - -			physicsCost		= content["selected"]["physics"].asReal(); -			networkCost		= content["selected"]["streaming"].asReal(); -			simulationCost	= content["selected"]["simulation"].asReal(); -				 -			SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost ); - -			LLAccountingCostObserver* observer = mObserverHandle.get(); -			if (observer && observer->getTransactionID() == mTransactionID) -			{ -				observer->onWeightsUpdate(selectionCost); -			} -		} - -		clearPendingRequests(); -	} -	 -private: -	//List of posted objects -	LLSD mObjectIDs; +    try +    { +        LLSD objectList; +        U32  objectIndex = 0; + +        IDIt IDIter = mObjectList.begin(); +        IDIt IDIterEnd = mObjectList.end(); + +        for (; IDIter != IDIterEnd; ++IDIter) +        { +            // Check to see if a request for this object has already been made. +            if (mPendingObjectQuota.find(*IDIter) == mPendingObjectQuota.end()) +            { +                mPendingObjectQuota.insert(*IDIter); +                objectList[objectIndex++] = *IDIter; +            } +        } + +        mObjectList.clear(); + +        //Post results +        if (objectList.size() == 0) +            return; + +        std::string keystr; +        if (selectionType == Roots) +        { +            keystr = "selected_roots"; +        } +        else if (selectionType == Prims) +        { +            keystr = "selected_prims"; +        } +        else +        { +            LL_INFOS() << "Invalid selection type " << LL_ENDL; +            mObjectList.clear(); +            mPendingObjectQuota.clear(); +            return; +        } -	// Current request ID -	LLUUID mTransactionID; +        LLSD dataToPost = LLSD::emptyMap(); +        dataToPost[keystr.c_str()] = objectList; + +        LLAccountingCostObserver* observer = observerHandle.get(); +        LLUUID transactionId = observer->getTransactionID(); +        observer = NULL; + +        LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("AccountingCost", mHttpPolicy); + +        LLSD results = httpAdapter.postAndYield(mHttpRequest, url, dataToPost); + +        LLSD httpResults; +        httpResults = results["http_result"]; + +        // do/while(false) allows error conditions to break out of following  +        // block while normal flow goes forward once. +        do  +        { +            observer = observerHandle.get(); +            if ((!observer) || (observer->getTransactionID() != transactionId)) +            {   // *TODO: Rider: I've noticed that getTransactionID() does not  +                // always match transactionId (the new transaction Id does not show a  +                // corresponding request.) (ask Vir) +                if (!observer) +                    break; +                LL_WARNS() << "Request transaction Id(" << transactionId +                    << ") does not match observer's transaction Id(" +                    << observer->getTransactionID() << ")." << LL_ENDL; +                break; +            } + +            if (!httpResults["success"].asBoolean()) +            { +                LL_WARNS() << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code " +                    << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL; +                if (observer) +                { +                    observer->setErrorStatus(httpResults["status"].asInteger(), httpResults["message"].asStringRef()); +                } +                break; +            } + +            if (!results.isMap() || results.has("error")) +            { +                LL_WARNS() << "Error on fetched data" << LL_ENDL; +                observer->setErrorStatus(499, "Error on fetched data"); +                break; +            } + +            if (results.has("selected")) +            { +                F32 physicsCost = 0.0f; +                F32 networkCost = 0.0f; +                F32 simulationCost = 0.0f; + +                physicsCost = results["selected"]["physics"].asReal(); +                networkCost = results["selected"]["streaming"].asReal(); +                simulationCost = results["selected"]["simulation"].asReal(); + +                SelectionCost selectionCost( physicsCost, networkCost, simulationCost); + +                observer->onWeightsUpdate(selectionCost); +            } + +        } while (false); + +    } +    catch (std::exception e) +    { +        LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL; +    } +    catch (...) +    { +        LL_WARNS() << "Caught unknown exception." << LL_ENDL; +    } + +    mPendingObjectQuota.clear(); +} -	// Cost update observer handle -	LLHandle<LLAccountingCostObserver> mObserverHandle; -};  //===============================================================================  void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,  										  const std::string& url, @@ -119,50 +179,11 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,  	// Invoking system must have already determined capability availability  	if ( !url.empty() )  	{ -		LLSD objectList; -		U32  objectIndex = 0; -		 -		IDIt IDIter = mObjectList.begin(); -		IDIt IDIterEnd = mObjectList.end(); -		 -		for ( ; IDIter != IDIterEnd; ++IDIter ) -		{ -			// Check to see if a request for this object has already been made. -			if ( mPendingObjectQuota.find( *IDIter ) ==	mPendingObjectQuota.end() ) -			{ -				mPendingObjectQuota.insert( *IDIter ); -				objectList[objectIndex++] = *IDIter; -			} -		} -	 -		mObjectList.clear(); -		 -		//Post results -		if ( objectList.size() > 0 ) -		{ -			std::string keystr; -			if ( selectionType == Roots )  -			{  -				keystr="selected_roots";  -			} -			else -			if ( selectionType == Prims )  -			{  -				keystr="selected_prims"; -			} -			else  -			{ -				LL_INFOS()<<"Invalid selection type "<<LL_ENDL; -				mObjectList.clear(); -				mPendingObjectQuota.clear(); -				return; -			} -			 -			LLSD dataToPost = LLSD::emptyMap();		 -			dataToPost[keystr.c_str()] = objectList; - -			LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList, observer_handle )); -		} +        std::string coroname =  +            LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro", +            boost::bind(&LLAccountingCostManager::accountingCostCoro, this, url, selectionType, observer_handle)); +        LL_DEBUGS() << coroname << " with  url '" << url << LL_ENDL; +  	}  	else  	{ diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 3ade34c81d..d5a94f6fda 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -30,6 +30,13 @@  #include "llhandle.h"  #include "llaccountingcost.h" +#include "httpcommon.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h" +  //===============================================================================  // An interface class for panels which display the parcel accounting information.  class LLAccountingCostObserver @@ -69,6 +76,11 @@ private:  	//a fetch has been instigated.  	std::set<LLUUID> mPendingObjectQuota;  	typedef std::set<LLUUID>::iterator IDIt; + +    void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle); + +    LLCore::HttpRequest::ptr_t		mHttpRequest; +    LLCore::HttpRequest::policy_t	mHttpPolicy;  };  //=============================================================================== diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 359171c5bd..2060065c75 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -38,7 +38,6 @@  #include "llappearancemgr.h"  #include "llanimationstates.h"  #include "llcallingcard.h" -#include "llcapabilitylistener.h"  #include "llchannelmanager.h"  #include "llchicletbar.h"  #include "llconsole.h" @@ -52,7 +51,6 @@  #include "llfloatertools.h"  #include "llgroupactions.h"  #include "llgroupmgr.h" -#include "llhomelocationresponder.h"  #include "llhudmanager.h"  #include "lljoystickbutton.h"  #include "llmorphview.h" @@ -63,7 +61,6 @@  #include "llpaneltopinfobar.h"  #include "llparcel.h"  #include "llrendersphere.h" -#include "llsdmessage.h"  #include "llsdutil.h"  #include "llsky.h"  #include "llslurl.h" @@ -95,6 +92,7 @@  #include "lscript_byteformat.h"  #include "stringize.h"  #include "boost/foreach.hpp" +#include "llcorehttputil.h"  using namespace LLAvatarAppearanceDefines; @@ -361,7 +359,8 @@ LLAgent::LLAgent() :  	mMaturityPreferenceNumRetries(0U),  	mLastKnownRequestMaturity(SIM_ACCESS_MIN),  	mLastKnownResponseMaturity(SIM_ACCESS_MIN), -	mTeleportState( TELEPORT_NONE ), +	mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +	mTeleportState(TELEPORT_NONE),  	mRegionp(NULL),  	mAgentOriginGlobal(), @@ -461,6 +460,10 @@ void LLAgent::init()  		mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this));  	} +	LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + +	mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT); +  	mInitialized = TRUE;  } @@ -2326,27 +2329,9 @@ void LLAgent::setStartPosition( U32 location_id )      body["HomeLocation"] = homeLocation; -    // This awkward idiom warrants explanation. -    // For starters, LLSDMessage::ResponderAdapter is ONLY for testing the new -    // LLSDMessage functionality with a pre-existing LLHTTPClient::Responder. -    // In new code, define your reply/error methods on the same class as the -    // sending method, bind them to local LLEventPump objects and pass those -    // LLEventPump names in the request LLSD object. -    // When testing old code, the new LLHomeLocationResponder object -    // is referenced by an LLHTTPClient::ResponderPtr, so when the -    // ResponderAdapter is deleted, the LLHomeLocationResponder will be too. -    // We must trust that the underlying LLHTTPClient code will eventually -    // fire either the reply callback or the error callback; either will cause -    // the ResponderAdapter to delete itself. -    LLSDMessage::ResponderAdapter* -        adapter(new LLSDMessage::ResponderAdapter(new LLHomeLocationResponder())); - -    request["message"] = "HomeLocation"; -    request["payload"] = body; -    request["reply"]   = adapter->getReplyName(); -    request["error"]   = adapter->getErrorName(); - -    gAgent.getRegion()->getCapAPI().post(request); +    if (!requestPostCapability("HomeLocation", body,  +            boost::bind(&LLAgent::setStartPositionSuccess, this, _1))) +        LL_WARNS() << "Unable to post to HomeLocation capability." << LL_ENDL;      const U32 HOME_INDEX = 1;      if( HOME_INDEX == location_id ) @@ -2355,32 +2340,51 @@ void LLAgent::setStartPosition( U32 location_id )      }  } -struct HomeLocationMapper: public LLCapabilityListener::CapabilityMapper +void LLAgent::setStartPositionSuccess(const LLSD &result)  { -    // No reply message expected -    HomeLocationMapper(): LLCapabilityListener::CapabilityMapper("HomeLocation") {} -    virtual void buildMessage(LLMessageSystem* msg, -                              const LLUUID& agentID, -                              const LLUUID& sessionID, -                              const std::string& capabilityName, -                              const LLSD& payload) const +    LLVector3 agent_pos; +    bool      error = true; + +    do { +        // was the call to /agent/<agent-id>/home-location successful? +        // If not, we keep error set to true +        if (!result.has("success")) +            break; + +        if (0 != strncmp("true", result["success"].asString().c_str(), 4)) +            break; + +        // did the simulator return a "justified" home location? +        // If no, we keep error set to true +        if (!result.has("HomeLocation")) +            break; + +        if ((!result["HomeLocation"].has("LocationPos")) || +                (!result["HomeLocation"]["LocationPos"].has("X")) || +                (!result["HomeLocation"]["LocationPos"].has("Y")) || +                (!result["HomeLocation"]["LocationPos"].has("Z"))) +            break; + +        agent_pos.mV[VX] = result["HomeLocation"]["LocationPos"]["X"].asInteger(); +        agent_pos.mV[VY] = result["HomeLocation"]["LocationPos"]["Y"].asInteger(); +        agent_pos.mV[VZ] = result["HomeLocation"]["LocationPos"]["Z"].asInteger(); + +        error = false; + +    } while (0); + +    if (error)      { -        msg->newMessageFast(_PREHASH_SetStartLocationRequest); -        msg->nextBlockFast( _PREHASH_AgentData); -        msg->addUUIDFast(_PREHASH_AgentID, agentID); -        msg->addUUIDFast(_PREHASH_SessionID, sessionID); -        msg->nextBlockFast( _PREHASH_StartLocationData); -        // corrected by sim -        msg->addStringFast(_PREHASH_SimName, ""); -        msg->addU32Fast(_PREHASH_LocationID, payload["HomeLocation"]["LocationId"].asInteger()); -        msg->addVector3Fast(_PREHASH_LocationPos, -                            ll_vector3_from_sdmap(payload["HomeLocation"]["LocationPos"])); -        msg->addVector3Fast(_PREHASH_LocationLookAt, -                            ll_vector3_from_sdmap(payload["HomeLocation"]["LocationLookAt"])); +        LL_WARNS() << "Error in response to home position set." << LL_ENDL;      } -}; -// Need an instance of this class so it will self-register -static HomeLocationMapper homeLocationMapper; +    else +    { +        LL_INFOS() << "setting home position" << LL_ENDL; + +        LLViewerRegion *viewer_region = gAgent.getRegion(); +        setHomePosRegion(viewer_region->getHandle(), agent_pos); +    } +}  void LLAgent::requestStopMotion( LLMotion* motion )  { @@ -2517,87 +2521,6 @@ int LLAgent::convertTextToMaturity(char text)  	return LLAgentAccess::convertTextToMaturity(text);  } -class LLMaturityPreferencesResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLMaturityPreferencesResponder); -public: -	LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); -	virtual ~LLMaturityPreferencesResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -protected: - -private: -	U8 parseMaturityFromServerResponse(const LLSD &pContent) const; - -	LLAgent                                  *mAgent; -	U8                                       mPreferredMaturity; -	U8                                       mPreviousMaturity; -}; - -LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) -	: LLHTTPClient::Responder(), -	mAgent(pAgent), -	mPreferredMaturity(pPreferredMaturity), -	mPreviousMaturity(pPreviousMaturity) -{ -} - -LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() -{ -} - -void LLMaturityPreferencesResponder::httpSuccess() -{ -	U8 actualMaturity = parseMaturityFromServerResponse(getContent()); - -	if (actualMaturity != mPreferredMaturity) -	{ -		LL_WARNS() << "while attempting to change maturity preference from '" -				   << LLViewerRegion::accessToString(mPreviousMaturity) -				   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  -				   << "', the server responded with '" -				   << LLViewerRegion::accessToString(actualMaturity)  -				   << "' [value:" << static_cast<U32>(actualMaturity)  -				   << "], " << dumpResponse() << LL_ENDL; -	} -	mAgent->handlePreferredMaturityResult(actualMaturity); -} - -void LLMaturityPreferencesResponder::httpFailure() -{ -	LL_WARNS() << "while attempting to change maturity preference from '"  -			   << LLViewerRegion::accessToString(mPreviousMaturity) -			   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  -			<< "', " << dumpResponse() << LL_ENDL; -	mAgent->handlePreferredMaturityError(); -} - -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const -{ -	U8 maturity = SIM_ACCESS_MIN; - -	llassert(pContent.isDefined()); -	llassert(pContent.isMap()); -	llassert(pContent.has("access_prefs")); -	llassert(pContent.get("access_prefs").isMap()); -	llassert(pContent.get("access_prefs").has("max")); -	llassert(pContent.get("access_prefs").get("max").isString()); -	if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs") -		&& pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") -		&& pContent.get("access_prefs").get("max").isString()) -	{ -		LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString(); -		LLStringUtil::trim(actualPreference); -		maturity = LLViewerRegion::shortStringToAccess(actualPreference); -	} - -	return maturity; -} -  void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity)  {  	// Update the number of responses received @@ -2726,42 +2649,96 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  		// Update the last know maturity request  		mLastKnownRequestMaturity = pPreferredMaturity; -		// Create a response handler -		LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); -  		// If we don't have a region, report it as an error  		if (getRegion() == NULL)  		{ -			responderPtr->failureResult(0U, "region is not defined", LLSD()); +			LL_WARNS("Agent") << "Region is not defined, can not change Maturity setting." << LL_ENDL; +			return;  		} -		else -		{ -			// Find the capability to send maturity preference -			std::string url = getRegion()->getCapability("UpdateAgentInformation"); -			// If the capability is not defined, report it as an error -			if (url.empty()) -			{ -				responderPtr->failureResult(0U,  -							"capability 'UpdateAgentInformation' is not defined for region", LLSD()); -			} -			else -			{ -				// Set new access preference -				LLSD access_prefs = LLSD::emptyMap(); -				access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); - -				LLSD body = LLSD::emptyMap(); -				body["access_prefs"] = access_prefs; -				LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) -					<< "' via capability to: " << url << LL_ENDL; -				LLSD headers; -				LLHTTPClient::post(url, body, responderPtr, headers, 30.0f); -			} -		} +		LLSD access_prefs = LLSD::emptyMap(); +		access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); + +		LLSD postData = LLSD::emptyMap(); +		postData["access_prefs"] = access_prefs; +		LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) << LL_ENDL; + +        if (!requestPostCapability("UpdateAgentInformation", postData, +            static_cast<httpCallback_t>(boost::bind(&LLAgent::processMaturityPreferenceFromServer, this, _1, pPreferredMaturity)), +            static_cast<httpCallback_t>(boost::bind(&LLAgent::handlePreferredMaturityError, this)) +            )) +        { +            LL_WARNS("Agent") << "Maturity request post failed." << LL_ENDL; +        }  	}  } + +void LLAgent::processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity) +{ +    U8 maturity = SIM_ACCESS_MIN; + +    llassert(result.isDefined()); +    llassert(result.isMap()); +    llassert(result.has("access_prefs")); +    llassert(result.get("access_prefs").isMap()); +    llassert(result.get("access_prefs").has("max")); +    llassert(result.get("access_prefs").get("max").isString()); +    if (result.isDefined() && result.isMap() && result.has("access_prefs") +        && result.get("access_prefs").isMap() && result.get("access_prefs").has("max") +        && result.get("access_prefs").get("max").isString()) +    { +        LLSD::String actualPreference = result.get("access_prefs").get("max").asString(); +        LLStringUtil::trim(actualPreference); +        maturity = LLViewerRegion::shortStringToAccess(actualPreference); +    } + +    if (maturity != perferredMaturity) +    { +        LL_WARNS() << "while attempting to change maturity preference from '" +            << LLViewerRegion::accessToString(mLastKnownResponseMaturity) +            << "' to '" << LLViewerRegion::accessToString(perferredMaturity) +            << "', the server responded with '" +            << LLViewerRegion::accessToString(maturity) +            << "' [value:" << static_cast<U32>(maturity) +            << "], " << LL_ENDL; +    } +    handlePreferredMaturityResult(maturity); +} + + +bool LLAgent::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ +    std::string url; + +    url = getRegion()->getCapability(capName); + +    if (url.empty()) +    { +        LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL; +        return false; +    } + +    LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, mHttpPolicy, postData, cbSuccess, cbFailure); +    return true; +} + +bool LLAgent::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ +    std::string url; + +    url = getRegion()->getCapability(capName); + +    if (url.empty()) +    { +        LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL; +        return false; +    } + +    LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, mHttpPolicy, cbSuccess, cbFailure); +    return true; +} +  BOOL LLAgent::getAdminOverride() const	  {   	return mAgentAccess->getAdminOverride();  diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 4830cb754b..0ba3dea427 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -34,7 +34,9 @@  #include "llcoordframe.h"			// for mFrameAgent  #include "llavatarappearancedefines.h"  #include "llpermissionsflags.h" +#include "llevents.h"  #include "v3dmath.h" +#include "llcorehttputil.h"  #include <boost/function.hpp>  #include <boost/shared_ptr.hpp> @@ -61,6 +63,8 @@ class LLPauseRequestHandle;  class LLUIColor;  class LLTeleportRequest; + +  typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr;  //-------------------------------------------------------------------- @@ -112,6 +116,8 @@ public:  	void			init();  	void			cleanup(); +private: +  	//--------------------------------------------------------------------  	// Login  	//-------------------------------------------------------------------- @@ -227,6 +233,8 @@ public:  	void			setHomePosRegion(const U64& region_handle, const LLVector3& pos_region);  	BOOL			getHomePosGlobal(LLVector3d* pos_global);  private: +    void            setStartPositionSuccess(const LLSD &result); +  	BOOL 			mHaveHomePosition;  	U64				mHomeRegionHandle;  	LLVector3		mHomePosRegion; @@ -631,6 +639,8 @@ public:  	void            setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange);  private: + +  	friend class LLTeleportRequest;  	friend class LLTeleportRequestViaLandmark;  	friend class LLTeleportRequestViaLure; @@ -758,11 +768,12 @@ private:  	unsigned int                    mMaturityPreferenceNumRetries;  	U8                              mLastKnownRequestMaturity;  	U8                              mLastKnownResponseMaturity; +	LLCore::HttpRequest::policy_t	mHttpPolicy;  	bool            isMaturityPreferenceSyncedWithServer() const;  	void 			sendMaturityPreferenceToServer(U8 pPreferredMaturity); +    void            processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity); -	friend class LLMaturityPreferencesResponder;  	void            handlePreferredMaturityResult(U8 pServerMaturity);  	void            handlePreferredMaturityError();  	void            reportPreferredMaturitySuccess(); @@ -911,6 +922,22 @@ public:  /********************************************************************************   **                                                                            ** + **                    UTILITY + **/ +public: +    typedef LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t httpCallback_t; + +	/// Utilities for allowing the the agent sub managers to post and get via +	/// HTTP using the agent's policy settings and headers.   +    bool requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL); +    bool requestGetCapability(const std::string &capName, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL); + +/**                    Utility + **                                                                            ** + *******************************************************************************/ + +/******************************************************************************** + **                                                                            **   **                    DEBUGGING   **/ diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp index fe6236a32a..cdb0e3302d 100755 --- a/indra/newview/llagentlanguage.cpp +++ b/indra/newview/llagentlanguage.cpp @@ -32,6 +32,7 @@  #include "llviewerregion.h"  // library includes  #include "llui.h"					// getLanguage() +#include "httpcommon.h"  // static  void LLAgentLanguage::init() @@ -54,22 +55,17 @@ void LLAgentLanguage::onChange()  // static  bool LLAgentLanguage::update()  { -	LLSD body; -	std::string url; +    LLSD body; -	if (gAgent.getRegion()) -	{ -		url = gAgent.getRegion()->getCapability("UpdateAgentLanguage"); -	} - -	if (!url.empty()) -	{ -		std::string language = LLUI::getLanguage(); +	std::string language = LLUI::getLanguage(); -		body["language"] = language; -		body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); +	body["language"] = language; +	body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); -		LLHTTPClient::post(url, body, new LLHTTPClient::Responder); -	} +    if (!gAgent.requestPostCapability("UpdateAgentLanguage", body)) +    { +        LL_WARNS("Language") << "Language capability unavailable." << LL_ENDL; +    } +      return true;  } diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index f5f224b83e..51cca273d8 100755 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -31,6 +31,10 @@  #include "llappviewer.h"  #include "llviewercontrol.h" +#include <openssl/x509_vfy.h> +#include <openssl/ssl.h> +#include "llsecapi.h" +#include <curl/curl.h>  // Here is where we begin to get our connection usage under control.  // This establishes llcorehttp policy classes that, among other @@ -93,6 +97,16 @@ static const struct  		4,		1,		4,		0,		false,  		"",  		"inventory" +	}, +	{ // AP_MATERIALS +		2,		1,		8,		0,		false, +		"RenderMaterials", +		"material manager requests" +	}, +	{ // AP_AGENT +		2,		1,		32,		0,		true, +		"Agent", +		"Agent requests"  	}  }; @@ -151,6 +165,15 @@ void LLAppCoreHttp::init()  						 << LL_ENDL;  	} +	// Set up SSL Verification call back. +	status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_SSL_VERIFY_CALLBACK, +														LLCore::HttpRequest::GLOBAL_POLICY_ID, +														sslVerify, NULL); +	if (!status) +	{ +		LL_WARNS("Init") << "Failed to set SSL Verification.  Reason:  " << status.toString() << LL_ENDL; +	} +  	// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):  	// 0 - None  	// 1 - Basic start, stop simple transitions @@ -182,6 +205,8 @@ void LLAppCoreHttp::init()  		}  		mHttpClasses[app_policy].mPolicy = LLCore::HttpRequest::createPolicyClass(); +		// We have run out of available HTTP policies. Adjust HTTP_POLICY_CLASS_LIMIT in _httpinternal.h +		llassert(mHttpClasses[app_policy].mPolicy != LLCore::HttpRequest::INVALID_POLICY_ID);  		if (! mHttpClasses[app_policy].mPolicy)  		{  			// Use default policy (but don't accidentally modify default) @@ -457,6 +482,62 @@ void LLAppCoreHttp::refreshSettings(bool initial)  	}  } +LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url,  +	LLCore::HttpHandler const * const handler, void *appdata) +{ +	X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata); +	LLCore::HttpStatus result; +	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); +	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); +	LLSD validation_params = LLSD::emptyMap(); +	LLURI uri(url); + +	validation_params[CERT_HOSTNAME] = uri.hostName(); + +	// *TODO: In the case of an exception while validating the cert, we need a way +	// to pass the offending(?) cert back out. *Rider* + +	try +	{ +		// don't validate hostname.  Let libcurl do it instead.  That way, it'll handle redirects +		store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); +	} +	catch (LLCertValidationTrustException &cert_exception) +	{ +		// this exception is is handled differently than the general cert +		// exceptions, as we allow the user to actually add the certificate +		// for trust. +		// therefore we pass back a different error code +		// NOTE: We're currently 'wired' to pass around CURL error codes.  This is +		// somewhat clumsy, as we may run into errors that do not map directly to curl +		// error codes.  Should be refactored with login refactoring, perhaps. +		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CACERT); +		result.setMessage(cert_exception.getMessage()); +		LLPointer<LLCertificate> cert = cert_exception.getCert(); +		cert->ref(); // adding an extra ref here +		result.setErrorData(cert.get()); +		// We should probably have a more generic way of passing information +		// back to the error handlers. +	} +	catch (LLCertException &cert_exception) +	{ +		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_PEER_CERTIFICATE); +		result.setMessage(cert_exception.getMessage()); +		LLPointer<LLCertificate> cert = cert_exception.getCert(); +		cert->ref(); // adding an extra ref here +		result.setErrorData(cert.get()); +	} +	catch (...) +	{ +		// any other odd error, we just handle as a connect error. +		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR); +	} + +	return result; +} + + +  void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)  { diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h index 37d7a737e7..410d7c6b07 100755 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -164,7 +164,29 @@ public:  		/// Pipelined:       no  		AP_INVENTORY,  		AP_REPORTING = AP_INVENTORY,	// Piggy-back on inventory -		 + +		/// Material resource requests and puts.   +		/// +		/// Destination:     simhost:12043 +		/// Protocol:        https: +		/// Transfer size:   KB +		/// Long poll:       no +		/// Concurrency:     low +		/// Request rate:    low +		/// Pipelined:       no +		AP_MATERIALS, + +		/// Appearance resource requests and puts.   +		/// +		/// Destination:     simhost:12043 +		/// Protocol:        https: +		/// Transfer size:   KB +		/// Long poll:       no +		/// Concurrency:     mid +		/// Request rate:    low +		/// Pipelined:       yes +		AP_AGENT, +  		AP_COUNT						// Must be last  	}; @@ -233,7 +255,9 @@ private:  	bool						mStopped;  	HttpClass					mHttpClasses[AP_COUNT];  	bool						mPipelined;				// Global setting -	boost::signals2::connection mPipelinedSignal;		// Signal for 'HttpPipelining' setting +	boost::signals2::connection	mPipelinedSignal;		// Signal for 'HttpPipelining' setting + +	static LLCore::HttpStatus	sslVerify(const std::string &uri, LLCore::HttpHandler const * const handler, void *appdata);  }; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index b3317e937e..5ad71369c3 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -23,7 +23,7 @@   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ - +   #include "llviewerprecompiledheaders.h"  #include <boost/lexical_cast.hpp> @@ -54,6 +54,9 @@  #include "llsdserialize.h"  #include "llhttpretrypolicy.h"  #include "llaisapi.h" +#include "llhttpsdhandler.h" +#include "llcorehttputil.h" +#include "llappviewer.h"  #if LL_MSVC  // disable boost::lexical_cast warning @@ -1242,6 +1245,8 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)  	items = new_items;  } +//========================================================================= +  const LLUUID LLAppearanceMgr::getCOF() const  {  	return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); @@ -3233,276 +3238,6 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,  } -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(RequestAgentUpdateAppearanceResponder); - -	friend class LLAppearanceMgr; -	 -public: -	RequestAgentUpdateAppearanceResponder(); - -	virtual ~RequestAgentUpdateAppearanceResponder(); - -private: -	// Called when sendServerAppearanceUpdate called. May or may not -	// trigger a request depending on various bits of state. -	void onRequestRequested(); - -	// Post the actual appearance request to cap. -	void sendRequest(); - -	void debugCOF(const LLSD& content); - -protected: -	// Successful completion. -	/* virtual */ void httpSuccess(); - -	// Error -	/*virtual*/ void httpFailure(); - -	void onFailure(); -	void onSuccess(); - -	S32 mInFlightCounter; -	LLTimer mInFlightTimer; -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder() -{ -	bool retry_on_4xx = true; -	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); -	mInFlightCounter = 0; -} - -RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() -{ -} - -void RequestAgentUpdateAppearanceResponder::onRequestRequested() -{ -	// If we have already received an update for this or higher cof version, ignore. -	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); -	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; -	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; -	LL_DEBUGS("Avatar") << "cof_version " << cof_version -						<< " last_rcv " << last_rcv -						<< " last_req " << last_req -						<< " in flight " << mInFlightCounter << LL_ENDL; -	if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired())) -	{ -		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; -		mInFlightCounter = 0; -	} -	if (cof_version < last_rcv) -	{ -		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv -							<< " will not request for " << cof_version << LL_ENDL; -		return; -	} -	if (mInFlightCounter>0 && last_req >= cof_version) -	{ -		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req  -							<< " will not request for " << cof_version << LL_ENDL; -		return; -	} - -	// Actually send the request. -	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; -	mRetryPolicy->reset(); -	sendRequest(); -} -	 -void RequestAgentUpdateAppearanceResponder::sendRequest() -{ -	if (gAgentAvatarp->isEditingAppearance())  -	{ -		// don't send out appearance updates if in appearance editing mode -		return; -	} - -	if (!gAgent.getRegion()) -	{ -		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; -		return; -	} -	if (gAgent.getRegion()->getCentralBakeVersion()==0) -	{ -		LL_WARNS() << "Region does not support baking" << LL_ENDL; -	} -	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 -	if (url.empty()) -	{ -		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; -		return; -	} -	 -	LLSD body; -	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); -	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) -	{ -		body = LLAppearanceMgr::instance().dumpCOF(); -	} -	else -	{ -		body["cof_version"] = cof_version; -		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) -		{ -			body["cof_version"] = cof_version+999; -		} -	} -	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; - -	mInFlightCounter++; -	mInFlightTimer.setTimerExpirySec(60.0); -	LLHTTPClient::post(url, body, this); -	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); -	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; -} - -void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) -{ -	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() -					   << " ================================= " << LL_ENDL; -	std::set<LLUUID> ais_items, local_items; -	const LLSD& cof_raw = content["cof_raw"]; -	for (LLSD::array_const_iterator it = cof_raw.beginArray(); -		 it != cof_raw.endArray(); ++it) -	{ -		const LLSD& item = *it; -		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) -		{ -			ais_items.insert(item["item_id"].asUUID()); -			if (item["type"].asInteger() == 24) // link -			{ -				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << LL_ENDL;  -			} -			else if (item["type"].asInteger() == 25) // folder link -			{ -				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << LL_ENDL;  -			} -			else -			{ -				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << " type: " << item["type"].asInteger() -								   << LL_ENDL;  -			} -		} -	} -	LL_INFOS("Avatar") << LL_ENDL; -	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()  -					   << " ================================= " << LL_ENDL; -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), -								  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i=0; i<item_array.size(); i++) -	{ -		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -		local_items.insert(inv_item->getUUID()); -		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() -						   << " linked_item_id: " << inv_item->getLinkedUUID() -						   << " name: " << inv_item->getName() -						   << " parent: " << inv_item->getParentUUID() -						   << LL_ENDL; -	} -	LL_INFOS("Avatar") << " ================================= " << LL_ENDL; -	S32 local_only = 0, ais_only = 0; -	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) -	{ -		if (ais_items.find(*it) == ais_items.end()) -		{ -			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; -			local_only++; -		} -	} -	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) -	{ -		if (local_items.find(*it) == local_items.end()) -		{ -			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; -			ais_only++; -		} -	} -	if (local_only==0 && ais_only==0) -	{ -		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " -						   << content["observed"].asInteger() -						   << " rcv " << content["expected"].asInteger() -						   << ")" << LL_ENDL; -	} -} - -/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	if (content["success"].asBoolean()) -	{ -		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; -		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -		{ -			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); -		} - -		onSuccess(); -	} -	else -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content); -	} -} - -void RequestAgentUpdateAppearanceResponder::onSuccess() -{ -	mInFlightCounter = llmax(mInFlightCounter-1,0); -} - -/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() -{ -	LL_WARNS("Avatar") << "appearance update request failed, status " -					   << getStatus() << " reason " << getReason() << LL_ENDL; - -	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -	{ -		const LLSD& content = getContent(); -		dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); -		debugCOF(content); -	} -	onFailure(); -} - -void RequestAgentUpdateAppearanceResponder::onFailure() -{ -	mInFlightCounter = llmax(mInFlightCounter-1,0); - -	F32 seconds_to_wait; -	mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); -	if (mRetryPolicy->shouldRetry(seconds_to_wait)) -	{ -		LL_INFOS() << "retrying" << LL_ENDL; -		doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), -						seconds_to_wait); -	} -	else -	{ -		LL_WARNS() << "giving up after too many retries" << LL_ENDL; -	} -}	 -  LLSD LLAppearanceMgr::dumpCOF() const  { @@ -3569,102 +3304,201 @@ LLSD LLAppearanceMgr::dumpCOF() const  void LLAppearanceMgr::requestServerAppearanceUpdate()  { -	mAppearanceResponder->onRequestRequested(); -} -class LLIncrementCofVersionResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLIncrementCofVersionResponder); -public: -	LLIncrementCofVersionResponder() : LLHTTPClient::Responder() +	if (!testCOFRequestVersion())  	{ -		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5); +		// *TODO: LL_LOG message here +		return;  	} -	virtual ~LLIncrementCofVersionResponder() +	if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired()))  	{ +		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; +		mInFlightCounter = 0;  	} -protected: -	virtual void httpSuccess() +	if (gAgentAvatarp->isEditingAppearance())  	{ -		LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		S32 new_version = content["category"]["version"].asInteger(); - -		// cof_version should have increased -		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion); - -		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version; +		LL_WARNS("Avatar") << "Avatar editing appearance, not sending request." << LL_ENDL; +		// don't send out appearance updates if in appearance editing mode +		return;  	} -	virtual void httpFailure() +	if (!gAgent.getRegion())  	{ -		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " -						   << dumpResponse() << LL_ENDL; -		F32 seconds_to_wait; -		mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); -		if (mRetryPolicy->shouldRetry(seconds_to_wait)) -		{ -			LL_INFOS() << "retrying" << LL_ENDL; -			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, -										LLAppearanceMgr::getInstance(), -										LLHTTPClient::ResponderPtr(this)), -										seconds_to_wait); -		} -		else -		{ -			LL_WARNS() << "giving up after too many retries" << LL_ENDL; -		} +		LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL; +		return;  	} - -private: -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr) -{ -	// If we don't have a region, report it as an error -	if (gAgent.getRegion() == NULL) +	if (gAgent.getRegion()->getCentralBakeVersion() == 0)  	{ -		LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL; -		return; +		LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;  	} -	std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion"); -	if (url.empty()) +	LLSD postData; +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))  	{ -		LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL; -		return; +		postData = LLAppearanceMgr::instance().dumpCOF();  	} - -	LL_INFOS() << "Requesting cof_version be incremented via capability to: " -			<< url << LL_ENDL; -	LLSD headers; -	LLSD body = LLSD::emptyMap(); - -	if (!responder_ptr.get()) +	else  	{ -		responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder()); +		postData["cof_version"] = cof_version; +		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) +		{ +			postData["cof_version"] = cof_version + 999; +		}  	} -	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f); +	mInFlightCounter++; +	mInFlightTimer.setTimerExpirySec(60.0); + +	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); +	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; + +    if (!gAgent.requestPostCapability("UpdateAvatarAppearance", postData,  +        static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::serverAppearanceUpdateSuccess, this, _1)),  +        static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::decrementInFlightCounter, this)))) +    { +        LL_WARNS("Avatar") << "Unable to access UpdateAvatarAppearance in this region." << LL_ENDL; +    }  } -U32 LLAppearanceMgr::getNumAttachmentsInCOF() +void LLAppearanceMgr::serverAppearanceUpdateSuccess(const LLSD &result)  { -	const LLUUID cof = getCOF(); -	LLInventoryModel::item_array_t obj_items; -	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); -	return obj_items.size(); +    decrementInFlightCounter(); +    if (result["success"].asBoolean()) +    { +        LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; +        if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +        { +            dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result); +        } +    } +    else +    { +        LL_WARNS("Avatar") << "Non success response for change appearance" << LL_ENDL; +        if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +        { +            debugAppearanceUpdateCOF(result); +        } +    } +} + +/*static*/ +void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content) +{ +    dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); + +    LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() +        << " ================================= " << LL_ENDL; +    std::set<LLUUID> ais_items, local_items; +    const LLSD& cof_raw = content["cof_raw"]; +    for (LLSD::array_const_iterator it = cof_raw.beginArray(); +        it != cof_raw.endArray(); ++it) +    { +        const LLSD& item = *it; +        if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) +        { +            ais_items.insert(item["item_id"].asUUID()); +            if (item["type"].asInteger() == 24) // link +            { +                LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() +                    << " linked_item_id: " << item["asset_id"].asUUID() +                    << " name: " << item["name"].asString() +                    << LL_ENDL; +            } +            else if (item["type"].asInteger() == 25) // folder link +            { +                LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() +                    << " linked_item_id: " << item["asset_id"].asUUID() +                    << " name: " << item["name"].asString() +                    << LL_ENDL; +            } +            else +            { +                LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() +                    << " linked_item_id: " << item["asset_id"].asUUID() +                    << " name: " << item["name"].asString() +                    << " type: " << item["type"].asInteger() +                    << LL_ENDL; +            } +        } +    } +    LL_INFOS("Avatar") << LL_ENDL; +    LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() +        << " ================================= " << LL_ENDL; +    LLInventoryModel::cat_array_t cat_array; +    LLInventoryModel::item_array_t item_array; +    gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +        cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); +    for (S32 i = 0; i < item_array.size(); i++) +    { +        const LLViewerInventoryItem* inv_item = item_array.at(i).get(); +        local_items.insert(inv_item->getUUID()); +        LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() +            << " linked_item_id: " << inv_item->getLinkedUUID() +            << " name: " << inv_item->getName() +            << " parent: " << inv_item->getParentUUID() +            << LL_ENDL; +    } +    LL_INFOS("Avatar") << " ================================= " << LL_ENDL; +    S32 local_only = 0, ais_only = 0; +    for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) +    { +        if (ais_items.find(*it) == ais_items.end()) +        { +            LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; +            local_only++; +        } +    } +    for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) +    { +        if (local_items.find(*it) == local_items.end()) +        { +            LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; +            ais_only++; +        } +    } +    if (local_only == 0 && ais_only == 0) +    { +        LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " +            << content["observed"].asInteger() +            << " rcv " << content["expected"].asInteger() +            << ")" << LL_ENDL; +    }  } +bool LLAppearanceMgr::testCOFRequestVersion() const +{ +	// If we have already received an update for this or higher cof version, ignore. +	S32 cof_version = getCOFVersion(); +	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; +	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; + +	LL_DEBUGS("Avatar") << "cof_version " << cof_version +		<< " last_rcv " << last_rcv +		<< " last_req " << last_req +		<< " in flight " << mInFlightCounter  +		<< LL_ENDL; +	if (cof_version < last_rcv) +	{ +		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv +			<< " will not request for " << cof_version << LL_ENDL; +		return false; +	} +	if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version) +	{ +		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req +			<< " will not request for " << cof_version << LL_ENDL; +		return false; +	} + +	// Actually send the request. +	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; +	return true; +} +  std::string LLAppearanceMgr::getAppearanceServiceURL() const  {  	if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) @@ -3929,15 +3763,17 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,  	}  } +bool LLAppearanceMgr::mActive = true; +  LLAppearanceMgr::LLAppearanceMgr():  	mAttachmentInvLinkEnabled(false),  	mOutfitIsDirty(false),  	mOutfitLocked(false), -	mIsInUpdateAppearanceFromCOF(false), -	mAppearanceResponder(new RequestAgentUpdateAppearanceResponder) +	mInFlightCounter(0), +	mInFlightTimer(), +	mIsInUpdateAppearanceFromCOF(false)  {  	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); -  	// unlock outfit on save operation completed  	outfit_observer.addCOFSavedCallback(boost::bind(  			&LLAppearanceMgr::setOutfitLocked, this, false)); @@ -3945,11 +3781,12 @@ LLAppearanceMgr::LLAppearanceMgr():  	mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(  			"OutfitOperationsTimeout"))); -	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL); +	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL);  }  LLAppearanceMgr::~LLAppearanceMgr()  { +	mActive = false;  }  void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index ee9d3b7209..3d9a1f1518 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -34,12 +34,10 @@  #include "llinventorymodel.h"  #include "llinventoryobserver.h"  #include "llviewerinventory.h" -#include "llhttpclient.h"  class LLWearableHoldingPattern;  class LLInventoryCallback;  class LLOutfitUnLockTimer; -class RequestAgentUpdateAppearanceResponder;  class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  { @@ -54,7 +52,6 @@ public:  	void updateAppearanceFromCOF(bool enforce_item_restrictions = true,  								 bool enforce_ordering = true,  								 nullary_func_t post_update_func = no_op); -	bool needToSaveCOF();  	void updateCOF(const LLUUID& category, bool append = false);  	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);  	void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); @@ -224,20 +221,23 @@ public:  	void requestServerAppearanceUpdate(); -	void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL); +	void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } +	std::string getAppearanceServiceURL() const; -	U32 getNumAttachmentsInCOF(); -	// *HACK Remove this after server side texture baking is deployed on all sims. -	void incrementCofVersionLegacy(); +	bool testCOFRequestVersion() const; +	void decrementInFlightCounter() +	{ +		mInFlightCounter = llmax(mInFlightCounter - 1, 0); +	} -	void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } -	std::string getAppearanceServiceURL() const;  private: +    void serverAppearanceUpdateSuccess(const LLSD &result); +    static void debugAppearanceUpdateCOF(const LLSD& content); +  	std::string		mAppearanceServiceURL; -  protected:  	LLAppearanceMgr();  	~LLAppearanceMgr(); @@ -261,13 +261,14 @@ private:  	bool mOutfitIsDirty;  	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. -	LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; -  	/**  	 * Lock for blocking operations on outfit until server reply or timeout exceed  	 * to avoid unsynchronized outfit state or performing duplicate operations.  	 */  	bool mOutfitLocked; +	S32  mInFlightCounter; +	LLTimer mInFlightTimer; +	static bool mActive;  	std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index d2b1dcbf35..e492b8cf5d 100755 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -674,6 +674,7 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)  } +#if 0  /////////////////////////////////////////////////////  // LLNewAgentInventoryVariablePriceResponder::Impl //  ///////////////////////////////////////////////////// @@ -1144,5 +1145,5 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(  				LLPointer<LLNewAgentInventoryVariablePriceResponder>(this)));  	}  } - +#endif diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 7fbebc7481..18968bb1af 100755 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -79,6 +79,7 @@ protected:  	virtual void httpFailure();  }; +#if 0  // A base class which goes through and performs some default  // actions for variable price uploads.  If more specific actions  // are needed (such as different confirmation messages, etc.) @@ -115,6 +116,7 @@ private:  	class Impl;  	Impl* mImpl;  }; +#endif  class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder  { diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 38e153137c..e260142254 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -35,7 +35,6 @@  // external library headers  // other Linden headers  #include "llcharacter.h" -#include "llhttpclient.h"  #include "lltimer.h"  #include "llviewercontrol.h"  #include "llviewermenu.h" @@ -43,7 +42,10 @@  #include "llviewerregion.h"  #include "llvoavatar.h"  #include "llworld.h" - +#include "llhttpsdhandler.h" +#include "httpheaders.h" +#include "httpoptions.h" +#include "llcorehttputil.h"  static	const std::string KEY_AGENTS = "agents";			// map  static 	const std::string KEY_WEIGHT = "weight";			// integer @@ -55,166 +57,178 @@ static	const std::string KEY_ERROR = "error";  // Send data updates about once per minute, only need per-frame resolution  LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer; +//LLCore::HttpRequest::ptr_t LLAvatarRenderInfoAccountant::sHttpRequest; - -// HTTP responder class for GET request for avatar render weight information -class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder +//========================================================================= +void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64 regionHandle)  { -public: -	LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle) -	{ -	} - -	virtual void error(U32 statusNum, const std::string& reason) -	{ -		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if (regionp) -		{ -			LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum  -				<< ", " << reason -				<< " returned by region " << regionp->getName() -				<< LL_ENDL; -		} -		else -		{ -			LL_WARNS() << "Avatar render weight GET error recieved but region not found for "  -				<< mRegionHandle  -				<< ", error " << statusNum  -				<< ", " << reason -				<< LL_ENDL; -		} - -	} - -	virtual void result(const LLSD& content) -	{ -		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if (regionp) -		{ -			if (LLAvatarRenderInfoAccountant::logRenderInfo()) -			{ -				LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; -			} - -			if (content.isMap()) -			{ -				if (content.has(KEY_AGENTS)) -				{ -					const LLSD & agents = content[KEY_AGENTS]; -					if (agents.isMap()) -					{ -						LLSD::map_const_iterator	report_iter = agents.beginMap(); -						while (report_iter != agents.endMap()) -						{ -							LLUUID target_agent_id = LLUUID(report_iter->first); -							const LLSD & agent_info_map = report_iter->second; -							LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); -							if (avatarp &&  -								avatarp->isAvatar() && -								agent_info_map.isMap()) -							{	// Extract the data for this avatar - -								if (LLAvatarRenderInfoAccountant::logRenderInfo()) -								{ -									LL_INFOS() << "LRI:  Agent " << target_agent_id  -										<< ": " << agent_info_map << LL_ENDL; -								} - -								if (agent_info_map.has(KEY_WEIGHT)) -								{ -									((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); -								} -							} -							report_iter++; -						} -					} -				}	// has "agents" -				else if (content.has(KEY_ERROR)) -				{ -					const LLSD & error = content[KEY_ERROR]; -					LL_WARNS() << "Avatar render info GET error: " -						<< error[KEY_IDENTIFIER] -						<< ": " << error[KEY_MESSAGE]  -						<< " from region " << regionp->getName() -						<< LL_ENDL; -				} -			} -		} -		else -		{ -			LL_INFOS() << "Avatar render weight info recieved but region not found for "  -				<< mRegionHandle << LL_ENDL; -		} -	} - -private: -	U64		mRegionHandle; -}; +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t  +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +    if (!regionp) +    { +        LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for "  +                << regionHandle << LL_ENDL; +        return; +    } + +    LLSD httpResults = result["http_result"]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("AvatarRenderInfoAccountant") << "HTTP status, " << status.toTerseString() << LL_ENDL; +        return; +    } + +    if (result.has(KEY_AGENTS)) +    { +        const LLSD & agents = result[KEY_AGENTS]; +        if (agents.isMap()) +        { +            LLSD::map_const_iterator	report_iter = agents.beginMap(); +            while (report_iter != agents.endMap()) +            { +                LLUUID target_agent_id = LLUUID(report_iter->first); +                const LLSD & agent_info_map = report_iter->second; +                LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); +                if (avatarp &&  +                    avatarp->isAvatar() && +                    agent_info_map.isMap()) +                {	// Extract the data for this avatar + +                    if (LLAvatarRenderInfoAccountant::logRenderInfo()) +                    { +                        LL_INFOS() << "LRI:  Agent " << target_agent_id  +                            << ": " << agent_info_map << LL_ENDL; +                    } + +                    if (agent_info_map.has(KEY_WEIGHT)) +                    { +                        ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); +                    } +                } +                report_iter++; +            } +        } +    }	// has "agents" +    else if (result.has(KEY_ERROR)) +    { +        const LLSD & error = result[KEY_ERROR]; +        LL_WARNS() << "Avatar render info GET error: " +            << error[KEY_IDENTIFIER] +            << ": " << error[KEY_MESSAGE]  +            << " from region " << regionp->getName() +            << LL_ENDL; +    } +} -// HTTP responder class for POST request for avatar render weight information -class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder +//------------------------------------------------------------------------- +void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U64 regionHandle)  { -public: -	LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle) -	{ -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +    if (!regionp) +    { +        LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but region not found for " +            << regionHandle << LL_ENDL; +        return; +    } + +    if (logRenderInfo()) +    { +        LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Sending avatar render info to region " << regionp->getName() +                << " from " << url << LL_ENDL; +    } + +    // Build the render info to POST to the region +    LLSD report = LLSD::emptyMap(); +    LLSD agents = LLSD::emptyMap(); + +    std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); +    while( iter != LLCharacter::sInstances.end() ) +    { +        LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter); +        if (avatar && +            avatar->getRezzedStatus() >= 2 &&					// Mostly rezzed (maybe without baked textures downloaded) +            !avatar->isDead() &&								// Not dead yet +            avatar->getObjectHost() == regionp->getHost())		// Ensure it's on the same region +        { +            avatar->calculateUpdateRenderCost();			// Make sure the numbers are up-to-date + +            LLSD info = LLSD::emptyMap(); +            if (avatar->getVisualComplexity() > 0) +            { +                info[KEY_WEIGHT] = avatar->getVisualComplexity(); +                agents[avatar->getID().asString()] = info; + +                if (logRenderInfo()) +                { +                    LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Sending avatar render info for " << avatar->getID() +                            << ": " << info << LL_ENDL; +                    LL_INFOS("AvatarRenderInfoAccountant") << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes() +                            << ", area " << avatar->getAttachmentSurfaceArea() +                            << LL_ENDL; +                } +            } +        } +        iter++; +    } + +    if (agents.size() == 0) +        return; + +    report[KEY_AGENTS] = agents; +    regionp = NULL; +    LLSD result = httpAdapter->postAndYield(httpRequest, url, report); + +    regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +    if (!regionp) +    { +        LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for " +                << regionHandle << LL_ENDL; +        return; +    } + +    LLSD httpResults = result["http_result"]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +    if (!status) +    { +        LL_WARNS("AvatarRenderInfoAccountant") << "HTTP status, " << status.toTerseString() << LL_ENDL; +        return; +    } + +    if (LLAvatarRenderInfoAccountant::logRenderInfo()) +    { +        LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Result for avatar weights POST for region " << regionp->getName() +            << ": " << result << LL_ENDL; +    } + +    if (result.isMap()) +    { +        if (result.has(KEY_ERROR)) +        { +            const LLSD & error = result[KEY_ERROR]; +            LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render info POST error: " +                << error[KEY_IDENTIFIER] +                << ": " << error[KEY_MESSAGE]  +                << " from region " << regionp->getName() +                << LL_ENDL; +        } +    } -	virtual void error(U32 statusNum, const std::string& reason) -	{ -		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if (regionp) -		{ -			LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum  -				<< ", " << reason -				<< " returned by region " << regionp->getName() -				<< LL_ENDL; -		} -		else -		{ -			LL_WARNS() << "Avatar render weight POST error recieved but region not found for "  -				<< mRegionHandle  -				<< ", error " << statusNum  -				<< ", " << reason -				<< LL_ENDL; -		} -	} - -	virtual void result(const LLSD& content) -	{ -		LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if (regionp) -		{ -			if (LLAvatarRenderInfoAccountant::logRenderInfo()) -			{ -				LL_INFOS() << "LRI: Result for avatar weights POST for region " << regionp->getName() -					<< ": " << content << LL_ENDL; -			} - -			if (content.isMap()) -			{ -				if (content.has(KEY_ERROR)) -				{ -					const LLSD & error = content[KEY_ERROR]; -					LL_WARNS() << "Avatar render info POST error: " -						<< error[KEY_IDENTIFIER] -						<< ": " << error[KEY_MESSAGE]  -						<< " from region " << regionp->getName() -						<< LL_ENDL; -				} -			} -		} -		else -		{ -			LL_INFOS() << "Avatar render weight POST result recieved but region not found for "  -				<< mRegionHandle << LL_ENDL; -		} -	} - -private: -	U64		mRegionHandle; -}; +}  // static   // Send request for one region, no timer checks @@ -223,53 +237,9 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio  	std::string url = regionp->getCapability("AvatarRenderInfo");  	if (!url.empty())  	{ -		if (logRenderInfo()) -		{ -			LL_INFOS() << "LRI: Sending avatar render info to region " -				<< regionp->getName()  -				<< " from " << url -				<< LL_ENDL; -		} - -		// Build the render info to POST to the region -		LLSD report = LLSD::emptyMap(); -		LLSD agents = LLSD::emptyMap(); -				 -		std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); -		while( iter != LLCharacter::sInstances.end() ) -		{ -			LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter); -			if (avatar && -				avatar->getRezzedStatus() >= 2 &&					// Mostly rezzed (maybe without baked textures downloaded) -				!avatar->isDead() &&								// Not dead yet -				avatar->getObjectHost() == regionp->getHost())		// Ensure it's on the same region -			{ -				avatar->calculateUpdateRenderCost();			// Make sure the numbers are up-to-date - -				LLSD info = LLSD::emptyMap(); -				if (avatar->getVisualComplexity() > 0) -				{ -					info[KEY_WEIGHT] = avatar->getVisualComplexity(); -					agents[avatar->getID().asString()] = info; - -					if (logRenderInfo()) -					{ -						LL_INFOS() << "LRI: Sending avatar render info for " << avatar->getID() -							<< ": " << info << LL_ENDL; -						LL_INFOS() << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes() -							<< ", area " << avatar->getAttachmentSurfaceArea() -							<< LL_ENDL; -					} -				} -			} -			iter++; -		} - -		report[KEY_AGENTS] = agents; -		if (agents.size() > 0) -		{ -			LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle())); -		} +        std::string coroname = +            LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro", +            boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro, url, regionp->getHandle()));  	}  } @@ -292,7 +262,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi  		}  		// First send a request to get the latest data -		LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle())); +        std::string coroname = +            LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro", +            boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro, url, regionp->getHandle()));  	}  } @@ -301,6 +273,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi  // Called every frame - send render weight requests to every region  void LLAvatarRenderInfoAccountant::idle()  { +//	if (!LLAvatarRenderInfoAccountant::sHttpRequest) +//		sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +  	if (sRenderInfoReportTimer.hasExpired())  	{  		const F32 SECS_BETWEEN_REGION_SCANS   =  5.f;		// Scan the region list every 5 seconds @@ -393,6 +368,7 @@ void LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer(const LLUUID& reg  // static   bool LLAvatarRenderInfoAccountant::logRenderInfo()  { -	static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false); -	return render_mute_logging_enabled; +    return true; +// 	static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false); +// 	return render_mute_logging_enabled;  } diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h index d68f2dccfb..f7a04cca2c 100644 --- a/indra/newview/llavatarrenderinfoaccountant.h +++ b/indra/newview/llavatarrenderinfoaccountant.h @@ -29,6 +29,9 @@  #if ! defined(LL_llavatarrenderinfoaccountant_H)  #define LL_llavatarrenderinfoaccountant_H +#include "httpcommon.h" +#include "llcoros.h" +  class LLViewerRegion;  // Class to gather avatar rendering information  @@ -36,8 +39,6 @@ class LLViewerRegion;  class LLAvatarRenderInfoAccountant  {  public: -	LLAvatarRenderInfoAccountant()	{}; -	~LLAvatarRenderInfoAccountant()	{};  	static void sendRenderInfoToRegion(LLViewerRegion * regionp);  	static void getRenderInfoFromRegion(LLViewerRegion * regionp); @@ -49,8 +50,16 @@ public:  	static bool logRenderInfo();  private: +	LLAvatarRenderInfoAccountant() {}; +	~LLAvatarRenderInfoAccountant()	{}; +  	// Send data updates about once per minute, only need per-frame resolution  	static LLFrameTimer sRenderInfoReportTimer; + +    static void avatarRenderInfoGetCoro(std::string url, U64 regionHandle); +    static void avatarRenderInfoReportCoro(std::string url, U64 regionHandle); + +  };  #endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */ diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp deleted file mode 100755 index ef9b910ae5..0000000000 --- a/indra/newview/llcapabilitylistener.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/** - * @file   llcapabilitylistener.cpp - * @author Nat Goodspeed - * @date   2009-01-07 - * @brief  Implementation for llcapabilitylistener. - *  - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -// Precompiled header -#include "llviewerprecompiledheaders.h" -// associated header -#include "llcapabilitylistener.h" -// STL headers -#include <map> -// std headers -// external library headers -#include <boost/bind.hpp> -// other Linden headers -#include "stringize.h" -#include "llcapabilityprovider.h" -#include "message.h" - -class LLCapabilityListener::CapabilityMappers: public LLSingleton<LLCapabilityListener::CapabilityMappers> -{ -public: -    void registerMapper(const LLCapabilityListener::CapabilityMapper*); -    void unregisterMapper(const LLCapabilityListener::CapabilityMapper*); -    const LLCapabilityListener::CapabilityMapper* find(const std::string& cap) const; - -    struct DupCapMapper: public std::runtime_error -    { -        DupCapMapper(const std::string& what): -            std::runtime_error(std::string("DupCapMapper: ") + what) -        {} -    }; - -private: -    friend class LLSingleton<LLCapabilityListener::CapabilityMappers>; -    CapabilityMappers(); - -    typedef std::map<std::string, const LLCapabilityListener::CapabilityMapper*> CapabilityMap; -    CapabilityMap mMap; -}; - -LLCapabilityListener::LLCapabilityListener(const std::string& name, -                                           LLMessageSystem* messageSystem, -                                           const LLCapabilityProvider& provider, -                                           const LLUUID& agentID, -                                           const LLUUID& sessionID): -    mEventPump(name), -    mMessageSystem(messageSystem), -    mProvider(provider), -    mAgentID(agentID), -    mSessionID(sessionID) -{ -    mEventPump.listen("self", boost::bind(&LLCapabilityListener::capListener, this, _1)); -} - -bool LLCapabilityListener::capListener(const LLSD& request) -{ -    // Extract what we want from the request object. We do it all up front -    // partly to document what we expect. -    LLSD::String cap(request["message"]); -    LLSD payload(request["payload"]); -    LLSD::String reply(request["reply"]); -    LLSD::String error(request["error"]); -    LLSD::Real timeout(request["timeout"]); -    // If the LLSD doesn't even have a "message" key, we doubt it was intended -    // for this listener. -    if (cap.empty()) -    { -        LL_ERRS("capListener") << "capability request event without 'message' key to '" -                               << getCapAPI().getName() -                               << "' on region\n" << mProvider.getDescription() -                               << LL_ENDL; -        return false;               // in case fatal-error function isn't -    } -    // Establish default timeout. This test relies on LLSD::asReal() returning -    // exactly 0.0 for an undef value. -    if (! timeout) -    { -        timeout = HTTP_REQUEST_EXPIRY_SECS; -    } -    // Look up the url for the requested capability name. -    std::string url = mProvider.getCapability(cap); -    if (! url.empty()) -    { -        // This capability is supported by the region to which we're talking. -        LLHTTPClient::post(url, payload, -                           new LLSDMessage::EventResponder(LLEventPumps::instance(), -                                                           request, -                                                           mProvider.getDescription(), -                                                           cap, reply, error), -                           LLSD(),  // headers -                           timeout); -    } -    else -    { -        // Capability not supported -- do we have a registered mapper? -        const CapabilityMapper* mapper = CapabilityMappers::instance().find(cap); -        if (! mapper)               // capability neither supported nor mapped -        { -            LL_ERRS("capListener") << "unsupported capability '" << cap << "' request to '" -                                   << getCapAPI().getName() << "' on region\n" -                                   << mProvider.getDescription() -                                   << LL_ENDL; -        } -        else if (! mapper->getReplyName().empty()) // mapper expects reply support -        { -            LL_ERRS("capListener") << "Mapper for capability '" << cap -                                   << "' requires unimplemented support for reply message '" -                                   << mapper->getReplyName() -                                   << "' on '" << getCapAPI().getName() << "' on region\n" -                                   << mProvider.getDescription() -                                   << LL_ENDL; -        } -        else -        { -            LL_INFOS("capListener") << "fallback invoked for capability '" << cap -                                    << "' request to '" << getCapAPI().getName() -                                    << "' on region\n" << mProvider.getDescription() -                                    << LL_ENDL; -            mapper->buildMessage(mMessageSystem, mAgentID, mSessionID, cap, payload); -            mMessageSystem->sendReliable(mProvider.getHost()); -        } -    } -    return false; -} - -LLCapabilityListener::CapabilityMapper::CapabilityMapper(const std::string& cap, const std::string& reply): -    mCapName(cap), -    mReplyName(reply) -{ -    LLCapabilityListener::CapabilityMappers::instance().registerMapper(this); -} - -LLCapabilityListener::CapabilityMapper::~CapabilityMapper() -{ -    LLCapabilityListener::CapabilityMappers::instance().unregisterMapper(this); -} - -LLSD LLCapabilityListener::CapabilityMapper::readResponse(LLMessageSystem* messageSystem) const -{ -    return LLSD(); -} - -LLCapabilityListener::CapabilityMappers::CapabilityMappers() {} - -void LLCapabilityListener::CapabilityMappers::registerMapper(const LLCapabilityListener::CapabilityMapper* mapper) -{ -    // Try to insert a new map entry by which we can look up the passed mapper -    // instance. -    std::pair<CapabilityMap::iterator, bool> inserted = -        mMap.insert(CapabilityMap::value_type(mapper->getCapName(), mapper)); -    // If we already have a mapper for that name, insert() merely located the -    // existing iterator and returned false. It is a coding error to try to -    // register more than one mapper for the same capability name. -    if (! inserted.second) -    { -        throw DupCapMapper(std::string("Duplicate capability name ") + mapper->getCapName()); -    } -} - -void LLCapabilityListener::CapabilityMappers::unregisterMapper(const LLCapabilityListener::CapabilityMapper* mapper) -{ -    CapabilityMap::iterator found = mMap.find(mapper->getCapName()); -    if (found != mMap.end()) -    { -        mMap.erase(found); -    } -} - -const LLCapabilityListener::CapabilityMapper* -LLCapabilityListener::CapabilityMappers::find(const std::string& cap) const -{ -    CapabilityMap::const_iterator found = mMap.find(cap); -    if (found != mMap.end()) -    { -        return found->second; -    } -    return NULL; -} diff --git a/indra/newview/llcapabilitylistener.h b/indra/newview/llcapabilitylistener.h deleted file mode 100755 index e7535013e7..0000000000 --- a/indra/newview/llcapabilitylistener.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file   llcapabilitylistener.h - * @author Nat Goodspeed - * @date   2009-01-07 - * @brief  Provide an event-based API for capability requests - *  - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLCAPABILITYLISTENER_H) -#define LL_LLCAPABILITYLISTENER_H - -#include "llevents.h"               // LLEventPump -#include "llsdmessage.h"            // LLSDMessage::ArgError -#include "llerror.h"                // LOG_CLASS() - -class LLCapabilityProvider; -class LLMessageSystem; -class LLSD; - -class LLCapabilityListener -{ -    LOG_CLASS(LLCapabilityListener); -public: -    LLCapabilityListener(const std::string& name, LLMessageSystem* messageSystem, -                         const LLCapabilityProvider& provider, -                         const LLUUID& agentID, const LLUUID& sessionID); - -    /// Capability-request exception -    typedef LLSDMessage::ArgError ArgError; -    /// Get LLEventPump on which we listen for capability requests -    /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) -    LLEventPump& getCapAPI() { return mEventPump; } - -    /** -     * Base class for mapping an as-yet-undeployed capability name to a (pair -     * of) LLMessageSystem message(s). To map a capability name to such -     * messages, derive a subclass of CapabilityMapper and declare a static -     * instance in a translation unit known to be loaded. The mapping is not -     * region-specific. If an LLViewerRegion's capListener() receives a -     * request for a supported capability, it will use the capability's URL. -     * If not, it will look for an applicable CapabilityMapper subclass -     * instance. -     */ -    class CapabilityMapper -    { -    public: -        /** -         * Base-class constructor. Typically your subclass constructor will -         * pass these parameters as literals. -         * @param cap the capability name handled by this (subclass) instance -         * @param reply the name of the response LLMessageSystem message. Omit -         * if the LLMessageSystem message you intend to send doesn't prompt a -         * reply message, or if you already handle that message in some other -         * way. -         */ -        CapabilityMapper(const std::string& cap, const std::string& reply = ""); -        virtual ~CapabilityMapper(); -        /// query the capability name -        std::string getCapName() const { return mCapName; } -        /// query the reply message name -        std::string getReplyName() const { return mReplyName; } -        /** -         * Override this method to build the LLMessageSystem message we should -         * send instead of the requested capability message. DO NOT send that -         * message: that will be handled by the caller. -         */ -        virtual void buildMessage(LLMessageSystem* messageSystem, -                                  const LLUUID& agentID, -                                  const LLUUID& sessionID, -                                  const std::string& capabilityName, -                                  const LLSD& payload) const = 0; -        /** -         * Override this method if you pass a non-empty @a reply -         * LLMessageSystem message name to the constructor: that is, if you -         * expect to receive an LLMessageSystem message in response to the -         * message you constructed in buildMessage(). If you don't pass a @a -         * reply message name, you need not override this method as it won't -         * be called. -         * -         * Using LLMessageSystem message-reading operations, your -         * readResponse() override should construct and return an LLSD object -         * of the form you expect to receive from the real implementation of -         * the capability you intend to invoke, when it finally goes live. -         */ -        virtual LLSD readResponse(LLMessageSystem* messageSystem) const; - -    private: -        const std::string mCapName; -        const std::string mReplyName; -    }; - -private: -    /// Bind the LLCapabilityProvider passed to our ctor -    const LLCapabilityProvider& mProvider; - -    /// Post an event to this LLEventPump to invoke a capability message on -    /// the bound LLCapabilityProvider's server -    /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) -    LLEventStream mEventPump; - -    LLMessageSystem* mMessageSystem; -    LLUUID mAgentID, mSessionID; - -    /// listener to process capability requests -    bool capListener(const LLSD&); - -    /// helper class for capListener() -    class CapabilityMappers; -}; - -#endif /* ! defined(LL_LLCAPABILITYLISTENER_H) */ diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp deleted file mode 100755 index f1ef8e9a03..0000000000 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/**  - * @file llclassifiedstatsresponder.cpp - * @brief Receives information about classified ad click-through - * counts for display in the classified information UI. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llclassifiedstatsresponder.h" - -#include "llpanelclassified.h" -#include "llpanel.h" -#include "llhttpclient.h" -#include "llsdserialize.h" -#include "llviewerregion.h" -#include "llview.h" -#include "message.h" - -LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID classified_id) -:	mClassifiedID(classified_id) -{} - -/*virtual*/ -void LLClassifiedStatsResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	S32 teleport = content["teleport_clicks"].asInteger(); -	S32 map = content["map_clicks"].asInteger(); -	S32 profile = content["profile_clicks"].asInteger(); -	S32 search_teleport = content["search_teleport_clicks"].asInteger(); -	S32 search_map = content["search_map_clicks"].asInteger(); -	S32 search_profile = content["search_profile_clicks"].asInteger(); - -	LLPanelClassifiedInfo::setClickThrough(	mClassifiedID,  -											teleport + search_teleport,  -											map + search_map, -											profile + search_profile, -											true); -} - -/*virtual*/ -void LLClassifiedStatsResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -} - diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h deleted file mode 100755 index efa4d82411..0000000000 --- a/indra/newview/llclassifiedstatsresponder.h +++ /dev/null @@ -1,50 +0,0 @@ -/**  - * @file llclassifiedstatsresponder.h - * @brief Receives information about classified ad click-through - * counts for display in the classified information UI. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ -#ifndef LL_LLCLASSIFIEDSTATSRESPONDER_H -#define LL_LLCLASSIFIEDSTATSRESPONDER_H - -#include "llhttpclient.h" -#include "llview.h" -#include "lluuid.h" - -class LLClassifiedStatsResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLClassifiedStatsResponder); -public: -	LLClassifiedStatsResponder(LLUUID classified_id); - -protected: -	//If we get back a normal response, handle it here -	virtual void httpSuccess(); -	//If we get back an error (not found, etc...), handle it here -	virtual void httpFailure(); - -protected: -	LLUUID mClassifiedID; -}; - -#endif // LL_LLCLASSIFIEDSTATSRESPONDER_H diff --git a/indra/newview/llcoproceduremanager.cpp b/indra/newview/llcoproceduremanager.cpp new file mode 100644 index 0000000000..d3168985f8 --- /dev/null +++ b/indra/newview/llcoproceduremanager.cpp @@ -0,0 +1,176 @@ +/** +* @file llcoproceduremanager.cpp +* @author Rider Linden +* @brief Singleton class for managing asset uploads to the sim. +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "linden_common.h"  + +#include "llviewercontrol.h" + +#include "llcoproceduremanager.h" + +//========================================================================= +#define COROCOUNT 1 + +//========================================================================= +LLCoprocedureManager::LLCoprocedureManager(): +    LLSingleton<LLCoprocedureManager>(), +    mPendingCoprocs(), +    mShutdown(false), +    mWakeupTrigger("CoprocedureManager", true), +    mCoroMapping(), +    mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID) +{ + +    // *TODO: Retrieve the actual number of concurrent coroutines fro gSavedSettings and +    // clamp to a "reasonable" number. +    for (int count = 0; count < COROCOUNT; ++count) +    { +        LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter = +            LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t( +            new LLCoreHttpUtil::HttpCoroutineAdapter("uploadPostAdapter", mHTTPPolicy)); + +        std::string uploadCoro = LLCoros::instance().launch("LLCoprocedureManager::coprocedureInvokerCoro", +            boost::bind(&LLCoprocedureManager::coprocedureInvokerCoro, this, httpAdapter)); + +        mCoroMapping.insert(CoroAdapterMap_t::value_type(uploadCoro, httpAdapter)); +    } + +    mWakeupTrigger.post(LLSD()); +} + +LLCoprocedureManager::~LLCoprocedureManager()  +{ +    shutdown(); +} + +//========================================================================= + +void LLCoprocedureManager::shutdown(bool hardShutdown) +{ +    CoroAdapterMap_t::iterator it; + +    for (it = mCoroMapping.begin(); it != mCoroMapping.end(); ++it) +    { +        if (!(*it).first.empty()) +        { +            if (hardShutdown) +            { +                LLCoros::instance().kill((*it).first); +            } +        } +        if ((*it).second) +        { +            (*it).second->cancelYieldingOperation(); +        } +    } + +    mShutdown = true; +    mCoroMapping.clear(); +    mPendingCoprocs.clear(); +} + +//========================================================================= +LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &name, LLCoprocedureManager::CoProcedure_t proc) +{ +    LLUUID id(LLUUID::generateNewID()); + +    mPendingCoprocs.push_back(QueuedCoproc::ptr_t(new QueuedCoproc(name, id, proc))); +    LL_INFOS() << "Coprocedure(" << name << ") enqueued with id=" << id.asString() << LL_ENDL; + +    mWakeupTrigger.post(LLSD()); + +    return id; +} + +void LLCoprocedureManager::cancelCoprocedure(const LLUUID &id) +{ +    // first check the active coroutines.  If there, remove it and return. +    ActiveCoproc_t::iterator itActive = mActiveCoprocs.find(id); +    if (itActive != mActiveCoprocs.end()) +    { +        LL_INFOS() << "Found and canceling active coprocedure with id=" << id.asString() << LL_ENDL; +        (*itActive).second->cancelYieldingOperation(); +        mActiveCoprocs.erase(itActive); +        return; +    } + +    for (CoprocQueue_t::iterator it = mPendingCoprocs.begin(); it != mPendingCoprocs.end(); ++it) +    { +        if ((*it)->mId == id) +        { +            LL_INFOS() << "Found and removing queued coroutine(" << (*it)->mName << ") with Id=" << id.asString() << LL_ENDL; +            mPendingCoprocs.erase(it); +            return; +        } +    } + +    LL_INFOS() << "Coprocedure with Id=" << id.asString() << " was not found." << LL_ENDL; +} + +//========================================================================= +void LLCoprocedureManager::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter) +{ +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    while (!mShutdown) +    { +        llcoro::waitForEventOn(mWakeupTrigger); +        if (mShutdown) +            break; +         +        while (!mPendingCoprocs.empty()) +        { +            QueuedCoproc::ptr_t coproc = mPendingCoprocs.front(); +            mPendingCoprocs.pop_front(); +            mActiveCoprocs.insert(ActiveCoproc_t::value_type(coproc->mId, httpAdapter)); + +            LL_INFOS() << "Dequeued and invoking coprocedure(" << coproc->mName << ") with id=" << coproc->mId.asString() << LL_ENDL; + +            try +            { +                coproc->mProc(httpAdapter, coproc->mId); +            } +            catch (std::exception &e) +            { +                LL_WARNS() << "Coprocedure(" << coproc->mName << ") id=" << coproc->mId.asString() << +                    " threw an exception! Message=\"" << e.what() << "\"" << LL_ENDL; +            } +            catch (...) +            { +                LL_WARNS() << "A non std::exception was thrown from " << coproc->mName << " with id=" << coproc->mId << "." << LL_ENDL; +            } + +            LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << LL_ENDL; + +            ActiveCoproc_t::iterator itActive = mActiveCoprocs.find(coproc->mId); +            if (itActive != mActiveCoprocs.end()) +            { +                mActiveCoprocs.erase(itActive); +            } +        } +    } +} diff --git a/indra/newview/llcoproceduremanager.h b/indra/newview/llcoproceduremanager.h new file mode 100644 index 0000000000..6ba3891e87 --- /dev/null +++ b/indra/newview/llcoproceduremanager.h @@ -0,0 +1,117 @@ +/** +* @file llcoproceduremanager.h +* @author Rider Linden +* @brief Singleton class for managing asset uploads to the sim. +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#ifndef LL_COPROCEDURE_MANAGER_H +#define LL_COPROCEDURE_MANAGER_H + +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h" +#include "lluuid.h" + +class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager > +{ +public: +    typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t; + +    LLCoprocedureManager(); +    virtual ~LLCoprocedureManager(); + +    /// Places the coprocedure on the queue for processing.  +    ///  +    /// @param name Is used for debugging and should identify this coroutine. +    /// @param proc Is a bound function to be executed  +    ///  +    /// @return This method returns a UUID that can be used later to cancel execution. +    LLUUID enqueueCoprocedure(const std::string &name, CoProcedure_t proc); + +    /// Cancel a coprocedure. If the coprocedure is already being actively executed  +    /// this method calls cancelYieldingOperation() on the associated HttpAdapter +    /// If it has not yet been dequeued it is simply removed from the queue. +    void cancelCoprocedure(const LLUUID &id); + +    /// Requests a shutdown of the upload manager. Passing 'true' will perform  +    /// an immediate kill on the upload coroutine. +    void shutdown(bool hardShutdown = false); + +    /// Returns the number of coprocedures in the queue awaiting processing. +    /// +    inline size_t countPending() const +    { +        return mPendingCoprocs.size(); +    } + +    /// Returns the number of coprocedures actively being processed. +    /// +    inline size_t countActive() const +    { +        return mActiveCoprocs.size(); +    } + +    /// Returns the total number of coprocedures either queued or in active processing. +    /// +    inline size_t count() const +    { +        return countPending() + countActive(); +    } + +private: +    struct QueuedCoproc +    { +        typedef boost::shared_ptr<QueuedCoproc> ptr_t; + +        QueuedCoproc(const std::string &name, const LLUUID &id, CoProcedure_t proc): +            mName(name), +            mId(id), +            mProc(proc) +        {} + +        std::string mName; +        LLUUID mId; +        CoProcedure_t mProc; +    }; +     +    // we use a deque here rather than std::queue since we want to be able to  +    // iterate through the queue and potentially erase an entry from the middle. +    typedef std::deque<QueuedCoproc::ptr_t>  CoprocQueue_t;   +    typedef std::map<LLUUID, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> ActiveCoproc_t; + +    CoprocQueue_t   mPendingCoprocs; +    ActiveCoproc_t  mActiveCoprocs; +    bool            mShutdown; +    LLEventStream   mWakeupTrigger; + + +    typedef std::map<std::string, LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t> CoroAdapterMap_t; +    LLCore::HttpRequest::policy_t mHTTPPolicy; + +    CoroAdapterMap_t mCoroMapping; + +    void coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter); +}; + +#endif diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 78d619a315..884d1579e6 100755 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -29,7 +29,6 @@  #include "llestateinfomodel.h"  // libs -#include "llhttpclient.h"  #include "llregionflags.h"  #include "message.h" @@ -38,6 +37,8 @@  #include "llfloaterregioninfo.h" // for invoice id  #include "llviewerregion.h" +#include "llcorehttputil.h" +  LLEstateInfoModel::LLEstateInfoModel()  :	mID(0)  ,	mFlags(0) @@ -110,24 +111,6 @@ void LLEstateInfoModel::notifyCommit()  //== PRIVATE STUFF ============================================================ -class LLEstateChangeInfoResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLEstateChangeInfoResponder); -protected: -	// if we get a normal response, handle it here -	virtual void httpSuccesss() -	{ -		LL_INFOS() << "Committed estate info" << LL_ENDL; -		LLEstateInfoModel::instance().notifyCommit(); -	} - -	// if we get an error response -	virtual void httpFailure() -	{ -		LL_WARNS() << "Failed to commit estate info " << dumpResponse() << LL_ENDL; -	} -}; -  // tries to send estate info using a cap; returns true if it succeeded  bool LLEstateInfoModel::commitEstateInfoCaps()  { @@ -139,29 +122,53 @@ bool LLEstateInfoModel::commitEstateInfoCaps()  		return false;  	} -	LLSD body; -	body["estate_name"          ] = getName(); -	body["sun_hour"             ] = getSunHour(); +    LLCoros::instance().launch("LLEstateInfoModel::commitEstateInfoCapsCoro", +        boost::bind(&LLEstateInfoModel::commitEstateInfoCapsCoro, this, url)); -	body["is_sun_fixed"         ] = getUseFixedSun(); -	body["is_externally_visible"] = getIsExternallyVisible(); -	body["allow_direct_teleport"] = getAllowDirectTeleport(); -	body["deny_anonymous"       ] = getDenyAnonymous(); -	body["deny_age_unverified"  ] = getDenyAgeUnverified(); -	body["allow_voice_chat"     ] = getAllowVoiceChat(); - -	body["invoice"              ] = LLFloaterRegionInfo::getLastInvoice(); - -	LL_DEBUGS("Windlight Sync") << "Sending estate caps: " -		<< "is_sun_fixed = " << getUseFixedSun() -		<< ", sun_hour = " << getSunHour() << LL_ENDL; -	LL_DEBUGS() << body << LL_ENDL; - -	// we use a responder so that we can re-get the data after committing to the database -	LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder);      return true;  } +void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EstateChangeInfo", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD body; +    body["estate_name"] = getName(); +    body["sun_hour"] = getSunHour(); + +    body["is_sun_fixed"] = getUseFixedSun(); +    body["is_externally_visible"] = getIsExternallyVisible(); +    body["allow_direct_teleport"] = getAllowDirectTeleport(); +    body["deny_anonymous"] = getDenyAnonymous(); +    body["deny_age_unverified"] = getDenyAgeUnverified(); +    body["allow_voice_chat"] = getAllowVoiceChat(); + +    body["invoice"] = LLFloaterRegionInfo::getLastInvoice(); + +    LL_DEBUGS("Windlight Sync") << "Sending estate caps: " +        << "is_sun_fixed = " << getUseFixedSun() +        << ", sun_hour = " << getSunHour() << LL_ENDL; +    LL_DEBUGS() << body << LL_ENDL; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, body); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status) +    { +        LL_INFOS() << "Committed estate info" << LL_ENDL; +        LLEstateInfoModel::instance().notifyCommit(); +    } +    else +    { +        LL_WARNS() << "Failed to commit estate info " << LL_ENDL; +    } +} +  /* This is the old way of doing things, is deprecated, and should be     deleted when the dataserver model can be removed */  // key = "estatechangeinfo" diff --git a/indra/newview/llestateinfomodel.h b/indra/newview/llestateinfomodel.h index 538f2f7c75..fcfbd1ce7d 100755 --- a/indra/newview/llestateinfomodel.h +++ b/indra/newview/llestateinfomodel.h @@ -30,6 +30,8 @@  class LLMessageSystem;  #include "llsingleton.h" +#include "llcoros.h" +#include "lleventcoro.h"  /**   * Contains estate info, notifies interested parties of its changes. @@ -73,7 +75,6 @@ protected:  	friend class LLSingleton<LLEstateInfoModel>;  	friend class LLDispatchEstateUpdateInfo; -	friend class LLEstateChangeInfoResponder;  	LLEstateInfoModel(); @@ -99,6 +100,8 @@ private:  	update_signal_t mUpdateSignal; /// emitted when we receive update from sim  	update_signal_t mCommitSignal; /// emitted when our update gets applied to sim + +    void commitEstateInfoCapsCoro(std::string url);  };  inline bool LLEstateInfoModel::getFlag(U64 flag) const diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 4de6ad4d2f..0aad1d5ba9 100755 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -30,261 +30,248 @@  #include "llappviewer.h"  #include "llagent.h" -#include "llhttpclient.h" -#include "llhttpconstants.h"  #include "llsdserialize.h"  #include "lleventtimer.h"  #include "llviewerregion.h"  #include "message.h"  #include "lltrans.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +#include "lleventfilter.h" -namespace +namespace LLEventPolling  { -	// We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error. -	// This means we attempt to recover relatively quickly but back off giving more time to recover -	// until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts. -	const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout. -	const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout. -	const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules. - -	class LLEventPollResponder : public LLHTTPClient::Responder -	{ -		LOG_CLASS(LLEventPollResponder); -	public: -		 -		static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); -		void stop(); -		 -		void makeRequest(); - -		/* virtual */ void completedRaw(const LLChannelDescriptors& channels, -								  const LLIOPipe::buffer_ptr_t& buffer); - -	private: -		LLEventPollResponder(const std::string&	pollURL, const LLHost& sender); -		~LLEventPollResponder(); - -		 -		void handleMessage(const LLSD& content); - -		/* virtual */ void httpFailure(); -		/* virtual */ void httpSuccess(); - -	private: - -		bool	mDone; - -		std::string			mPollURL; -		std::string			mSender; -		 -		LLSD	mAcknowledge; -		 -		// these are only here for debugging so	we can see which poller	is which -		static int sCount; -		int	mCount; -		S32 mErrorCount; -	}; - -	class LLEventPollEventTimer : public LLEventTimer -	{ -		typedef LLPointer<LLEventPollResponder> EventPollResponderPtr; - -	public: -		LLEventPollEventTimer(F32 period, EventPollResponderPtr responder) -			: LLEventTimer(period), mResponder(responder) -		{ } - -		virtual BOOL tick() -		{ -			mResponder->makeRequest(); -			return TRUE;	// Causes this instance to be deleted. -		} - -	private: -		 -		EventPollResponderPtr mResponder; -	}; - -	//static -	LLHTTPClient::ResponderPtr LLEventPollResponder::start( -		const std::string& pollURL, const LLHost& sender) -	{ -		LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender); -		LL_INFOS()	<< "LLEventPollResponder::start <" << sCount << "> " -				<< pollURL << LL_ENDL; -		return result; -	} - -	void LLEventPollResponder::stop() -	{ -		LL_INFOS()	<< "LLEventPollResponder::stop	<" << mCount <<	"> " -				<< mPollURL	<< LL_ENDL; -		// there should	be a way to	stop a LLHTTPClient	request	in progress -		mDone =	true; -	} - -	int	LLEventPollResponder::sCount =	0; - -	LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender) -		: mDone(false), -		  mPollURL(pollURL), -		  mCount(++sCount), -		  mErrorCount(0) -	{ -		//extract host and port of simulator to set as sender -		LLViewerRegion *regionp = gAgent.getRegion(); -		if (!regionp) -		{ -			LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL; -		} -		mSender = sender.getIPandPort(); -		LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL; -		makeRequest(); -	} - -	LLEventPollResponder::~LLEventPollResponder() -	{ -		stop(); -		LL_DEBUGS() <<	"LLEventPollResponder::~Impl <" <<	mCount << "> " -				 <<	mPollURL <<	LL_ENDL; -	} - -	// virtual  -	void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels, -											const LLIOPipe::buffer_ptr_t& buffer) -	{ -		if (getStatus() == HTTP_BAD_GATEWAY) -		{ -			// These errors are not parsable as LLSD,  -			// which LLHTTPClient::Responder::completedRaw will try to do. -			httpCompleted(); -		} -		else -		{ -			LLHTTPClient::Responder::completedRaw(channels,buffer); -		} -	} - -	void LLEventPollResponder::makeRequest() -	{ -		LLSD request; -		request["ack"] = mAcknowledge; -		request["done"]	= mDone; -		 -		LL_DEBUGS() <<	"LLEventPollResponder::makeRequest	<" << mCount <<	"> ack = " -				 <<	LLSDXMLStreamer(mAcknowledge) << LL_ENDL; -		LLHTTPClient::post(mPollURL, request, this); -	} - -	void LLEventPollResponder::handleMessage(const	LLSD& content) -	{ -		std::string	msg_name	= content["message"]; -		LLSD message; -		message["sender"] = mSender; -		message["body"] = content["body"]; -		LLMessageSystem::dispatch(msg_name, message); -	} - -	//virtual -	void LLEventPollResponder::httpFailure() -	{ -		if (mDone) return; - -		// A HTTP_BAD_GATEWAY (502) error is our standard timeout response -		// we get this when there are no events. -		if ( getStatus() == HTTP_BAD_GATEWAY ) -		{ -			mErrorCount = 0; -			makeRequest(); -		} -		else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS) -		{ -			++mErrorCount; -			 -			// The 'tick' will return TRUE causing the timer to delete this. -			new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS -										+ mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC -									, this); - -			LL_WARNS() << dumpResponse() << LL_ENDL; -		} -		else -		{ -			LL_WARNS() << dumpResponse() -					   << " [count:" << mCount << "] " -					   << (mDone ? " -- done" : "") << LL_ENDL; -			stop(); - -			// At this point we have given up and the viewer will not receive HTTP messages from the simulator. -			// IMs, teleports, about land, selecing land, region crossing and more will all fail. -			// They are essentially disconnected from the region even though some things may still work. -			// Since things won't get better until they relog we force a disconnect now. - -			// *NOTE:Mani - The following condition check to see if this failing event poll -			// is attached to the Agent's main region. If so we disconnect the viewer. -			// Else... its a child region and we just leave the dead event poll stopped and  -			// continue running. -			if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender) -			{ -				LL_WARNS() << "Forcing disconnect due to stalled main region event poll."  << LL_ENDL; -				LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection")); -			} -		} -	} - -	//virtual -	void LLEventPollResponder::httpSuccess() -	{ -		LL_DEBUGS() <<	"LLEventPollResponder::result <" << mCount	<< ">" -				 <<	(mDone ? " -- done"	: "") << LL_ENDL; -		 -		if (mDone) return; - -		mErrorCount = 0; - -		const LLSD& content = getContent(); -		if (!content.isMap() || -			!content.get("events") || -			!content.get("id")) -		{ -			LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL; -			makeRequest(); -			return; -		} -		 -		mAcknowledge = content["id"]; -		LLSD events	= content["events"]; - -		if(mAcknowledge.isUndefined()) -		{ -			LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL; -		} -		 -		// was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG -		LL_DEBUGS()  << "LLEventPollResponder::httpSuccess <" <<	mCount << "> " << events.size() << "events (id " -					 <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; -		 -		LLSD::array_const_iterator i = events.beginArray(); -		LLSD::array_const_iterator end = events.endArray(); -		for	(; i !=	end; ++i) -		{ -			if (i->has("message")) -			{ -				handleMessage(*i); -			} -		} -		 -		makeRequest(); -	}	 +namespace Details +{ + +    class LLEventPollImpl +    { +    public: +        LLEventPollImpl(const LLHost &sender); + +        void start(const std::string &url); +        void stop(); + +    private: +        // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error. +        // This means we attempt to recover relatively quickly but back off giving more time to recover +        // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts. +        static const F32                EVENT_POLL_ERROR_RETRY_SECONDS; +        static const F32                EVENT_POLL_ERROR_RETRY_SECONDS_INC; +        static const S32                MAX_EVENT_POLL_HTTP_ERRORS; + +        void                            eventPollCoro(std::string url); + +        void                            handleMessage(const LLSD &content); + +        bool                            mDone; +        LLCore::HttpRequest::ptr_t      mHttpRequest; +        LLCore::HttpRequest::policy_t   mHttpPolicy; +        std::string                     mSenderIp; +        int                             mCounter; +        LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mAdapter; + +        static int                      sNextCounter; +    }; + + +    const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout. +    const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout. +    const S32 LLEventPollImpl::MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules. + +    int LLEventPollImpl::sNextCounter = 1; + + +    LLEventPollImpl::LLEventPollImpl(const LLHost &sender) : +        mDone(false), +        mHttpRequest(), +        mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +        mSenderIp(), +        mCounter(sNextCounter++) + +    { +        LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + +        mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest); +        mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_LONG_POLL); +        mSenderIp = sender.getIPandPort(); +    } + +    void LLEventPollImpl::handleMessage(const LLSD& content) +    { +        std::string	msg_name = content["message"]; +        LLSD message; +        message["sender"] = mSenderIp; +        message["body"] = content["body"]; +        LLMessageSystem::dispatch(msg_name, message); +    } + +    void LLEventPollImpl::start(const std::string &url) +    { +        if (!url.empty()) +        { +            std::string coroname = +                LLCoros::instance().launch("LLEventPollImpl::eventPollCoro", +                boost::bind(&LLEventPollImpl::eventPollCoro, this, url)); +            LL_INFOS("LLEventPollImpl") << coroname << " with  url '" << url << LL_ENDL; +        } +    } + +    void LLEventPollImpl::stop() +    { +        LL_INFOS() << "requesting stop for event poll coroutine <" << mCounter << ">" << LL_ENDL; +        mDone = true; + +        LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter = mAdapter.lock(); +        if (adapter) +        { +            // cancel the yielding operation if any. +            adapter->cancelYieldingOperation(); +        } +    } + +    void LLEventPollImpl::eventPollCoro(std::string url) +    { +        LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EventPoller", mHttpPolicy)); +        LLSD acknowledge; +        int errorCount = 0; +        int counter = mCounter; // saved on the stack for logging.  + +        LL_INFOS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL; + +        mAdapter = httpAdapter; + +        // continually poll for a server update until we've been flagged as  +        // finished  +        while (!mDone) +        { +            LLSD request; +            request["ack"] = acknowledge; +            request["done"] = mDone; + +//          LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> request = " +//              << LLSDXMLStreamer(request) << LL_ENDL; + +            LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> posting and yielding." << LL_ENDL; +            LLSD result = httpAdapter->postAndYield(mHttpRequest, url, request); + +//          LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = " +//              << LLSDXMLStreamer(result) << LL_ENDL; + +            LLSD httpResults = result["http_result"]; +            LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +            if (!status) +            { +                if (status == LLCore::HttpStatus(HTTP_BAD_GATEWAY)) +                {   // A HTTP_BAD_GATEWAY (502) error is our standard timeout response +                    // we get this when there are no events. +                    errorCount = 0; +                    continue; +                } +                else if ((status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_OP_CANCELED)) ||  +                        (status == LLCore::HttpStatus(HTTP_NOT_FOUND))) +                {   // Event polling for this server has been canceled.  In  +                    // some cases the server gets ahead of the viewer and will  +                    // return a 404 error (Not Found) before the cancel event +                    // comes back in the queue +                    LL_WARNS() << "Canceling coroutine" << LL_ENDL; +                    break; +                } +                LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code " +                    << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL; + +                if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS) +                {   // An unanticipated error has been received from our poll  +                    // request. Calculate a timeout and wait for it to expire(sleep) +                    // before trying again.  The sleep time is increased by 5 seconds +                    // for each consecutive error. +                    LLEventTimeout timeout; +                    ++errorCount; + +                    F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS +                        + errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC; + +                    LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry << +                        " seconds, error count is now " << errorCount << LL_ENDL; + +                    timeout.eventAfter(waitToRetry, LLSD()); +                    llcoro::waitForEventOn(timeout); +                     +                    if (mDone) +                        break; +                    LL_INFOS("LLEventPollImpl") << "<" << counter << "> About to retry request." << LL_ENDL; +                    continue; +                } +                else +                { +                    // At this point we have given up and the viewer will not receive HTTP messages from the simulator. +                    // IMs, teleports, about land, selecting land, region crossing and more will all fail. +                    // They are essentially disconnected from the region even though some things may still work. +                    // Since things won't get better until they relog we force a disconnect now. +                    mDone = true; + +                    // *NOTE:Mani - The following condition check to see if this failing event poll +                    // is attached to the Agent's main region. If so we disconnect the viewer. +                    // Else... its a child region and we just leave the dead event poll stopped and  +                    // continue running. +                    if (gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSenderIp) +                    { +                        LL_WARNS("LLEventPollImpl") << "< " << counter << "> Forcing disconnect due to stalled main region event poll." << LL_ENDL; +                        LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection")); +                    } +                    break; +                } +            } + +            errorCount = 0; + +            if (!result.isMap() || +                !result.get("events") || +                !result.get("id")) +            { +                LL_WARNS("LLEventPollImpl") << " <" << counter << "> received event poll with no events or id key: " << LLSDXMLStreamer(result) << LL_ENDL; +                continue; +            } + +            acknowledge = result["id"]; +            LLSD events = result["events"]; + +            if (acknowledge.isUndefined()) +            { +                LL_WARNS("LLEventPollImpl") << " id undefined" << LL_ENDL; +            } + +            // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG +            LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << LLSDXMLStreamer(acknowledge) << ")" << LL_ENDL; + +            LLSD::array_const_iterator i = events.beginArray(); +            LLSD::array_const_iterator end = events.endArray(); +            for (; i != end; ++i) +            { +                if (i->has("message")) +                { +                    handleMessage(*i); +                } +            } +        } +        LL_INFOS("LLEventPollImpl") << " <" << counter << "> Leaving coroutine." << LL_ENDL; +    } + +}  } -LLEventPoll::LLEventPoll(const std::string&	poll_url, const LLHost& sender) -	: mImpl(LLEventPollResponder::start(poll_url, sender)) -	{ } +LLEventPoll::LLEventPoll(const std::string&	poll_url, const LLHost& sender): +    mImpl() +{  +    mImpl = boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl> +            (new LLEventPolling::Details::LLEventPollImpl(sender)); +    mImpl->start(poll_url); +}  LLEventPoll::~LLEventPoll()  { -	LLHTTPClient::Responder* responderp = mImpl.get(); -	LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp); -	if (event_poll_responder) event_poll_responder->stop(); +    mImpl->stop(); +  } diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h index e8d98062aa..e32b4ed322 100755 --- a/indra/newview/lleventpoll.h +++ b/indra/newview/lleventpoll.h @@ -28,9 +28,23 @@  #define LL_LLEVENTPOLL_H  #include "llhttpclient.h" +#include "boost/move/unique_ptr.hpp" + +namespace boost +{ +    using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace. +}  class LLHost; +namespace LLEventPolling +{ +namespace Details +{ +    class LLEventPollImpl; +} +} +  class LLEventPoll  	///< implements the viewer side of server-to-viewer pushed events. @@ -40,11 +54,11 @@ public:  		///< Start polling the URL.  	virtual ~LLEventPoll(); -		///< will stop polling, cancelling any poll in progress. +		///< will stop polling, canceling any poll in progress.  private: -	LLHTTPClient::ResponderPtr mImpl; +    boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl>    mImpl;  }; diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp index 28319564e4..136e02953c 100755 --- a/indra/newview/llfacebookconnect.cpp +++ b/indra/newview/llfacebookconnect.cpp @@ -34,7 +34,6 @@  #include "llagent.h"  #include "llcallingcard.h"			// for LLAvatarTracker  #include "llcommandhandler.h" -#include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llurlaction.h"  #include "llimagepng.h" @@ -42,9 +41,11 @@  #include "lltrans.h"  #include "llevents.h"  #include "llviewerregion.h" +#include "llviewercontrol.h"  #include "llfloaterwebcontent.h"  #include "llfloaterreg.h" +#include "llcorehttputil.h"  boost::scoped_ptr<LLEventPump> LLFacebookConnect::sStateWatcher(new LLEventStream("FacebookConnectState"));  boost::scoped_ptr<LLEventPump> LLFacebookConnect::sInfoWatcher(new LLEventStream("FacebookConnectInfo")); @@ -67,6 +68,24 @@ void toast_user_for_facebook_success()      LLNotificationsUtil::add("FacebookConnect", args);  } +LLCore::HttpHeaders::ptr_t get_headers() +{ +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +    // The DebugSlshareLogTag mechanism is intended to trigger slshare-service +    // debug logging. slshare-service is coded to respond to an X-debug-tag +    // header by engaging debug logging for that request only. This way a +    // developer need not muck with the slshare-service image to engage debug +    // logging. Moreover, the value of X-debug-tag is embedded in each such +    // log line so the developer can quickly find the log lines pertinent to +    // THIS session. +    std::string logtag(gSavedSettings.getString("DebugSlshareLogTag")); +    if (! logtag.empty()) +    { +        httpHeaders->append("X-debug-tag", logtag); +    } +    return httpHeaders; +} +  ///////////////////////////////////////////////////////////////////////////////  //  class LLFacebookConnectHandler : public LLCommandHandler @@ -125,266 +144,354 @@ LLFacebookConnectHandler gFacebookConnectHandler;  ///////////////////////////////////////////////////////////////////////////////  // -class LLFacebookConnectResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookConnectCoro(std::string authCode, std::string authState)  { -	LOG_CLASS(LLFacebookConnectResponder); -public: -	 -    LLFacebookConnectResponder() +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    LLSD putData; +    if (!authCode.empty())      { -        LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); +        putData["code"] = authCode; +    } +    if (!authState.empty()) +    { +        putData["state"] = authState;      } -     -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); -	} -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() -							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -				LLFacebookConnect::instance().openFacebookWeb(location); -			} -		} -		else -		{ -			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; -			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); -			const LLSD& content = getContent(); -			log_facebook_connect_error("Connect", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); + +    LLSD result = httpAdapter->putAndYield(httpRequest, getFacebookConnectURL("/connection"), putData, httpOpts, get_headers()); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +    if (!status) +    { +        if (status == LLCore::HttpStatus(HTTP_FOUND)) +        { +            std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +            if (location.empty()) +            { +                LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; +            } +            else +            { +                openFacebookWeb(location); +            } +        } +    } +    else +    { +        LL_INFOS("FacebookConnect") << "Connect successful. " << LL_ENDL; +        setConnectionState(LLFacebookConnect::FB_CONNECTED); +    } + +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFacebookShareResponder : public LLHTTPClient::Responder +bool LLFacebookConnect::testShareStatus(LLSD &result)  { -	LOG_CLASS(LLFacebookShareResponder); -public: -     -	LLFacebookShareResponder() -	{ -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING); -	} +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); -	/* virtual */ void httpSuccess() -	{ -		toast_user_for_facebook_success(); -		LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL; -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); -	} +    if (status) +        return true; -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() -							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -				LLFacebookConnect::instance().openFacebookWeb(location); -			} -		} -		else if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LLFacebookConnect::instance().connectToFacebook(); -		} -		else -		{ -			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; -			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); -			const LLSD& content = getContent(); -			log_facebook_connect_error("Share", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openFacebookWeb(location); +        } +    } +    if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) +    { +        LL_DEBUGS("FacebookConnect") << "Not connected. " << LL_ENDL; +        connectToFacebook(); +    } +    else +    { +        LL_WARNS("FacebookConnect") << "HTTP Status error " << status.toString() << LL_ENDL; +        setConnectionState(LLFacebookConnect::FB_POST_FAILED); +        log_facebook_connect_error("Share", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    return false; +} -/////////////////////////////////////////////////////////////////////////////// -// -class LLFacebookDisconnectResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookShareCoro(std::string route, LLSD share)  { -	LOG_CLASS(LLFacebookDisconnectResponder); -public: -  -	LLFacebookDisconnectResponder() -	{ -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECTING); -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	void setUserDisconnected() -	{ -		// Clear data -		LLFacebookConnect::instance().clearInfo(); -		LLFacebookConnect::instance().clearContent(); -		//Notify state change -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); -	} +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; -		setUserDisconnected(); -	} +    setConnectionState(LLFacebookConnect::FB_POSTING); -	/* virtual */ void httpFailure() -	{ -		//User not found so already disconnected -		if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; -			setUserDisconnected(); -		} -		else -		{ -			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; -			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); -			const LLSD& content = getContent(); -			log_facebook_connect_error("Disconnect", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    LLSD result = httpAdapter->postAndYield(httpRequest, getFacebookConnectURL(route, true), share, httpOpts, get_headers()); + +    if (testShareStatus(result)) +    { +        toast_user_for_facebook_success(); +        LL_DEBUGS("FacebookConnect") << "Post successful. " << LL_ENDL; +        setConnectionState(LLFacebookConnect::FB_POSTED); +    } +} + +void LLFacebookConnect::facebookShareImageCoro(std::string route, LLPointer<LLImageFormatted> image, std::string caption) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpHeaders::ptr_t httpHeaders(get_headers()); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    std::string imageFormat; +    if (dynamic_cast<LLImagePNG*>(image.get())) +    { +        imageFormat = "png"; +    } +    else if (dynamic_cast<LLImageJPEG*>(image.get())) +    { +        imageFormat = "jpg"; +    } +    else +    { +        LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; +        return; +    } + +    // All this code is mostly copied from LLWebProfile::post() +    static const std::string boundary = "----------------------------0123abcdefab"; + +    std::string contentType = "multipart/form-data; boundary=" + boundary; +    httpHeaders->append("Content-Type", contentType.c_str()); + +    LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); //  +    LLCore::BufferArrayStream body(raw.get()); + +    // *NOTE: The order seems to matter. +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"caption\"\r\n\r\n" +        << caption << "\r\n"; + +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" +        << "Content-Type: image/" << imageFormat << "\r\n\r\n"; + +    // Insert the image data. +    // *FIX: Treating this as a string will probably screw it up ... +    U8* image_data = image->getData(); +    for (S32 i = 0; i < image->getDataSize(); ++i) +    { +        body << image_data[i]; +    } + +    body << "\r\n--" << boundary << "--\r\n"; + +    setConnectionState(LLFacebookConnect::FB_POSTING); + +    LLSD result = httpAdapter->postAndYield(httpRequest, getFacebookConnectURL(route, true), raw, httpOpts, httpHeaders); + +    if (testShareStatus(result)) +    { +        toast_user_for_facebook_success(); +        LL_DEBUGS("FacebookConnect") << "Post successful. " << LL_ENDL; +        setConnectionState(LLFacebookConnect::FB_POSTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFacebookConnectedResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookDisconnectCoro()  { -	LOG_CLASS(LLFacebookConnectedResponder); -public: -     -	LLFacebookConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    setConnectionState(LLFacebookConnect::FB_DISCONNECTING); +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->deleteAndYield(httpRequest, getFacebookConnectURL("/connection"), httpOpts, get_headers()); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +    if (!status && (status != LLCore::HttpStatus(HTTP_FOUND))) +    { +        LL_WARNS("FacebookConnect") << "Failed to disconnect:" << status.toTerseString() << LL_ENDL; +        setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); +        log_facebook_connect_error("Disconnect", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else      { -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); +        LL_DEBUGS("FacebookConnect") << "Facebook Disconnect successful. " << LL_ENDL; +        clearInfo(); +        clearContent(); +        //Notify state change +        setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);      } -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; -		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); -	} +} -	/* virtual */ void httpFailure() -	{ -		// show the facebook login page if not connected yet -		if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL; -			if (mAutoConnect) -			{ -				LLFacebookConnect::instance().connectToFacebook(); -			} -			else -			{ -				LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); -			} -		} -		else -		{ -			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; -			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); -			const LLSD& content = getContent(); -			log_facebook_connect_error("Connected", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -     -private: -	bool mAutoConnect; -}; +/////////////////////////////////////////////////////////////////////////////// +// +void LLFacebookConnect::facebookConnectedCheckCoro(bool autoConnect) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); + +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->getAndYield(httpRequest, getFacebookConnectURL("/connection", true), httpOpts, get_headers()); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        if ( status == LLCore::HttpStatus(HTTP_NOT_FOUND) ) +        { +            LL_DEBUGS("FacebookConnect") << "Not connected. " << LL_ENDL; +            if (autoConnect) +            { +                connectToFacebook(); +            } +            else +            { +                setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); +            } +        } +        else +        { +            LL_WARNS("FacebookConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; + +            setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); +            log_facebook_connect_error("Connected", status.getStatus(), status.toString(), +                result.get("error_code"), result.get("error_description")); +        } +    } +    else +    { +        LL_DEBUGS("FacebookConnect") << "Connect successful. " << LL_ENDL; +        setConnectionState(LLFacebookConnect::FB_CONNECTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFacebookInfoResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookConnectInfoCoro()  { -	LOG_CLASS(LLFacebookInfoResponder); -public: +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	/* virtual */ void httpSuccess() -	{ -		LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; -		LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL; -		LLFacebookConnect::instance().storeInfo(getContent()); -	} +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -				LLFacebookConnect::instance().openFacebookWeb(location); -			} -		} -		else -		{ -			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; -			const LLSD& content = getContent(); -			log_facebook_connect_error("Info", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    LLSD result = httpAdapter->getAndYield(httpRequest, getFacebookConnectURL("/info", true), httpOpts, get_headers()); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openFacebookWeb(location); +        } +    } +    else if (!status) +    { +        LL_WARNS("FacebookConnect") << "Facebook Info failed: " << status.toString() << LL_ENDL; +        log_facebook_connect_error("Info", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else +    { +        LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        storeInfo(result); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFacebookFriendsResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookConnectFriendsCoro()  { -	LOG_CLASS(LLFacebookFriendsResponder); -public: -     -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL; -		LLFacebookConnect::instance().storeContent(getContent()); -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() -							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -				LLFacebookConnect::instance().openFacebookWeb(location); -			} -		} -		else -		{ -			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; -			const LLSD& content = getContent(); -			log_facebook_connect_error("Friends", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->getAndYield(httpRequest, getFacebookConnectURL("/friends", true), httpOpts, get_headers()); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openFacebookWeb(location); +        } +    } +    else if (!status) +    { +        LL_WARNS("FacebookConnect") << "Facebook Friends failed: " << status.toString() << LL_ENDL; +        log_facebook_connect_error("Info", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else +    { +        LL_INFOS("FacebookConnect") << "Facebook: Friends received" << LL_ENDL; +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        LLSD content = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; +        storeContent(content); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // @@ -439,40 +546,28 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b  void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state)  { -	LLSD body; -	if (!auth_code.empty()) -    { -		body["code"] = auth_code; -    } -	if (!auth_state.empty()) -    { -		body["state"] = auth_state; -    } -     -	LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder()); +    LLCoros::instance().launch("LLFacebookConnect::facebookConnectCoro", +        boost::bind(&LLFacebookConnect::facebookConnectCoro, this, auth_code, auth_state));  }  void LLFacebookConnect::disconnectFromFacebook()  { -	LLHTTPClient::del(getFacebookConnectURL("/connection"), new LLFacebookDisconnectResponder()); +    LLCoros::instance().launch("LLFacebookConnect::facebookDisconnectCoro", +        boost::bind(&LLFacebookConnect::facebookDisconnectCoro, this));  }  void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect)  { -	const bool follow_redirects = false; -	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -	LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect), -						LLSD(), timeout, follow_redirects); +    LLCoros::instance().launch("LLFacebookConnect::facebookConnectedCheckCoro", +        boost::bind(&LLFacebookConnect::facebookConnectedCheckCoro, this, auto_connect));  }  void LLFacebookConnect::loadFacebookInfo()  {  	if(mRefreshInfo)  	{ -		const bool follow_redirects = false; -		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -		LLHTTPClient::get(getFacebookConnectURL("/info", true), new LLFacebookInfoResponder(), -			LLSD(), timeout, follow_redirects); +        LLCoros::instance().launch("LLFacebookConnect::facebookConnectInfoCoro", +            boost::bind(&LLFacebookConnect::facebookConnectInfoCoro, this));  	}  } @@ -480,14 +575,13 @@ void LLFacebookConnect::loadFacebookFriends()  {  	if(mRefreshContent)  	{ -		const bool follow_redirects = false; -		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -		LLHTTPClient::get(getFacebookConnectURL("/friends", true), new LLFacebookFriendsResponder(), -			LLSD(), timeout, follow_redirects); +        LLCoros::instance().launch("LLFacebookConnect::facebookConnectFriendsCoro", +            boost::bind(&LLFacebookConnect::facebookConnectFriendsCoro, this));  	}  } -void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& image, const std::string& message) +void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name,  +    const std::string& description, const std::string& image, const std::string& message)  {  	LLSD body;  	if (!location.empty()) @@ -511,80 +605,34 @@ void LLFacebookConnect::postCheckin(const std::string& location, const std::stri  		body["message"] = message;      } -	// Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder()); +    LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro", +        boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/checkin", body));  }  void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::string& caption)  { +    // *TODO: I could not find an instace where this method is used.  Remove?  	LLSD body;  	body["image"] = image_url;  	body["caption"] = caption; -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::post(getFacebookConnectURL("/share/photo", true), body, new LLFacebookShareResponder()); +    LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro", +        boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/photo", body));  }  void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption)  { -	std::string imageFormat; -	if (dynamic_cast<LLImagePNG*>(image.get())) -	{ -		imageFormat = "png"; -	} -	else if (dynamic_cast<LLImageJPEG*>(image.get())) -	{ -		imageFormat = "jpg"; -	} -	else -	{ -		LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; -		return; -	} -	 -	// All this code is mostly copied from LLWebProfile::post() -	const std::string boundary = "----------------------------0123abcdefab"; - -	LLSD headers; -	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; - -	std::ostringstream body; - -	// *NOTE: The order seems to matter. -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"caption\"\r\n\r\n" -			<< caption << "\r\n"; - -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" -			<< "Content-Type: image/" << imageFormat << "\r\n\r\n"; - -	// Insert the image data. -	// *FIX: Treating this as a string will probably screw it up ... -	U8* image_data = image->getData(); -	for (S32 i = 0; i < image->getDataSize(); ++i) -	{ -		body << image_data[i]; -	} - -	body <<	"\r\n--" << boundary << "--\r\n"; - -	// postRaw() takes ownership of the buffer and releases it later. -	size_t size = body.str().size(); -	U8 *data = new U8[size]; -	memcpy(data, body.str().data(), size); -	 -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::postRaw(getFacebookConnectURL("/share/photo", true), data, size, new LLFacebookShareResponder(), headers); +    LLCoros::instance().launch("LLFacebookConnect::facebookShareImageCoro", +        boost::bind(&LLFacebookConnect::facebookShareImageCoro, this, "/share/photo", image, caption));  }  void LLFacebookConnect::updateStatus(const std::string& message)  {  	LLSD body;  	body["message"] = message; -	 -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::post(getFacebookConnectURL("/share/wall", true), body, new LLFacebookShareResponder()); + +    LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro", +        boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/wall", body));  }  void LLFacebookConnect::storeInfo(const LLSD& info) diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h index c157db2178..2a2cdb5499 100644 --- a/indra/newview/llfacebookconnect.h +++ b/indra/newview/llfacebookconnect.h @@ -30,6 +30,8 @@  #include "llsingleton.h"  #include "llimage.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLEventPump; @@ -101,6 +103,15 @@ private:  	static boost::scoped_ptr<LLEventPump> sStateWatcher;  	static boost::scoped_ptr<LLEventPump> sInfoWatcher;  	static boost::scoped_ptr<LLEventPump> sContentWatcher; + +    bool testShareStatus(LLSD &results); +    void facebookConnectCoro(std::string authCode, std::string authState); +    void facebookConnectedCheckCoro(bool autoConnect); +    void facebookDisconnectCoro(); +    void facebookShareCoro(std::string route, LLSD share); +    void facebookShareImageCoro(std::string route, LLPointer<LLImageFormatted> image, std::string caption); +    void facebookConnectInfoCoro(); +    void facebookConnectFriendsCoro();  };  #endif // LL_LLFACEBOOKCONNECT_H diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index ea39f812fd..0b76ca16a9 100755 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -40,7 +40,6 @@  #include "llappviewer.h"  #include "llbufferstream.h" -#include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llviewercontrol.h"  #include "llworld.h" @@ -55,6 +54,7 @@  #include "llviewershadermgr.h"  #include "llstring.h"  #include "stringize.h" +#include "llcorehttputil.h"  #if LL_WINDOWS  #include "lldxhardware.h" @@ -492,95 +492,70 @@ bool LLFeatureManager::loadGPUClass()  	return true; // indicates that a gpu value was established  } -	 -// responder saves table into file -class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder +void LLFeatureManager::fetchFeatureTableCoro(std::string tableName)  { -	LOG_CLASS(LLHTTPFeatureTableResponder); -public: +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FeatureManagerHTTPTable", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -	LLHTTPFeatureTableResponder(std::string filename) : -		mFilename(filename) -	{ -	} +    const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); -	 -	virtual void completedRaw(const LLChannelDescriptors& channels, -							  const LLIOPipe::buffer_ptr_t& buffer) -	{ -		if (isGoodStatus()) -		{ -			// write to file - -			LL_INFOS() << "writing feature table to " << mFilename << LL_ENDL; -			 -			S32 file_size = buffer->countAfter(channels.in(), NULL); -			if (file_size > 0) -			{ -				// read from buffer -				U8* copy_buffer = new U8[file_size]; -				buffer->readAfter(channels.in(), NULL, copy_buffer, file_size); - -				// write to file -				LLAPRFile out(mFilename, LL_APR_WB); -				out.write(copy_buffer, file_size); -				out.close(); -			} -		} -		else -		{ -			char body[1025];  -			body[1024] = '\0'; -			LLBufferStream istr(channels, buffer.get()); -			istr.get(body,1024); -			if (strlen(body) > 0) -			{ -				mContent["body"] = body; -			} -			LL_WARNS() << dumpResponse() << LL_ENDL; -		} -	} -	 -private: -	std::string mFilename; -}; - -void fetch_feature_table(std::string table) -{ -	const std::string base       = gSavedSettings.getString("FeatureManagerHTTPTable");  #if LL_WINDOWS -	std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); -	std::string filename; -	if (os_string.find("Microsoft Windows XP") == 0) -	{ -		filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); -	} -	else -	{ -		filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str()); -	} +    std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); +    std::string filename; + +    if (os_string.find("Microsoft Windows XP") == 0) +    { +        filename = llformat(tableName.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); +    } +    else +    { +        filename = llformat(tableName.c_str(), "", LLVersionInfo::getVersion().c_str()); +    }  #else -	const std::string filename   = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); +    const std::string filename   = llformat(tableName.c_str(), LLVersionInfo::getVersion().c_str());  #endif -	const std::string url        = base + "/" + filename; +    std::string url        = base + "/" + filename; +    // testing url below +    //url = "http://viewer-settings.secondlife.com/featuretable.2.1.1.208406.txt"; +    const std::string path       = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); -	const std::string path       = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); -	LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL; -	 -	LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); -} +    LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL; + +    LLSD result = httpAdapter->getRawAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status) +    {   // There was a newer feature table on the server. We've grabbed it and now should write it. +        // write to file +        const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); +        LL_INFOS() << "writing feature table to " << filename << LL_ENDL; + +        S32 size = raw.size(); +        if (size > 0) +        { +            // write to file +            LLAPRFile out(filename, LL_APR_WB); +            out.write(raw.data(), size); +            out.close(); +        } +    } +}  // fetch table(s) from a website (S3)  void LLFeatureManager::fetchHTTPTables()  { -	fetch_feature_table(FEATURE_TABLE_VER_FILENAME); +    LLCoros::instance().launch("LLFeatureManager::fetchFeatureTableCoro", +        boost::bind(&LLFeatureManager::fetchFeatureTableCoro, this, FEATURE_TABLE_VER_FILENAME));  } -  void LLFeatureManager::cleanupFeatureTables()  {  	std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index 69078ccc21..12ea691b49 100755 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -32,6 +32,8 @@  #include "llsingleton.h"  #include "llstring.h"  #include <map> +#include "llcoros.h" +#include "lleventcoro.h"  typedef enum EGPUClass  { @@ -164,6 +166,7 @@ protected:  	void initBaseMask(); +    void fetchFeatureTableCoro(std::string name);  	std::map<std::string, LLFeatureList *> mMaskList;  	std::set<std::string> mSkippedFeatures; diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp index b75660ea00..83e4f19191 100644 --- a/indra/newview/llflickrconnect.cpp +++ b/indra/newview/llflickrconnect.cpp @@ -32,7 +32,6 @@  #include "llagent.h"  #include "llcallingcard.h"			// for LLAvatarTracker  #include "llcommandhandler.h" -#include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llurlaction.h"  #include "llimagepng.h" @@ -43,6 +42,7 @@  #include "llfloaterwebcontent.h"  #include "llfloaterreg.h" +#include "llcorehttputil.h"  boost::scoped_ptr<LLEventPump> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState"));  boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo")); @@ -67,228 +67,324 @@ void toast_user_for_flickr_success()  ///////////////////////////////////////////////////////////////////////////////  // -class LLFlickrConnectResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrConnectCoro(std::string requestToken, std::string oauthVerifier)  { -	LOG_CLASS(LLFlickrConnectResponder); -public: -	 -    LLFlickrConnectResponder() +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    LLSD body; +    if (!requestToken.empty()) +        body["request_token"] = requestToken; +    if (!oauthVerifier.empty()) +        body["oauth_verifier"] = oauthVerifier; + +    setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); + +    LLSD result = httpAdapter->putAndYield(httpRequest, getFlickrConnectURL("/connection"), body, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        if ( status == LLCore::HttpStatus(HTTP_FOUND) ) +        { +            std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +            if (location.empty()) +            { +                LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; +            } +            else +            { +                openFlickrWeb(location); +            } +        } +        else +        { +            LL_WARNS("FlickrConnect") << "Connection failed " << status.toString() << LL_ENDL; +            setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); +            log_flickr_connect_error("Connect", status.getStatus(), status.toString(), +                result.get("error_code"), result.get("error_description")); +        } +    } +    else      { -        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); +        LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL; +        setConnectionState(LLFlickrConnect::FLICKR_CONNECTED);      } -     -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; -        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); -	} -     -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -                LLFlickrConnect::instance().openFlickrWeb(location); -			} -		} -		else -		{ -			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; -            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); -			const LLSD& content = getContent(); -			log_flickr_connect_error("Connect", getStatus(), getReason(), -                                      content.get("error_code"), content.get("error_description")); -		} -	} -}; +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFlickrShareResponder : public LLHTTPClient::Responder +bool LLFlickrConnect::testShareStatus(LLSD &result)  { -	LOG_CLASS(LLFlickrShareResponder); -public: -     -	LLFlickrShareResponder() -	{ -		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTING); -	} -	 -	/* virtual */ void httpSuccess() -	{ +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status) +        return true; + +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openFlickrWeb(location); +        } +    } +    if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) +    { +        LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL; +        connectToFlickr(); +    } +    else +    { +        LL_WARNS("FlickrConnect") << "HTTP Status error " << status.toString() << LL_ENDL; +        setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED); +        log_flickr_connect_error("Share", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    return false; +} + +void LLFlickrConnect::flickrShareCoro(LLSD share) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    setConnectionState(LLFlickrConnect::FLICKR_POSTING); + +    LLSD result = httpAdapter->postAndYield(httpRequest, getFlickrConnectURL("/share/photo", true), share, httpOpts); + +    if (testShareStatus(result)) +    {          toast_user_for_flickr_success(); -		LL_DEBUGS("FlickrConnect") << "Post successful. " << dumpResponse() << LL_ENDL; -        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTED); -	} -     -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -                LLFlickrConnect::instance().openFlickrWeb(location); -			} -		} -		else if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LLFlickrConnect::instance().connectToFlickr(); -		} -		else -		{ -			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; -            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED); -			const LLSD& content = getContent(); -			log_flickr_connect_error("Share", getStatus(), getReason(), -                                      content.get("error_code"), content.get("error_description")); -		} -	} -}; +        LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL; +        setConnectionState(LLFlickrConnect::FLICKR_POSTED); +    } + +} + +void LLFlickrConnect::flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    std::string imageFormat; +    if (dynamic_cast<LLImagePNG*>(image.get())) +    { +        imageFormat = "png"; +    } +    else if (dynamic_cast<LLImageJPEG*>(image.get())) +    { +        imageFormat = "jpg"; +    } +    else +    { +        LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; +        return; +    } + +    // All this code is mostly copied from LLWebProfile::post() +    const std::string boundary = "----------------------------0123abcdefab"; + +    std::string contentType = "multipart/form-data; boundary=" + boundary; +    httpHeaders->append("Content-Type", contentType.c_str()); + +    LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); //  +    LLCore::BufferArrayStream body(raw.get()); + +    // *NOTE: The order seems to matter. +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"title\"\r\n\r\n" +        << title << "\r\n"; + +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"description\"\r\n\r\n" +        << description << "\r\n"; + +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" +        << tags << "\r\n"; + +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n" +        << safetyLevel << "\r\n"; + +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" +        << "Content-Type: image/" << imageFormat << "\r\n\r\n"; + +    // Insert the image data. +    // *FIX: Treating this as a string will probably screw it up ... +    U8* image_data = image->getData(); +    for (S32 i = 0; i < image->getDataSize(); ++i) +    { +        body << image_data[i]; +    } + +    body << "\r\n--" << boundary << "--\r\n"; + +    LLSD result = httpAdapter->postAndYield(httpRequest, getFlickrConnectURL("/share/photo", true), raw, httpOpts, httpHeaders); + +    if (testShareStatus(result)) +    { +        toast_user_for_flickr_success(); +        LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL; +        setConnectionState(LLFlickrConnect::FLICKR_POSTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFlickrDisconnectResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrDisconnectCoro()  { -	LOG_CLASS(LLFlickrDisconnectResponder); -public: -  -	LLFlickrDisconnectResponder() -	{ -		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING); -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	void setUserDisconnected() -	{ -		// Clear data -		LLFlickrConnect::instance().clearInfo(); +    setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING); +    httpOpts->setFollowRedirects(false); -		//Notify state change -		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); -	} +    LLSD result = httpAdapter->deleteAndYield(httpRequest, getFlickrConnectURL("/connection"), httpOpts); -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; -		setUserDisconnected(); -	} -     -	/* virtual */ void httpFailure() -	{ -		//User not found so already disconnected -		if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LL_DEBUGS("FlickrConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; -			setUserDisconnected(); -		} -		else -		{ -			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; -			LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED); -			const LLSD& content = getContent(); -			log_flickr_connect_error("Disconnect", getStatus(), getReason(), -                                      content.get("error_code"), content.get("error_description")); -		} -	} -}; +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND))) +    { +        LL_WARNS("FlickrConnect") << "Disconnect failed!" << LL_ENDL; +        setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED); + +        log_flickr_connect_error("Disconnect", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else +    { +        LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << LL_ENDL; +        clearInfo(); +        setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFlickrConnectedResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrConnectedCoro(bool autoConnect)  { -	LOG_CLASS(LLFlickrConnectedResponder); -public: -     -	LLFlickrConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); + +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->getAndYield(httpRequest, getFlickrConnectURL("/connection", true), httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status)      { -		LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); +        if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) +        { +            LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL; +            if (autoConnect) +            { +                connectToFlickr(); +            } +            else +            { +                setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); +            } +        } +        else +        { +            LL_WARNS("FlickrConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; + +            setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); +            log_flickr_connect_error("Connected", status.getStatus(), status.toString(), +                result.get("error_code"), result.get("error_description")); +        }      } -     -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; -        LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); -	} -     -	/* virtual */ void httpFailure() -	{ -		// show the facebook login page if not connected yet -		if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LL_DEBUGS("FlickrConnect") << "Not connected. " << dumpResponse() << LL_ENDL; -			if (mAutoConnect) -			{ -                LLFlickrConnect::instance().connectToFlickr(); -			} -			else -			{ -                LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); -			} -		} -		else -		{ -			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; -            LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); -			const LLSD& content = getContent(); -			log_flickr_connect_error("Connected", getStatus(), getReason(), -                                      content.get("error_code"), content.get("error_description")); -		} -	} -     -private: -	bool mAutoConnect; -}; +    else +    { +        LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL; +        setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); +    } + +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLFlickrInfoResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrInfoCoro()  { -	LOG_CLASS(LLFlickrInfoResponder); -public: +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	/* virtual */ void httpSuccess() -	{ -		LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL; -		LL_DEBUGS("FlickrConnect") << "Getting Flickr info successful. " << dumpResponse() << LL_ENDL; -        LLFlickrConnect::instance().storeInfo(getContent()); -	} -     -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -                LLFlickrConnect::instance().openFlickrWeb(location); -			} -		} -		else -		{ -			LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; -			const LLSD& content = getContent(); -			log_flickr_connect_error("Info", getStatus(), getReason(), -                                      content.get("error_code"), content.get("error_description")); -		} -	} -}; +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->getAndYield(httpRequest, getFlickrConnectURL("/info", true), httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openFlickrWeb(location); +        } +    } +    else if (!status) +    { +        LL_WARNS("FlickrConnect") << "Flickr Info failed: " << status.toString() << LL_ENDL; +        log_flickr_connect_error("Info", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else +    { +        LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL; +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        storeInfo(result); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // @@ -341,36 +437,28 @@ std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool  void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier)  { -	LLSD body; -	if (!request_token.empty()) -		body["request_token"] = request_token; -	if (!oauth_verifier.empty()) -		body["oauth_verifier"] = oauth_verifier; -     -	LLHTTPClient::put(getFlickrConnectURL("/connection"), body, new LLFlickrConnectResponder()); +    LLCoros::instance().launch("LLFlickrConnect::flickrConnectCoro", +        boost::bind(&LLFlickrConnect::flickrConnectCoro, this, request_token, oauth_verifier));  }  void LLFlickrConnect::disconnectFromFlickr()  { -	LLHTTPClient::del(getFlickrConnectURL("/connection"), new LLFlickrDisconnectResponder()); +    LLCoros::instance().launch("LLFlickrConnect::flickrDisconnectCoro", +        boost::bind(&LLFlickrConnect::flickrDisconnectCoro, this));  }  void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect)  { -	const bool follow_redirects = false; -	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -	LLHTTPClient::get(getFlickrConnectURL("/connection", true), new LLFlickrConnectedResponder(auto_connect), -						LLSD(), timeout, follow_redirects); +    LLCoros::instance().launch("LLFlickrConnect::flickrConnectedCoro", +        boost::bind(&LLFlickrConnect::flickrConnectedCoro, this, auto_connect));  }  void LLFlickrConnect::loadFlickrInfo()  {  	if(mRefreshInfo)  	{ -		const bool follow_redirects = false; -		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -		LLHTTPClient::get(getFlickrConnectURL("/info", true), new LLFlickrInfoResponder(), -			LLSD(), timeout, follow_redirects); +        LLCoros::instance().launch("LLFlickrConnect::flickrInfoCoro", +            boost::bind(&LLFlickrConnect::flickrInfoCoro, this));  	}  } @@ -382,74 +470,17 @@ void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::strin  	body["description"] = description;  	body["tags"] = tags;  	body["safety_level"] = safety_level; -	 -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::post(getFlickrConnectURL("/share/photo", true), body, new LLFlickrShareResponder()); + +    LLCoros::instance().launch("LLFlickrConnect::flickrShareCoro", +        boost::bind(&LLFlickrConnect::flickrShareCoro, this, body));  }  void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level)  { -	std::string imageFormat; -	if (dynamic_cast<LLImagePNG*>(image.get())) -	{ -		imageFormat = "png"; -	} -	else if (dynamic_cast<LLImageJPEG*>(image.get())) -	{ -		imageFormat = "jpg"; -	} -	else -	{ -		LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; -		return; -	} -	 -	// All this code is mostly copied from LLWebProfile::post() -	const std::string boundary = "----------------------------0123abcdefab"; - -	LLSD headers; -	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; - -	std::ostringstream body; - -	// *NOTE: The order seems to matter. -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"title\"\r\n\r\n" -			<< title << "\r\n"; - -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"description\"\r\n\r\n" -			<< description << "\r\n"; - -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" -			<< tags << "\r\n"; - -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n" -			<< safety_level << "\r\n"; - -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" -			<< "Content-Type: image/" << imageFormat << "\r\n\r\n"; - -	// Insert the image data. -	// *FIX: Treating this as a string will probably screw it up ... -	U8* image_data = image->getData(); -	for (S32 i = 0; i < image->getDataSize(); ++i) -	{ -		body << image_data[i]; -	} - -	body <<	"\r\n--" << boundary << "--\r\n"; -	// postRaw() takes ownership of the buffer and releases it later. -	size_t size = body.str().size(); -	U8 *data = new U8[size]; -	memcpy(data, body.str().data(), size); -	 -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::postRaw(getFlickrConnectURL("/share/photo", true), data, size, new LLFlickrShareResponder(), headers); +    LLCoros::instance().launch("LLFlickrConnect::flickrShareImageCoro", +        boost::bind(&LLFlickrConnect::flickrShareImageCoro, this, image,  +        title, description, tags, safety_level));  }  void LLFlickrConnect::storeInfo(const LLSD& info) diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h index b127e6e104..0155804da0 100644 --- a/indra/newview/llflickrconnect.h +++ b/indra/newview/llflickrconnect.h @@ -30,6 +30,8 @@  #include "llsingleton.h"  #include "llimage.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLEventPump; @@ -93,6 +95,15 @@ private:  	static boost::scoped_ptr<LLEventPump> sStateWatcher;  	static boost::scoped_ptr<LLEventPump> sInfoWatcher;  	static boost::scoped_ptr<LLEventPump> sContentWatcher; + +    bool testShareStatus(LLSD &result); +    void flickrConnectCoro(std::string requestToken, std::string oauthVerifier); +    void flickrShareCoro(LLSD share); +    void flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel); +    void flickrDisconnectCoro(); +    void flickrConnectedCoro(bool autoConnect); +    void flickrInfoCoro(); +  };  #endif // LL_LLFLICKRCONNECT_H diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index b342d8fdf3..f58a5881a8 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -61,6 +61,7 @@  #include "stringize.h"  #include "llsdutil_math.h"  #include "lleventapi.h" +#include "llcorehttputil.h"  #if LL_WINDOWS  #include "lldxhardware.h" @@ -70,18 +71,6 @@ extern LLMemoryInfo gSysMemory;  extern U32 gPacketsIn;  ///---------------------------------------------------------------------------- -/// Class LLServerReleaseNotesURLFetcher -///---------------------------------------------------------------------------- -class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLServerReleaseNotesURLFetcher); -public: -	static void startFetch(); -private: -	/* virtual */ void httpCompleted(); -}; - -///----------------------------------------------------------------------------  /// Class LLFloaterAbout  ///----------------------------------------------------------------------------  class LLFloaterAbout  @@ -102,6 +91,9 @@ public:  private:  	void setSupportText(const std::string& server_release_notes_url); + +    static void startFetchServerReleaseNotes(); +    static void handleServerReleaseNotes(LLSD results);  }; @@ -138,7 +130,7 @@ BOOL LLFloaterAbout::postBuild()  	{  		// start fetching server release notes URL  		setSupportText(LLTrans::getString("RetrievingData")); -		LLServerReleaseNotesURLFetcher::startFetch(); +        startFetchServerReleaseNotes();  	}  	else // not logged in  	{ @@ -201,6 +193,50 @@ LLSD LLFloaterAbout::getInfo()  	return LLAppViewer::instance()->getViewerInfo();  } +/*static*/ +void LLFloaterAbout::startFetchServerReleaseNotes() +{ +    LLViewerRegion* region = gAgent.getRegion(); +    if (!region) return; + +    // We cannot display the URL returned by the ServerReleaseNotes capability +    // because opening it in an external browser will trigger a warning about untrusted +    // SSL certificate. +    // So we query the URL ourselves, expecting to find +    // an URL suitable for external browsers in the "Location:" HTTP header. +    std::string cap_url = region->getCapability("ServerReleaseNotes"); + +    LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(cap_url, +        &LLFloaterAbout::handleServerReleaseNotes, &LLFloaterAbout::handleServerReleaseNotes); + +} + +/*static*/ +void LLFloaterAbout::handleServerReleaseNotes(LLSD results) +{ +    LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); +    if (floater_about) +    { +        LLSD http_headers; +        if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS)) +        { +            LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +            http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +        } +        else +        { +            http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +        } +         +        std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString(); +        if (location.empty()) +        { +            location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); +        } +        LLAppViewer::instance()->setServerReleaseNotesURL(location); +    } +} +  class LLFloaterAboutListener: public LLEventAPI  {  public: @@ -264,40 +300,3 @@ void LLFloaterAboutUtil::registerFloater()  		&LLFloaterReg::build<LLFloaterAbout>);  } - -///---------------------------------------------------------------------------- -/// Class LLServerReleaseNotesURLFetcher implementation -///---------------------------------------------------------------------------- -// static -void LLServerReleaseNotesURLFetcher::startFetch() -{ -	LLViewerRegion* region = gAgent.getRegion(); -	if (!region) return; - -	// We cannot display the URL returned by the ServerReleaseNotes capability -	// because opening it in an external browser will trigger a warning about untrusted -	// SSL certificate. -	// So we query the URL ourselves, expecting to find -	// an URL suitable for external browsers in the "Location:" HTTP header. -	std::string cap_url = region->getCapability("ServerReleaseNotes"); -	LLHTTPClient::get(cap_url, new LLServerReleaseNotesURLFetcher); -} - -// virtual -void LLServerReleaseNotesURLFetcher::httpCompleted() -{ -	LL_DEBUGS("ServerReleaseNotes") << dumpResponse()  -									<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - -	LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); -	if (floater_about) -	{ -		std::string location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -		if (location.empty()) -		{ -			location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); -		} -		LLAppViewer::instance()->setServerReleaseNotesURL(location); -	} -} - diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index b661fed276..56619e818a 100755 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -57,6 +57,7 @@  #include "llsdutil.h"  #include "llsdutil_math.h"  #include "lltrans.h" +#include "llcorehttputil.h"  ///----------------------------------------------------------------------------  /// Local function declarations, constants, enums, and typedefs @@ -361,7 +362,10 @@ void LLFloaterAuction::doResetParcel()  		LL_INFOS() << "Sending parcel update to reset for auction via capability to: "  			<< mParcelUpdateCapUrl << LL_ENDL; -		LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::Responder()); + +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(mParcelUpdateCapUrl, body, +            "Parcel reset for auction", +            "Parcel not set for auction.");  		// Send a message to clear the object return time  		LLMessageSystem *msg = gMessageSystem; @@ -490,7 +494,10 @@ void LLFloaterAuction::doSellToAnyone()  		LL_INFOS() << "Sending parcel update to sell to anyone for L$1 via capability to: "  			<< mParcelUpdateCapUrl << LL_ENDL; -		LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::Responder()); + +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(mParcelUpdateCapUrl, body, +            "Parcel set as sell to everyone.", +            "Parcel sell to everyone failed.");  		// clean up floater, and get out  		cleanupAndClose(); diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp index 6e56e929df..5830f2f711 100755 --- a/indra/newview/llfloaterautoreplacesettings.cpp +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -36,7 +36,6 @@  #include "llcolorswatch.h"  #include "llcombobox.h"  #include "llview.h" -#include "llhttpclient.h"  #include "llbufferstream.h"  #include "llcheckboxctrl.h"  #include "llviewercontrol.h" diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 566a3c9cd3..2824038f77 100755 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -42,7 +42,6 @@  #include "llavatarnamecache.h"	// IDEVO  #include "llbutton.h"  #include "llcachename.h" -#include "llhttpclient.h"		// IDEVO  #include "lllineeditor.h"  #include "llscrolllistctrl.h"  #include "llscrolllistitem.h" @@ -52,6 +51,7 @@  #include "llfocusmgr.h"  #include "lldraghandle.h"  #include "message.h" +#include "llcorehttputil.h"  //#include "llsdserialize.h" @@ -456,39 +456,33 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const  	return FALSE;  } -class LLAvatarPickerResponder : public LLHTTPClient::Responder +/*static*/ +void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::string name)  { -	LOG_CLASS(LLAvatarPickerResponder); -public: -	LLUUID mQueryID; -    std::string mName; +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -	LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { } +    LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; -protected: -	/*virtual*/ void httpCompleted() -	{ -		//std::ostringstream ss; -		//LLSDSerialize::toPrettyXML(content, ss); -		//LL_INFOS() << ss.str() << LL_ENDL; +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST))) +    { +        LLFloaterAvatarPicker* floater = +            LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name); +        if (floater) +        { +            result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +            floater->processResponse(queryID, result); +        } +    } +} -		// in case of invalid characters, the avatar picker returns a 400 -		// just set it to process so it displays 'not found' -		if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST) -		{ -			LLFloaterAvatarPicker* floater = -				LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName); -			if (floater) -			{ -				floater->processResponse(mQueryID, getContent()); -			} -		} -		else -		{ -			LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL; -		} -	} -};  void LLFloaterAvatarPicker::find()  { @@ -517,7 +511,9 @@ void LLFloaterAvatarPicker::find()  		std::replace(text.begin(), text.end(), '.', ' ');  		url += LLURI::escape(text);  		LL_INFOS() << "avatar picker " << url << LL_ENDL; -		LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID, getKey().asString())); + +        LLCoros::instance().launch("LLFloaterAvatarPicker::findCoro", +            boost::bind(&LLFloaterAvatarPicker::findCoro, url, mQueryID, getKey().asString()));  	}  	else  	{ diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index ed3e51c56f..fbee61b054 100755 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -28,6 +28,8 @@  #define LLFLOATERAVATARPICKER_H  #include "llfloater.h" +#include "lleventcoro.h" +#include "llcoros.h"  #include <vector> @@ -84,6 +86,7 @@ private:  	void populateFriend();  	BOOL visibleItemsSelected() const; // Returns true if any items in the current tab are selected. +    static void findCoro(std::string url, LLUUID mQueryID, std::string mName);  	void find();  	void setAllowMultiple(BOOL allow_multiple);  	LLScrollListCtrl* getActiveList(); diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 669ffa7c59..39b5a40efc 100755 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -992,20 +992,16 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata)  			{  				std::string name = floaterp->getChild<LLUICtrl>("name_form")->getValue().asString();  				std::string desc = floaterp->getChild<LLUICtrl>("description_form")->getValue().asString(); -				LLAssetStorage::LLStoreAssetCallback callback = NULL;  				S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); -				void *userdata = NULL; -				upload_new_resource(floaterp->mTransactionID, // tid -						    LLAssetType::AT_ANIMATION, -						    name, -						    desc, -						    0, -						    LLFolderType::FT_NONE, -						    LLInventoryType::IT_ANIMATION, -						    LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), -						    name, -						    callback, expected_upload_cost, userdata); +                NewResourceUploadInfo::ptr_t assetUpdloadInfo(new NewResourceUploadInfo( +                    floaterp->mTransactionID, LLAssetType::AT_ANIMATION, +                    name, desc, 0, +                    LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION, +                    LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), +                    expected_upload_cost)); + +                upload_new_resource(assetUpdloadInfo);  			}  			else  			{ diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp deleted file mode 100755 index 596e8c0dbe..0000000000 --- a/indra/newview/llfloaterdisplayname.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/**  - * @file llfloaterdisplayname.cpp - * @author Leyla Farazha - * @brief Implementation of the LLFloaterDisplayName class. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - - -#include "llviewerprecompiledheaders.h" -#include "llfloaterreg.h" -#include "llfloater.h" - -#include "llnotificationsutil.h" -#include "llviewerdisplayname.h" - -#include "llnotifications.h" -#include "llfloaterdisplayname.h" -#include "llavatarnamecache.h" - -#include "llagent.h" - - -class LLFloaterDisplayName : public LLFloater -{ -public: -	LLFloaterDisplayName(const LLSD& key); -	virtual ~LLFloaterDisplayName() { } -	/*virtual*/	BOOL	postBuild(); -	void onSave(); -	void onReset(); -	void onCancel(); -	/*virtual*/ void onOpen(const LLSD& key); -	 -private: -	 -	void onCacheSetName(bool success, -										  const std::string& reason, -										  const LLSD& content); -}; - -LLFloaterDisplayName::LLFloaterDisplayName(const LLSD& key) : -	LLFloater(key) -{ -} - -void LLFloaterDisplayName::onOpen(const LLSD& key) -{ -	getChild<LLUICtrl>("display_name_editor")->clear(); -	getChild<LLUICtrl>("display_name_confirm")->clear(); - -	LLAvatarName av_name; -	LLAvatarNameCache::get(gAgent.getID(), &av_name); - -	F64 now_secs = LLDate::now().secondsSinceEpoch(); - -	if (now_secs < av_name.mNextUpdate) -	{ -		// ...can't update until some time in the future -		F64 next_update_local_secs = -			av_name.mNextUpdate - LLStringOps::getLocalTimeOffset(); -		LLDate next_update_local(next_update_local_secs); -		// display as "July 18 12:17 PM" -		std::string next_update_string = -		next_update_local.toHTTPDateString("%B %d %I:%M %p"); -		getChild<LLUICtrl>("lockout_text")->setTextArg("[TIME]", next_update_string); -		getChild<LLUICtrl>("lockout_text")->setVisible(true); -		getChild<LLUICtrl>("save_btn")->setEnabled(false); -		getChild<LLUICtrl>("display_name_editor")->setEnabled(false); -		getChild<LLUICtrl>("display_name_confirm")->setEnabled(false); -		getChild<LLUICtrl>("cancel_btn")->setFocus(TRUE); -		 -	} -	else -	{ -		getChild<LLUICtrl>("lockout_text")->setVisible(false); -		getChild<LLUICtrl>("save_btn")->setEnabled(true); -		getChild<LLUICtrl>("display_name_editor")->setEnabled(true); -		getChild<LLUICtrl>("display_name_confirm")->setEnabled(true); - -	} -} - -BOOL LLFloaterDisplayName::postBuild() -{ -	getChild<LLUICtrl>("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this));	 -	getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this));	 -	getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this));	 -	 -	center(); - -	return TRUE; -} - -void LLFloaterDisplayName::onCacheSetName(bool success, -										  const std::string& reason, -										  const LLSD& content) -{ -	if (success) -	{ -		// Inform the user that the change took place, but will take a while -		// to percolate. -		LLSD args; -		args["DISPLAY_NAME"] = content["display_name"]; -		LLNotificationsUtil::add("SetDisplayNameSuccess", args); -		return; -	} - -	// Request failed, notify the user -	std::string error_tag = content["error_tag"].asString(); -	LL_INFOS() << "set name failure error_tag " << error_tag << LL_ENDL; - -	// We might have a localized string for this message -	// error_args will usually be empty from the server. -	if (!error_tag.empty() -		&& LLNotifications::getInstance()->templateExists(error_tag)) -	{ -		LLNotificationsUtil::add(error_tag); -		return; -	} - -	// The server error might have a localized message for us -	std::string lang_code = LLUI::getLanguage(); -	LLSD error_desc = content["error_description"]; -	if (error_desc.has( lang_code )) -	{ -		LLSD args; -		args["MESSAGE"] = error_desc[lang_code].asString(); -		LLNotificationsUtil::add("GenericAlert", args); -		return; -	} - -	// No specific error, throw a generic one -	LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); -} - -void LLFloaterDisplayName::onCancel() -{ -	setVisible(false); -} - -void LLFloaterDisplayName::onReset() -{ -	if (LLAvatarNameCache::hasNameLookupURL()) -	{ -		LLViewerDisplayName::set("",boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); -	}	 -	else -	{ -		LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); -	} -	 -	setVisible(false); -} - - -void LLFloaterDisplayName::onSave() -{ -	std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString(); -	std::string display_name_confirm = getChild<LLUICtrl>("display_name_confirm")->getValue().asString(); - -	if (display_name_utf8.compare(display_name_confirm)) -	{ -		LLNotificationsUtil::add("SetDisplayNameMismatch"); -		return; -	} - -	const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes -	LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8); -	if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH) -	{ -		LLSD args; -		args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH); -		LLNotificationsUtil::add("SetDisplayNameFailedLength", args); -		return; -	} -	 -	if (LLAvatarNameCache::hasNameLookupURL()) -	{ -		LLViewerDisplayName::set(display_name_utf8,boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3));	 -	} -	else -	{ -		LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); -	} - -	setVisible(false); -} - - -////////////////////////////////////////////////////////////////////////////// -// LLInspectObjectUtil -////////////////////////////////////////////////////////////////////////////// -void LLFloaterDisplayNameUtil::registerFloater() -{ -	LLFloaterReg::add("display_name", "floater_display_name.xml", -					  &LLFloaterReg::build<LLFloaterDisplayName>); -} diff --git a/indra/newview/llfloaterdisplayname.h b/indra/newview/llfloaterdisplayname.h deleted file mode 100755 index a00bf56712..0000000000 --- a/indra/newview/llfloaterdisplayname.h +++ /dev/null @@ -1,38 +0,0 @@ -/**  - * @file llfloaterdisplayname.h - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LLFLOATERDISPLAYNAME_H -#define LLFLOATERDISPLAYNAME_H - - -namespace LLFloaterDisplayNameUtil -{ -	// Register with LLFloaterReg -	void registerFloater(); -} - - - -#endif diff --git a/indra/newview/llfloaterhoverheight.cpp b/indra/newview/llfloaterhoverheight.cpp index 8908626de6..003a22fa04 100755 --- a/indra/newview/llfloaterhoverheight.cpp +++ b/indra/newview/llfloaterhoverheight.cpp @@ -31,7 +31,6 @@  #include "llsliderctrl.h"  #include "llviewercontrol.h"  #include "llsdserialize.h" -#include "llhttpclient.h"  #include "llagent.h"  #include "llviewerregion.h"  #include "llvoavatarself.h" diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index fc7fcf3ab9..6623ce0f80 100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -41,7 +41,6 @@  #include "llchicletbar.h"  #include "lldonotdisturbnotificationstorage.h"  #include "llfloaterreg.h" -#include "llhttpclient.h"  #include "llfloateravatarpicker.h"  #include "llfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container  #include "llinventoryfunctions.h" @@ -62,6 +61,7 @@  #include "llviewerchat.h"  #include "llnotificationmanager.h"  #include "llautoreplace.h" +#include "llcorehttputil.h"  const F32 ME_TYPING_TIMEOUT = 4.0f;  const F32 OTHER_TYPING_TIMEOUT = 9.0f; @@ -1178,26 +1178,6 @@ BOOL LLFloaterIMSession::isInviteAllowed() const  			 || mIsP2PChat);  } -class LLSessionInviteResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLSessionInviteResponder); -public: -	LLSessionInviteResponder(const LLUUID& session_id) -	{ -		mSessionID = session_id; -	} - -protected: -	void httpFailure() -	{ -		LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL; -		//throw something back to the viewer here? -	} - -private: -	LLUUID mSessionID; -}; -  BOOL LLFloaterIMSession::inviteToSession(const uuid_vec_t& ids)  {  	LLViewerRegion* region = gAgent.getRegion(); @@ -1221,7 +1201,9 @@ BOOL LLFloaterIMSession::inviteToSession(const uuid_vec_t& ids)  			}  			data["method"] = "invite";  			data["session-id"] = mSessionID; -			LLHTTPClient::post(url,	data,new LLSessionInviteResponder(mSessionID)); + +            LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, +                "Session invite sent", "Session invite failed");  		}  		else  		{ diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 22a8ac4705..e2f84fd990 100755 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -30,6 +30,7 @@  #include "llagent.h"  #include "llviewerregion.h"  #include "llnotificationsutil.h" +#include "llcorehttputil.h"  LLFloaterModelUploadBase::LLFloaterModelUploadBase(const LLSD& key)  :LLFloater(key), @@ -47,7 +48,8 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()  		LL_INFOS()<< typeid(*this).name()  				  << "::requestAgentUploadPermissions() requesting for upload model permissions from: "  				  << url << LL_ENDL; -		LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle())); +        LLCoros::instance().launch("LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro", +            boost::bind(&LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro, this, url, getPermObserverHandle()));  	}  	else  	{ @@ -58,3 +60,34 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()  		mHasUploadPerm = true;  	}  } + +void LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro(std::string url, +    LLHandle<LLUploadPermissionsObserver> observerHandle) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("MeshUploadFlag", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    LLUploadPermissionsObserver* observer = observerHandle.get(); + +    if (!observer) +    {  +        LL_WARNS("MeshUploadFlag") << "Unable to get observer after call to '" << url << "' aborting." << LL_ENDL; +    } + +    if (!status) +    { +        observer->setPermissonsErrorStatus(status.getStatus(), status.getMessage()); +        return; +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    observer->onPermissionsReceived(result); +} diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index d9a8879687..0d4c834122 100755 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -28,6 +28,8 @@  #define LL_LLFLOATERMODELUPLOADBASE_H  #include "lluploadfloaterobservers.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObserver, public LLWholeModelFeeObserver, public LLWholeModelUploadObserver  { @@ -54,6 +56,8 @@ protected:  	// requests agent's permissions to upload model  	void requestAgentUploadPermissions(); +    void requestAgentUploadPermissionsCoro(std::string url, LLHandle<LLUploadPermissionsObserver> observerHandle); +  	std::string mUploadModelUrl;  	bool mHasUploadPerm;  }; diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp index 0cca715fe2..4960ecf5fe 100755 --- a/indra/newview/llfloaternamedesc.cpp +++ b/indra/newview/llfloaternamedesc.cpp @@ -164,6 +164,19 @@ void LLFloaterNameDesc::onBtnOK( )  	void *nruserdata = NULL;  	std::string display_name = LLStringUtil::null; +    NewResourceUploadInfo::ptr_t uploadInfo(new NewFileResourceUploadInfo( +            mFilenameAndPath, +            getChild<LLUICtrl>("name_form")->getValue().asString(),  +            getChild<LLUICtrl>("description_form")->getValue().asString(), 0, +            LLFolderType::FT_NONE, LLInventoryType::IT_NONE, +            LLFloaterPerms::getNextOwnerPerms("Uploads"), +            LLFloaterPerms::getGroupPerms("Uploads"), +            LLFloaterPerms::getEveryonePerms("Uploads"), +            expected_upload_cost)); + +    upload_new_resource(uploadInfo, callback, nruserdata); + +#if 0  	upload_new_resource(mFilenameAndPath, // file  			    getChild<LLUICtrl>("name_form")->getValue().asString(),   			    getChild<LLUICtrl>("description_form")->getValue().asString(),  @@ -172,6 +185,8 @@ void LLFloaterNameDesc::onBtnOK( )  				LLFloaterPerms::getGroupPerms("Uploads"),  				LLFloaterPerms::getEveryonePerms("Uploads"),  			    display_name, callback, expected_upload_cost, nruserdata); +#endif +  	closeFloater(false);  } diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 042cf47070..16bb449fdb 100755 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -37,6 +37,7 @@  #include "llnotificationsutil.h"  #include "llsdserialize.h"  #include "llvoavatar.h" +#include "llcorehttputil.h"  LLFloaterPerms::LLFloaterPerms(const LLSD& seed)  : LLFloater(seed) @@ -166,41 +167,6 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data)  	xfer->setEnabled(copyable);  } -class LLFloaterPermsResponder : public LLHTTPClient::Responder -{ -public: -	LLFloaterPermsResponder(): LLHTTPClient::Responder() {} -private: -	static	std::string sPreviousReason; - -	void httpFailure() -	{ -		const std::string& reason = getReason(); -		// Do not display the same error more than once in a row -		if (reason != sPreviousReason) -		{ -			sPreviousReason = reason; -			LLSD args; -			args["REASON"] = reason; -			LLNotificationsUtil::add("DefaultObjectPermissions", args); -		} -	} - -	void httpSuccess() -	{ -		//const LLSD& content = getContent(); -		//dump_sequential_xml("perms_responder_result.xml", content); - -		// Since we have had a successful POST call be sure to display the next error message -		// even if it is the same as a previous one. -		sPreviousReason = ""; -		LLFloaterPermsDefault::setCapSent(true); -		LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; -	} -}; - -	std::string	LLFloaterPermsResponder::sPreviousReason; -  void LLFloaterPermsDefault::sendInitialPerms()  {  	if(!mCapSent) @@ -215,23 +181,8 @@ void LLFloaterPermsDefault::updateCap()  	if(!object_url.empty())  	{ -		LLSD report = LLSD::emptyMap(); -		report["default_object_perm_masks"]["Group"] = -			(LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]); -		report["default_object_perm_masks"]["Everyone"] = -			(LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]); -		report["default_object_perm_masks"]["NextOwner"] = -			(LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]); - -        { -            LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '" -                                                  << object_url << "'\n"; -            std::ostringstream sent_perms_log; -            LLSDSerialize::toPrettyXML(report, sent_perms_log); -            LL_CONT << sent_perms_log.str() << LL_ENDL; -        } -     -		LLHTTPClient::post(object_url, report, new LLFloaterPermsResponder()); +        LLCoros::instance().launch("LLFloaterPermsDefault::updateCapCoro", +            boost::bind(&LLFloaterPermsDefault::updateCapCoro, object_url));  	}      else      { @@ -239,6 +190,57 @@ void LLFloaterPermsDefault::updateCap()      }  } +/*static*/ +void LLFloaterPermsDefault::updateCapCoro(std::string url) +{ +    static std::string previousReason; +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD postData = LLSD::emptyMap(); +    postData["default_object_perm_masks"]["Group"] = +        (LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]); +    postData["default_object_perm_masks"]["Everyone"] = +        (LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]); +    postData["default_object_perm_masks"]["NextOwner"] = +        (LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]); + +    { +        LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '" +            << url << "'\n"; +        std::ostringstream sent_perms_log; +        LLSDSerialize::toPrettyXML(postData, sent_perms_log); +        LL_CONT << sent_perms_log.str() << LL_ENDL; +    } + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        const std::string& reason = status.toString(); +        // Do not display the same error more than once in a row +        if (reason != previousReason) +        { +            previousReason = reason; +            LLSD args; +            args["REASON"] = reason; +            LLNotificationsUtil::add("DefaultObjectPermissions", args); +        } +        return; +    } + +    // Since we have had a successful POST call be sure to display the next error message +    // even if it is the same as a previous one. +    previousReason.clear(); +    LLFloaterPermsDefault::setCapSent(true); +    LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; +} +  void LLFloaterPermsDefault::setCapSent(bool cap_sent)  {  	mCapSent = cap_sent; diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h index 2bb0a19dc1..e866b6de7d 100755 --- a/indra/newview/llfloaterperms.h +++ b/indra/newview/llfloaterperms.h @@ -29,6 +29,8 @@  #define LL_LLFLOATERPERMPREFS_H  #include "llfloater.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLFloaterPerms : public LLFloater  { @@ -80,6 +82,8 @@ private:  	void refresh();  	static const std::string sCategoryNames[CAT_LAST];  +    static void updateCapCoro(std::string url); +  	// cached values only for implementing cancel.  	bool mShareWithGroup[CAT_LAST]; diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 40757a4d04..271fb2f9a3 100755 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -30,11 +30,11 @@  #include "llfloaterregiondebugconsole.h"  #include "llagent.h" -#include "llhttpclient.h"  #include "llhttpnode.h"  #include "lllineeditor.h"  #include "lltexteditor.h"  #include "llviewerregion.h" +#include "llcorehttputil.h"  // Two versions of the sim console API are supported.  // @@ -68,58 +68,6 @@ namespace  	const std::string CONSOLE_NOT_SUPPORTED(  		"This region does not support the simulator console."); -	// This responder handles the initial response. Unless error() is called -	// we assume that the simulator has received our request. Error will be -	// called if this request times out. -	class AsyncConsoleResponder : public LLHTTPClient::Responder -	{ -		LOG_CLASS(AsyncConsoleResponder); -	protected: -		/* virtual */ -		void httpFailure() -		{ -			LL_WARNS("Console") << dumpResponse() << LL_ENDL; -			sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); -		} -	}; - -	class ConsoleResponder : public LLHTTPClient::Responder -	{ -		LOG_CLASS(ConsoleResponder); -	public: -		ConsoleResponder(LLTextEditor *output) : mOutput(output) -		{ -		} - -	protected: -		/*virtual*/ -		void httpFailure() -		{ -			LL_WARNS("Console") << dumpResponse() << LL_ENDL; -			if (mOutput) -			{ -				mOutput->appendText( -					UNABLE_TO_SEND_COMMAND + PROMPT, -					false); -			} -		} - -		/*virtual*/ -		void httpSuccess() -		{ -			const LLSD& content = getContent(); -			LL_DEBUGS("Console") << content << LL_ENDL; -			if (mOutput) -			{ -				mOutput->appendText( -					content.asString() + PROMPT, false); -			} -		} - -	public: -		LLTextEditor * mOutput; -	}; -  	// This handles responses for console commands sent via the asynchronous  	// API.  	class ConsoleResponseNode : public LLHTTPNode @@ -202,26 +150,57 @@ void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param)  		}  		else  		{ -			// Using SimConsole (deprecated) -			LLHTTPClient::post( -				url, -				LLSD(input->getText()), -				new ConsoleResponder(mOutput)); +            LLSD postData = LLSD(input->getText()); +            LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, postData, +                boost::bind(&LLFloaterRegionDebugConsole::onConsoleSuccess, this, _1), +                boost::bind(&LLFloaterRegionDebugConsole::onConsoleError, this, _1));  		}  	}  	else  	{ -		// Using SimConsoleAsync -		LLHTTPClient::post( -			url, -			LLSD(input->getText()), -			new AsyncConsoleResponder); +        LLSD postData = LLSD(input->getText()); +        LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, postData, +            NULL, +            boost::bind(&LLFloaterRegionDebugConsole::onAsyncConsoleError, this, _1)); +  	}  	mOutput->appendText(text, false);  	input->clear();  } +void LLFloaterRegionDebugConsole::onAsyncConsoleError(LLSD result) +{ +    LL_WARNS("Console") << UNABLE_TO_SEND_COMMAND << LL_ENDL; +    sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); +} + +void LLFloaterRegionDebugConsole::onConsoleError(LLSD result) +{ +    LL_WARNS("Console") << UNABLE_TO_SEND_COMMAND << LL_ENDL; +    if (mOutput) +    { +        mOutput->appendText( +            UNABLE_TO_SEND_COMMAND + PROMPT, +            false); +    } + +} + +void LLFloaterRegionDebugConsole::onConsoleSuccess(LLSD result) +{ +    if (mOutput) +    { +        LLSD response = result; +        if (response.isMap() && response.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT)) +        { +            response = response[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; +        } +        mOutput->appendText( +            response.asString() + PROMPT, false); +    } +} +  void LLFloaterRegionDebugConsole::onReplyReceived(const std::string& output)  {  	mOutput->appendText(output + PROMPT, false); diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h index fd3af4152e..f55d964924 100755 --- a/indra/newview/llfloaterregiondebugconsole.h +++ b/indra/newview/llfloaterregiondebugconsole.h @@ -31,14 +31,13 @@  #include <boost/signals2.hpp>  #include "llfloater.h" -#include "llhttpclient.h"  class LLTextEditor;  typedef boost::signals2::signal<  	void (const std::string& output)> console_reply_signal_t; -class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Responder +class LLFloaterRegionDebugConsole : public LLFloater  {  public:  	LLFloaterRegionDebugConsole(LLSD const & key); @@ -56,6 +55,10 @@ public:   private:  	void onReplyReceived(const std::string& output); +    void onAsyncConsoleError(LLSD result); +    void onConsoleError(LLSD result); +    void onConsoleSuccess(LLSD result); +  	boost::signals2::connection mReplySignalConnection;  }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 5d1e01c1f7..37e934429f 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -97,6 +97,7 @@  #include "llpanelexperiencepicker.h"  #include "llexperiencecache.h"  #include "llpanelexperiences.h" +#include "llcorehttputil.h"  const S32 TERRAIN_TEXTURE_COUNT = 4;  const S32 CORNER_COUNT = 4; @@ -803,30 +804,6 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L  	return false;  } -class ConsoleRequestResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(ConsoleRequestResponder); -protected: -	/*virtual*/ -	void httpFailure() -	{ -		LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL; -	} -}; - - -// called if this request times out. -class ConsoleUpdateResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(ConsoleUpdateResponder); -protected: -	/* virtual */ -	void httpFailure() -	{ -		LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL; -	} -}; -  void LLFloaterRegionInfo::requestMeshRezInfo()  {  	std::string sim_console_url = gAgent.getRegion()->getCapability("SimConsoleAsync"); @@ -835,10 +812,8 @@ void LLFloaterRegionInfo::requestMeshRezInfo()  	{  		std::string request_str = "get mesh_rez_enabled"; -		LLHTTPClient::post( -			sim_console_url, -			LLSD(request_str), -			new ConsoleRequestResponder); +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(sim_console_url, LLSD(request_str), +            "Requested mesh_rez_enabled", "Error requesting mesh_rez_enabled");  	}  } @@ -874,7 +849,8 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate()  		body["allow_parcel_changes"] = getChild<LLUICtrl>("allow_parcel_changes_check")->getValue();  		body["block_parcel_search"] = getChild<LLUICtrl>("block_parcel_search_check")->getValue(); -		LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, +            "Region info update posted.", "Region info update not posted.");  	}  	else  	{ @@ -2303,36 +2279,6 @@ void LLPanelEstateInfo::getEstateOwner()  }  */ -class LLEstateChangeInfoResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLEstateChangeInfoResponder); -public: -	LLEstateChangeInfoResponder(LLPanelEstateInfo* panel) -	{ -		mpPanel = panel->getHandle(); -	} -	 -protected: -	// if we get a normal response, handle it here -	virtual void httpSuccess() -	{ -		LL_INFOS("Windlight") << "Successfully committed estate info" << LL_ENDL; - -	    // refresh the panel from the database -		LLPanelEstateInfo* panel = dynamic_cast<LLPanelEstateInfo*>(mpPanel.get()); -		if (panel) -			panel->refresh(); -	} -	 -	// if we get an error response -	virtual void httpFailure() -	{ -		LL_WARNS("Windlight") << dumpResponse() << LL_ENDL; -	} -private: -	LLHandle<LLPanel> mpPanel; -}; -  const std::string LLPanelEstateInfo::getOwnerName() const  {  	return getChild<LLUICtrl>("estate_owner")->getValue().asString(); diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index e7b49d8553..90f115faaf 100755 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -36,6 +36,7 @@  #include "llextendedstatus.h"  #include "llenvmanager.h" // for LLEnvironmentSettings +#include "lleventcoro.h"  class LLAvatarName;  class LLDispatcher; @@ -107,6 +108,8 @@ private:  	LLFloaterRegionInfo(const LLSD& seed);  	~LLFloaterRegionInfo(); + +  protected:  	void onTabSelected(const LLSD& param); diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 5fbdd75e97..14719a77f9 100755 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -50,6 +50,7 @@  #include "llviewerparcelmgr.h"  #include "llviewerregion.h"  #include "llviewerwindow.h" +#include "llcorehttputil.h"  ///----------------------------------------------------------------------------  /// LLFloaterScriptLimits @@ -180,372 +181,6 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr)  }  ///---------------------------------------------------------------------------- -// Responders -///---------------------------------------------------------------------------- - -void fetchScriptLimitsRegionInfoResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	//we don't need to test with a fake respose here (shouldn't anyway) - -#ifdef DUMP_REPLIES_TO_LLINFOS - -	LLSDNotationStreamer notation_streamer(content); -	std::ostringstream nice_llsd; -	nice_llsd << notation_streamer; - -	OSMessageBox(nice_llsd.str(), "main cap response:", 0); - -	LL_INFOS() << "main cap response:" << content << LL_ENDL; - -#endif - -	// at this point we have an llsd which should contain ether one or two urls to the services we want. -	// first we look for the details service: -	if(content.has("ScriptResourceDetails")) -	{ -		LLHTTPClient::get(content["ScriptResourceDetails"], new fetchScriptLimitsRegionDetailsResponder(mInfo)); -	} -	else -	{ -		LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); -		if(!instance) -		{ -			LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; -		} -	} - -	// then the summary service: -	if(content.has("ScriptResourceSummary")) -	{ -		LLHTTPClient::get(content["ScriptResourceSummary"], new fetchScriptLimitsRegionSummaryResponder(mInfo)); -	} -} - -void fetchScriptLimitsRegionInfoResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -} - -void fetchScriptLimitsRegionSummaryResponder::httpSuccess() -{ -	const LLSD& content_ref = getContent(); -#ifdef USE_FAKE_RESPONSES - -	LLSD fake_content; -	LLSD summary = LLSD::emptyMap(); -	LLSD available = LLSD::emptyArray(); -	LLSD available_urls = LLSD::emptyMap(); -	LLSD available_memory = LLSD::emptyMap(); -	LLSD used = LLSD::emptyArray(); -	LLSD used_urls = LLSD::emptyMap(); -	LLSD used_memory = LLSD::emptyMap(); - -	used_urls["type"] = "urls"; -	used_urls["amount"] = FAKE_NUMBER_OF_URLS; -	available_urls["type"] = "urls"; -	available_urls["amount"] = FAKE_AVAILABLE_URLS; -	used_memory["type"] = "memory"; -	used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY; -	available_memory["type"] = "memory"; -	available_memory["amount"] = FAKE_AVAILABLE_MEMORY; - -//summary response:{'summary':{'available':[{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'},{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'}],'used':[{'amount':i329,'type':'urls'},{'amount':i66741,'type':'memory'}]}} - -	used.append(used_urls); -	used.append(used_memory); -	available.append(available_urls); -	available.append(available_memory); - -	summary["available"] = available; -	summary["used"] = used; -	 -	fake_content["summary"] = summary; - -	const LLSD& content = fake_content; - -#else - -	const LLSD& content = content_ref; - -#endif - -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} - - -#ifdef DUMP_REPLIES_TO_LLINFOS - -	LLSDNotationStreamer notation_streamer(content); -	std::ostringstream nice_llsd; -	nice_llsd << notation_streamer; - -	OSMessageBox(nice_llsd.str(), "summary response:", 0); - -	LL_WARNS() << "summary response:" << *content << LL_ENDL; - -#endif - -	LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); -	if(!instance) -	{ -		LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; -	} -	else -	{ -		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); -		if(tab) -		{ -			LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); -			if(panel_memory) -			{ -				panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); - -				LLButton* btn = panel_memory->getChild<LLButton>("refresh_list_btn"); -				if(btn) -				{ -					btn->setEnabled(true); -				} - -				panel_memory->setRegionSummary(content); -			} -		} -	} -} - -void fetchScriptLimitsRegionSummaryResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -} - -void fetchScriptLimitsRegionDetailsResponder::httpSuccess() -{ -	const LLSD& content_ref = getContent(); -#ifdef USE_FAKE_RESPONSES -/* -Updated detail service, ** denotes field added: - -result (map) -+-parcels (array of maps) -  +-id (uuid) -  +-local_id (S32)** -  +-name (string) -  +-owner_id (uuid) (in ERS as owner, but owner_id in code) -  +-objects (array of maps) -    +-id (uuid) -    +-name (string) -	+-owner_id (uuid) (in ERS as owner, in code as owner_id) -	+-owner_name (sting)** -	+-location (map)** -	  +-x (float) -	  +-y (float) -	  +-z (float) -    +-resources (map) (this is wrong in the ERS but right in code) -      +-type (string) -      +-amount (int) -*/ -	LLSD fake_content; -	LLSD resource = LLSD::emptyMap(); -	LLSD location = LLSD::emptyMap(); -	LLSD object = LLSD::emptyMap(); -	LLSD objects = LLSD::emptyArray(); -	LLSD parcel = LLSD::emptyMap(); -	LLSD parcels = LLSD::emptyArray(); - -	resource["urls"] = FAKE_NUMBER_OF_URLS; -	resource["memory"] = FAKE_AMOUNT_OF_MEMORY; -	 -	location["x"] = 128.0f; -	location["y"] = 128.0f; -	location["z"] = 0.0f; -	 -	object["id"] = LLUUID("d574a375-0c6c-fe3d-5733-da669465afc7"); -	object["name"] = "Gabs fake Object!"; -	object["owner_id"] = LLUUID("8dbf2d41-69a0-4e5e-9787-0c9d297bc570"); -	object["owner_name"] = "Gabs Linden"; -	object["location"] = location; -	object["resources"] = resource; - -	objects.append(object); - -	parcel["id"] = LLUUID("da05fb28-0d20-e593-2728-bddb42dd0160"); -	parcel["local_id"] = 42; -	parcel["name"] = "Gabriel Linden\'s Sub Plot"; -	parcel["objects"] = objects; -	parcels.append(parcel); - -	fake_content["parcels"] = parcels; -	const LLSD& content = fake_content; - -#else - -	const LLSD& content = content_ref; - -#endif - -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} - -#ifdef DUMP_REPLIES_TO_LLINFOS - -	LLSDNotationStreamer notation_streamer(content); -	std::ostringstream nice_llsd; -	nice_llsd << notation_streamer; - -	OSMessageBox(nice_llsd.str(), "details response:", 0); - -	LL_INFOS() << "details response:" << content << LL_ENDL; - -#endif - -	LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); - -	if(!instance) -	{ -		LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; -	} -	else -	{ -		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); -		if(tab) -		{ -			LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); -			if(panel_memory) -			{ -				panel_memory->setRegionDetails(content); -			} -			else -			{ -				LL_WARNS() << "Failed to get scriptlimits memory panel" << LL_ENDL; -			} -		} -		else -		{ -			LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; -		} -	} -} - -void fetchScriptLimitsRegionDetailsResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -} - -void fetchScriptLimitsAttachmentInfoResponder::httpSuccess() -{ -	const LLSD& content_ref = getContent(); - -#ifdef USE_FAKE_RESPONSES - -	// just add the summary, as that's all I'm testing currently! -	LLSD fake_content = LLSD::emptyMap(); -	LLSD summary = LLSD::emptyMap(); -	LLSD available = LLSD::emptyArray(); -	LLSD available_urls = LLSD::emptyMap(); -	LLSD available_memory = LLSD::emptyMap(); -	LLSD used = LLSD::emptyArray(); -	LLSD used_urls = LLSD::emptyMap(); -	LLSD used_memory = LLSD::emptyMap(); - -	used_urls["type"] = "urls"; -	used_urls["amount"] = FAKE_NUMBER_OF_URLS; -	available_urls["type"] = "urls"; -	available_urls["amount"] = FAKE_AVAILABLE_URLS; -	used_memory["type"] = "memory"; -	used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY; -	available_memory["type"] = "memory"; -	available_memory["amount"] = FAKE_AVAILABLE_MEMORY; - -	used.append(used_urls); -	used.append(used_memory); -	available.append(available_urls); -	available.append(available_memory); - -	summary["available"] = available; -	summary["used"] = used; -	 -	fake_content["summary"] = summary; -	fake_content["attachments"] = content_ref["attachments"]; - -	const LLSD& content = fake_content; - -#else - -	const LLSD& content = content_ref; - -#endif - -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} - -#ifdef DUMP_REPLIES_TO_LLINFOS - -	LLSDNotationStreamer notation_streamer(content); -	std::ostringstream nice_llsd; -	nice_llsd << notation_streamer; - -	OSMessageBox(nice_llsd.str(), "attachment response:", 0); -	 -	LL_INFOS() << "attachment response:" << content << LL_ENDL; - -#endif - -	LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); - -	if(!instance) -	{ -		LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; -	} -	else -	{ -		LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); -		if(tab) -		{ -			LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel"); -			if(panel) -			{ -				panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); - -				LLButton* btn = panel->getChild<LLButton>("refresh_list_btn"); -				if(btn) -				{ -					btn->setEnabled(true); -				} -			 -				panel->setAttachmentDetails(content); -			} -			else -			{ -				LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL; -			} -		} -		else -		{ -			LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; -		} -	} -} - -void fetchScriptLimitsAttachmentInfoResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -} - -///----------------------------------------------------------------------------  // Memory Panel  ///---------------------------------------------------------------------------- @@ -564,12 +199,8 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources()  	std::string url = gAgent.getRegion()->getCapability("LandResources");  	if (!url.empty())  	{ -		body["parcel_id"] = mParcelId; - -		LLSD info; -		info["parcel_id"] = mParcelId; -		LLHTTPClient::post(url, body, new fetchScriptLimitsRegionInfoResponder(info)); -				 +        LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro", +            boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro, this, url));  		return TRUE;  	}  	else @@ -578,6 +209,147 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources()  	}  } +void LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptResourcesCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD postData; + +    postData["parcel_id"] = mParcelId; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS() << "Failed to get script resource info" << LL_ENDL; +        return; +    } + +    // We could retrieve these sequentially inline from this coroutine. But  +    // since the original code retrieved them in parallel I'll spawn two  +    // coroutines to do the retrieval.  + +    // The summary service: +    if (result.has("ScriptResourceSummary")) +    { +        std::string urlResourceSummary = result["ScriptResourceSummary"].asString(); +        LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro", +            boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro, this, urlResourceSummary)); +    } + +    if (result.has("ScriptResourceDetails")) +    { +        std::string urlResourceDetails = result["ScriptResourceDetails"].asString(); +        LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro", +            boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro, this, urlResourceDetails)); +    } + +    +} + +void LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptSummaryCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS() << "Unable to retrieve script summary." << LL_ENDL; +        return; +    } + +    LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); +    if (!instance) +    { +        LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; +        return; +    } + +    LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); +    if (!tab) +    { +        LL_WARNS() << "Unable to access script limits tab" << LL_ENDL; +        return; +    } + +    LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); +    if (!panelMemory) +    { +        LL_WARNS() << "Unable to get memory panel." << LL_ENDL; +        return; +    } + +    panelMemory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); + +    LLButton* btn = panelMemory->getChild<LLButton>("refresh_list_btn"); +    if (btn) +    { +        btn->setEnabled(true); +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    panelMemory->setRegionSummary(result); + +} + +void LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptDetailsCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS() << "Unable to retrieve script details." << LL_ENDL; +        return; +    } + +    LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); + +    if (!instance) +    { +        LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; +        return; +    } + +    LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); +    if (!tab) +    { +        LL_WARNS() << "Unable to access script limits tab" << LL_ENDL; +        return; +    } + +    LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); + +    if (!panelMemory) +    { +        LL_WARNS() << "Unable to get memory panel." << LL_ENDL; +        return; +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    panelMemory->setRegionDetails(result); +} +  void LLPanelScriptLimitsRegionMemory::processParcelInfo(const LLParcelData& parcel_data)  {  	if(!getLandScriptResources()) @@ -935,17 +707,8 @@ BOOL LLPanelScriptLimitsRegionMemory::StartRequestChain()  		std::string url = region->getCapability("RemoteParcelRequest");  		if (!url.empty())  		{ -			body["location"] = ll_sd_from_vector3(parcel_center); -			if (!region_id.isNull()) -			{ -				body["region_id"] = region_id; -			} -			if (!pos_global.isExactlyZero()) -			{ -				U64 region_handle = to_region_handle(pos_global); -				body["region_handle"] = ll_sd_from_U64(region_handle); -			} -			LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); +            LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url,  +                region_id, parcel_center, pos_global, getObserverHandle());  		}  		else  		{ @@ -1183,7 +946,8 @@ BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails()  	std::string url = gAgent.getRegion()->getCapability("AttachmentResources");  	if (!url.empty())  	{ -		LLHTTPClient::get(url, body, new fetchScriptLimitsAttachmentInfoResponder()); +        LLCoros::instance().launch("LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro", +            boost::bind(&LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro, this, url));  		return TRUE;  	}  	else @@ -1192,6 +956,59 @@ BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails()  	}  } +void LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL; +        return; +    } + +    LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); + +    if (!instance) +    { +        LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; +        return; +    } + +    LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); +    if (!tab) +    { +        LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; +        return; +    } + +    LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel"); +    if (!panel) +    { +        LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL; +        return; +    } + +    panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); + +    LLButton* btn = panel->getChild<LLButton>("refresh_list_btn"); +    if (btn) +    { +        btn->setEnabled(true); +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    panel->setAttachmentDetails(result); +} + +  void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content)  {  	LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list"); diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index 5ba0185d32..e3cbbd185f 100755 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -33,6 +33,8 @@  #include "llhost.h"  #include "llpanel.h"  #include "llremoteparcelrequest.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLPanelScriptLimitsInfo;  class LLTabContainer; @@ -80,57 +82,6 @@ protected:  };  ///////////////////////////////////////////////////////////////////////////// -// Responders -///////////////////////////////////////////////////////////////////////////// - -class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(fetchScriptLimitsRegionInfoResponder); -public: -	fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -	LLSD mInfo; -}; - -class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(fetchScriptLimitsRegionSummaryResponder); -public: -	fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -	LLSD mInfo; -}; - -class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(fetchScriptLimitsRegionDetailsResponder); -public: -	fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -	LLSD mInfo; -}; - -class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder); -public: -	fetchScriptLimitsAttachmentInfoResponder() {}; - -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -}; - -/////////////////////////////////////////////////////////////////////////////  // Memory panel  ///////////////////////////////////////////////////////////////////////////// @@ -181,6 +132,10 @@ private:  	std::vector<LLSD> mObjectListItems; +    void getLandScriptResourcesCoro(std::string url); +    void getLandScriptSummaryCoro(std::string url); +    void getLandScriptDetailsCoro(std::string url); +  protected:  // LLRemoteParcelInfoObserver interface: @@ -225,6 +180,7 @@ public:  	void clearList();  private: +    void getAttachmentLimitsCoro(std::string url);  	bool mGotAttachmentMemoryUsed;  	S32 mAttachmentMemoryMax; diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index c1c21c593e..6dc08417d7 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -35,8 +35,6 @@  // linden library includes  #include "llbutton.h"  #include "llevents.h" -#include "llhttpclient.h" -#include "llhttpconstants.h"  #include "llnotificationsutil.h"  #include "llradiogroup.h"  #include "lltextbox.h" @@ -45,7 +43,7 @@  #include "llvfile.h"  #include "message.h"  #include "llstartup.h"              // login_alert_done - +#include "llcorehttputil.h"  LLFloaterTOS::LLFloaterTOS(const LLSD& data)  :	LLModalDialog( data["message"].asString() ), @@ -57,57 +55,6 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data)  {  } -// helper class that trys to download a URL from a web site and calls a method  -// on parent class indicating if the web server is working or not -class LLIamHere : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLIamHere); -private: -	LLIamHere( LLFloaterTOS* parent ) : -	   mParent( parent ) -	{} - -	LLFloaterTOS* mParent; - -public: -	static LLIamHere* build( LLFloaterTOS* parent ) -	{ -		return new LLIamHere( parent ); -	} -	 -	virtual void  setParent( LLFloaterTOS* parentIn ) -	{ -		mParent = parentIn; -	} -	 -protected: -	virtual void httpSuccess() -	{ -		if ( mParent ) -		{ -			mParent->setSiteIsAlive( true ); -		} -	} - -	virtual void httpFailure() -	{ -		LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL; -		if ( mParent ) -		{ -			// *HACK: For purposes of this alive check, 302 Found -			// (aka Moved Temporarily) is considered alive.  The web site -			// redirects this link to a "cache busting" temporary URL. JC -			bool alive = (getStatus() == HTTP_FOUND); -			mParent->setSiteIsAlive( alive ); -		} -	} -}; - -// this is global and not a class member to keep crud out of the header file -namespace { -	LLPointer< LLIamHere > gResponsePtr = 0; -}; -  BOOL LLFloaterTOS::postBuild()  {	  	childSetAction("Continue", onContinue, this); @@ -180,9 +127,6 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )  LLFloaterTOS::~LLFloaterTOS()  { -	// tell the responder we're not here anymore -	if ( gResponsePtr ) -		gResponsePtr->setParent( 0 );  }  // virtual @@ -243,9 +187,10 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev  		if(!mLoadingScreenLoaded)  		{  			mLoadingScreenLoaded = true; +            std::string url(getString("real_url")); -			gResponsePtr = LLIamHere::build( this ); -			LLHTTPClient::get( getString( "real_url" ), gResponsePtr ); +            LLCoros::instance().launch("LLFloaterTOS::testSiteIsAliveCoro", +                boost::bind(&LLFloaterTOS::testSiteIsAliveCoro, this, url));  		}  		else if(mRealNavigateBegun)  		{ @@ -257,3 +202,26 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev  	}  } +void LLFloaterTOS::testSiteIsAliveCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); + +    LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    // double not.   +    // First ! returns a boolean error status, second ! is true if success result. +    setSiteIsAlive(!!status);  +} + + diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h index 47126d06a6..2748b20513 100755 --- a/indra/newview/llfloatertos.h +++ b/indra/newview/llfloatertos.h @@ -31,6 +31,8 @@  #include "llassetstorage.h"  #include "llmediactrl.h"  #include <boost/function.hpp> +#include "lleventcoro.h" +#include "llcoros.h"  class LLButton;  class LLRadioGroup; @@ -60,12 +62,15 @@ public:  	/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);  private: +    void testSiteIsAliveCoro(std::string url);  	std::string		mMessage;  	bool			mLoadingScreenLoaded;  	bool			mSiteAlive;  	bool			mRealNavigateBegun;  	std::string		mReplyPumpName; + +  };  #endif // LL_LLFLOATERTOS_H diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index e02e8eeb5a..6683a6e6e6 100755 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -26,8 +26,6 @@  #include "llviewerprecompiledheaders.h" -#include "llhttpclient.h" -  #include "llfloaterurlentry.h"  #include "llpanellandmedia.h" @@ -40,40 +38,10 @@  #include "lluictrlfactory.h"  #include "llwindow.h"  #include "llviewerwindow.h" +#include "llcorehttputil.h"  static LLFloaterURLEntry* sInstance = NULL; -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMediaTypeResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLMediaTypeResponder); -public: -	LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : -		mParent( parent ) -	{} - -	LLHandle<LLFloater> mParent; - -private: -	/* virtual */ void httpCompleted() -	{ -		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); -		std::string::size_type idx1 = media_type.find_first_of(";"); -		std::string mime_type = media_type.substr(0, idx1); - -		// Set empty type to none/none.  Empty string is reserved for legacy parcels -		// which have no mime type set. -		std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); -		LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); -		if ( floater_url_entry ) -		{ -			floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type ); -		} -	} -}; -  //-----------------------------------------------------------------------------  // LLFloaterURLEntry()  //----------------------------------------------------------------------------- @@ -225,8 +193,8 @@ void LLFloaterURLEntry::onBtnOK( void* userdata )  	if(!media_url.empty() &&   	   (scheme == "http" || scheme == "https"))  	{ -		LLHTTPClient::getHeaderOnly( media_url, -			new LLMediaTypeResponder(self->getHandle())); +        LLCoros::instance().launch("LLFloaterURLEntry::getMediaTypeCoro", +            boost::bind(&LLFloaterURLEntry::getMediaTypeCoro, media_url, self->getHandle()));  	}  	else  	{ @@ -240,6 +208,58 @@ void LLFloaterURLEntry::onBtnOK( void* userdata )  }  // static +void LLFloaterURLEntry::getMediaTypeCoro(std::string url, LLHandle<LLFloater> parentHandle) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMediaTypeCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + +    httpOpts->setHeadersOnly(true); + +    LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + +    LLSD result = httpAdapter->getAndYield(httpRequest, url, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    LLFloaterURLEntry* floaterUrlEntry = (LLFloaterURLEntry*)parentHandle.get(); +    if (!floaterUrlEntry) +    { +        LL_WARNS() << "Could not get URL entry floater." << LL_ENDL; +        return; +    } + +    // Set empty type to none/none.  Empty string is reserved for legacy parcels +    // which have no mime type set. +    std::string resolvedMimeType = LLMIMETypes::getDefaultMimeType(); + +    if (!status) +    { +        floaterUrlEntry->headerFetchComplete(status.getType(), resolvedMimeType); +        return; +    } + +    LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + +    if (resultHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) +    { +        const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE]; +        std::string::size_type idx1 = mediaType.find_first_of(";"); +        std::string mimeType = mediaType.substr(0, idx1); +        if (!mimeType.empty()) +        { +            resolvedMimeType = mimeType; +        } +    } + +    floaterUrlEntry->headerFetchComplete(status.getType(), resolvedMimeType); + +} + +// static  //-----------------------------------------------------------------------------  // onBtnCancel()  //----------------------------------------------------------------------------- diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index bdd1ebe592..20f4604907 100755 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -29,6 +29,8 @@  #include "llfloater.h"  #include "llpanellandmedia.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLLineEditor;  class LLComboBox; @@ -56,7 +58,10 @@ private:  	static void		onBtnOK(void*);  	static void		onBtnCancel(void*);  	static void		onBtnClear(void*); -	bool		callback_clear_url_list(const LLSD& notification, const LLSD& response); +	bool		    callback_clear_url_list(const LLSD& notification, const LLSD& response); + +    static void     getMediaTypeCoro(std::string url, LLHandle<LLFloater> parentHandle); +  };  #endif  // LL_LLFLOATERURLENTRY_H diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 56e671d902..edae0bfd19 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -53,6 +53,7 @@  #include "lltrans.h"  #include "llviewerregion.h"  #include <boost/regex.hpp> +#include "llcorehttputil.h"  #if LL_MSVC  #pragma warning(push)    @@ -768,9 +769,9 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id)  // LLGroupMgr  // -LLGroupMgr::LLGroupMgr() +LLGroupMgr::LLGroupMgr(): +    mMemberRequestInFlight(false)  { -	mLastGroupMembersRequestFrame = 0;  }  LLGroupMgr::~LLGroupMgr() @@ -1861,49 +1862,94 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,  	group_datap->mMemberVersion.generate();  } - -// Responder class for capability group management -class GroupBanDataResponder : public LLHTTPClient::Responder +void LLGroupMgr::getGroupBanRequestCoro(std::string url, LLUUID groupId)  { -public: -	GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false); -	virtual ~GroupBanDataResponder() {} -	virtual void httpSuccess(); -	virtual void httpFailure(); -private: -	LLUUID mGroupID; -	BOOL mForceRefresh; -}; +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) : -	mGroupID(gropup_id), -	mForceRefresh(force_refresh) -{} +    std::string finalUrl = url + "?group_id=" + groupId.asString(); -void GroupBanDataResponder::httpFailure() -{ -	LL_WARNS("GrpMgr") << "Error receiving group member data [status:"  -		<< mStatus << "]: " << mContent << LL_ENDL; +    LLSD result = httpAdapter->getAndYield(httpRequest, finalUrl); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL; +        return; +    } + +    if (result.has("ban_list")) +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        // group ban data received +        processGroupBanRequest(result); +    }  } -void GroupBanDataResponder::httpSuccess() +void LLGroupMgr::postGroupBanRequestCoro(std::string url, LLUUID groupId, +    U32 action, uuid_vec_t banList, bool update)  { -	if (mContent.has("ban_list")) -	{ -		// group ban data received -		LLGroupMgr::processGroupBanRequest(mContent); -	} -	else if (mForceRefresh) -	{ -		// no ban data received, refreshing data after successful operation  -		LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +    LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions); + +    httpOptions->setFollowRedirects(false); + +    httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + + +    std::string finalUrl = url + "?group_id=" + groupId.asString(); + +    LLSD postData = LLSD::emptyMap(); +    postData["ban_action"] = (LLSD::Integer)action; +    // Add our list of potential banned residents to the list +    postData["ban_ids"] = LLSD::emptyArray(); +    LLSD banEntry; + +    uuid_vec_t::const_iterator it = banList.begin(); +    for (; it != banList.end(); ++it) +    { +        banEntry = (*it); +        postData["ban_ids"].append(banEntry); +    } + +    LL_WARNS() << "post: " << ll_pretty_print_sd(postData) << LL_ENDL; + +    LLSD result = httpAdapter->postAndYield(httpRequest, finalUrl, postData, httpOptions, httpHeaders); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("GrpMgr") << "Error posting group member data " << LL_ENDL; +        return; +    } + +    if (result.has("ban_list")) +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        // group ban data received +        processGroupBanRequest(result); +    } + +    if (update) +    { +        getGroupBanRequestCoro(url, groupId); +    }  }  void LLGroupMgr::sendGroupBanRequest(	EBanRequestType request_type,   										const LLUUID& group_id,   										U32 ban_action, /* = BAN_NO_ACTION */ -										const std::vector<LLUUID> ban_list) /* = std::vector<LLUUID>() */ +										const std::vector<LLUUID> &ban_list) /* = std::vector<LLUUID>() */  {  	LLViewerRegion* currentRegion = gAgent.getRegion();  	if(!currentRegion) @@ -1925,37 +1971,27 @@ void LLGroupMgr::sendGroupBanRequest(	EBanRequestType request_type,  	{  		return;  	} -	cap_url += "?group_id=" + group_id.asString(); - -	LLSD body = LLSD::emptyMap(); -	body["ban_action"]  = (LLSD::Integer)(ban_action & ~BAN_UPDATE); -	// Add our list of potential banned residents to the list -	body["ban_ids"]	= LLSD::emptyArray(); -	LLSD ban_entry; -	uuid_vec_t::const_iterator iter = ban_list.begin(); -	for(;iter != ban_list.end(); ++iter) -	{ -		ban_entry = (*iter); -		body["ban_ids"].append(ban_entry); -	} +    U32 action = ban_action & ~BAN_UPDATE; +    bool update = ((ban_action & BAN_UPDATE) == BAN_UPDATE); -	LLHTTPClient::ResponderPtr grp_ban_responder = new GroupBanDataResponder(group_id, ban_action & BAN_UPDATE); -	switch(request_type) -	{ -	case REQUEST_GET: -		LLHTTPClient::get(cap_url, grp_ban_responder); -		break; -	case REQUEST_POST: -		LLHTTPClient::post(cap_url, body, grp_ban_responder); -		break; -	case REQUEST_PUT: -	case REQUEST_DEL: -		break; -	} +    switch (request_type) +    { +    case REQUEST_GET: +        LLCoros::instance().launch("LLGroupMgr::getGroupBanRequestCoro", +            boost::bind(&LLGroupMgr::getGroupBanRequestCoro, this, cap_url, group_id)); +        break; +    case REQUEST_POST: +        LLCoros::instance().launch("LLGroupMgr::postGroupBanRequestCoro", +            boost::bind(&LLGroupMgr::postGroupBanRequestCoro, this, cap_url, group_id,  +            action, ban_list, update)); +        break; +    case REQUEST_PUT: +    case REQUEST_DEL: +        break; +    }  } -  void LLGroupMgr::processGroupBanRequest(const LLSD& content)  {  	// Did we get anything in content? @@ -1992,45 +2028,42 @@ void LLGroupMgr::processGroupBanRequest(const LLSD& content)  	LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST);  } +void LLGroupMgr::groupMembersRequestCoro(std::string url, LLUUID groupId) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); +    mMemberRequestInFlight = true; -// Responder class for capability group management -class GroupMemberDataResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(GroupMemberDataResponder); -public: -	GroupMemberDataResponder() {} -	virtual ~GroupMemberDataResponder() {} +    LLSD postData = LLSD::emptyMap(); +    postData["group_id"] = groupId; -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -	LLSD mMemberData; -}; +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts); -void GroupMemberDataResponder::httpFailure() -{ -	LL_WARNS("GrpMgr") << "Error receiving group member data " -		<< dumpResponse() << LL_ENDL; -} +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); -void GroupMemberDataResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	LLGroupMgr::processCapGroupMembersRequest(content); -} +    if (!status) +    { +        LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL; +        mMemberRequestInFlight = false; +        return; +    } +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    LLGroupMgr::processCapGroupMembersRequest(result); +    mMemberRequestInFlight = false; +} -// static  void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id)  { +    static U32 lastGroupMemberRequestFrame = 0; +  	// Have we requested the information already this frame? -	if(mLastGroupMembersRequestFrame == gFrameCount) +    if ((lastGroupMemberRequestFrame == gFrameCount) || (mMemberRequestInFlight))  		return;  	LLViewerRegion* currentRegion = gAgent.getRegion(); @@ -2059,20 +2092,13 @@ void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id)  		return;  	} -	// Post to our service.  Add a body containing the group_id. -	LLSD body = LLSD::emptyMap(); -	body["group_id"]	= group_id; +    lastGroupMemberRequestFrame = gFrameCount; -	LLHTTPClient::ResponderPtr grp_data_responder = new GroupMemberDataResponder(); -	 -	// This could take a while to finish, timeout after 5 minutes. -	LLHTTPClient::post(cap_url, body, grp_data_responder, LLSD(), 300); - -	mLastGroupMembersRequestFrame = gFrameCount; +    LLCoros::instance().launch("LLGroupMgr::groupMembersRequestCoro", +        boost::bind(&LLGroupMgr::groupMembersRequestCoro, this, cap_url, group_id));  } -// static  void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)  {  	// Did we get anything in content? @@ -2089,7 +2115,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)  	LLUUID group_id = content["group_id"].asUUID(); -	LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); +	LLGroupMgrGroupData* group_datap = getGroupData(group_id);  	if(!group_datap)  	{  		LL_WARNS("GrpMgr") << "Received incorrect, possibly stale, group or request id" << LL_ENDL; @@ -2183,7 +2209,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)  	// TODO:  	// Refactor to reduce multiple calls for data we already have.  	if(group_datap->mTitles.size() < 1) -		LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id); +		sendGroupTitlesRequest(group_id);  	group_datap->mMemberDataComplete = true; @@ -2192,11 +2218,11 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)  	if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete)  	{  		group_datap->mPendingRoleMemberRequest = false; -		LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id); +		sendGroupRoleMembersRequest(group_id);  	}  	group_datap->mChanged = TRUE; -	LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); +	notifyObservers(GC_MEMBER_DATA);  } diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index 2e94e8d9a0..fd0c2de854 100755 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -32,6 +32,8 @@  #include <vector>  #include <string>  #include <map> +#include "lleventcoro.h" +#include "llcoros.h"  // Forward Declarations  class LLMessageSystem; @@ -362,6 +364,7 @@ public:  		BAN_UPDATE		= 4  	}; +  public:  	LLGroupMgr();  	~LLGroupMgr(); @@ -396,15 +399,13 @@ public:  	static void sendGroupMemberEjects(const LLUUID& group_id,  									  uuid_vec_t& member_ids); -	static void sendGroupBanRequest(EBanRequestType request_type,  +	void sendGroupBanRequest(EBanRequestType request_type,   									const LLUUID& group_id,	  									U32 ban_action = BAN_NO_ACTION, -									const uuid_vec_t ban_list = uuid_vec_t()); +									const uuid_vec_t &ban_list = uuid_vec_t()); -	static void processGroupBanRequest(const LLSD& content);  	void sendCapGroupMembersRequest(const LLUUID& group_id); -	static void processCapGroupMembersRequest(const LLSD& content);  	void cancelGroupRoleChanges(const LLUUID& group_id); @@ -427,6 +428,14 @@ public:  	void clearGroupData(const LLUUID& group_id);  private: +    void groupMembersRequestCoro(std::string url, LLUUID groupId); +    void processCapGroupMembersRequest(const LLSD& content); + +    void getGroupBanRequestCoro(std::string url, LLUUID groupId); +    void postGroupBanRequestCoro(std::string url, LLUUID groupId, U32 action, uuid_vec_t banList, bool update); + +    static void processGroupBanRequest(const LLSD& content); +  	void notifyObservers(LLGroupChange gc);  	void notifyObserver(const LLUUID& group_id, LLGroupChange gc);  	void addGroup(LLGroupMgrGroupData* group_datap); @@ -442,7 +451,7 @@ private:  	typedef std::map<LLUUID,observer_set_t> observer_map_t;  	observer_map_t mParticularObservers; -	S32 mLastGroupMembersRequestFrame; +    bool mMemberRequestInFlight;  }; diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp deleted file mode 100755 index d0492bcdb4..0000000000 --- a/indra/newview/llhomelocationresponder.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/**  - * @file llhomelocationresponder.cpp - * @author Meadhbh Hamrick - * @brief Processes responses to the HomeLocation CapReq - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -/* File Inclusions */ -#include "llviewerprecompiledheaders.h" - -#include "llhomelocationresponder.h" -#include "llsdutil.h" -#include "llagent.h" -#include "llviewerregion.h" - -void LLHomeLocationResponder::httpSuccess() -{ -  const LLSD& content = getContent(); -  LLVector3 agent_pos; -  bool      error = true; - -  do { - -    // was the call to /agent/<agent-id>/home-location successful? -    // If not, we keep error set to true -    if( ! content.has("success") ) -    { -      break; -    } - -    if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) ) -    { -      break; -    } - -    // did the simulator return a "justified" home location? -    // If no, we keep error set to true -    if( ! content.has( "HomeLocation" ) ) -    { -      break; -    } - -    if( ! content["HomeLocation"].has("LocationPos") ) -    { -      break; -    } - -    if( ! content["HomeLocation"]["LocationPos"].has("X") ) -    { -      break; -    } - -    agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); - -    if( ! content["HomeLocation"]["LocationPos"].has("Y") ) -    { -      break; -    } - -    agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); - -    if( ! content["HomeLocation"]["LocationPos"].has("Z") ) -    { -      break; -    } - -    agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); - -    error = false; -  } while( 0 ); - -  if( error ) -  { -    failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content); -  } -  else -  { -    LL_INFOS() << "setting home position" << LL_ENDL; - -    LLViewerRegion *viewer_region = gAgent.getRegion(); -    gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos ); -  } -} - -void LLHomeLocationResponder::httpFailure() -{ -  LL_WARNS() << dumpResponse() << LL_ENDL; -} diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h deleted file mode 100755 index adc6c8cb58..0000000000 --- a/indra/newview/llhomelocationresponder.h +++ /dev/null @@ -1,44 +0,0 @@ -/**  - * @file llhomelocationresponder.h - * @author Meadhbh Hamrick - * @brief Processes responses to the HomeLocation CapReq - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ -  - /* Macro Definitions */ -#ifndef LL_LLHOMELOCATIONRESPONDER_H -#define LL_LLHOMELOCATIONRESPONDER_H - -/* File Inclusions */ -#include "llhttpclient.h" - -/* Typedef, Enum, Class, Struct, etc. */ -class LLHomeLocationResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLHomeLocationResponder); -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -}; - -#endif diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp index 2d4ce6c883..530eb685fa 100755 --- a/indra/newview/llhttpretrypolicy.cpp +++ b/indra/newview/llhttpretrypolicy.cpp @@ -87,7 +87,7 @@ void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response)  	F32 retry_header_time;  	const LLCore::HttpHeaders *headers = response->getHeaders();  	bool has_retry_header_time = getRetryAfter(headers,retry_header_time); -	onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time); +	onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time);  }  void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 5d3a11e245..8d670d0b0a 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -37,7 +37,6 @@  #include "llrect.h"  #include "llerror.h"  #include "llbutton.h" -#include "llhttpclient.h"  #include "llsdutil_math.h"  #include "llstring.h"  #include "lltextutil.h" @@ -69,6 +68,7 @@  #include "llconversationlog.h"  #include "message.h"  #include "llviewerregion.h" +#include "llcorehttputil.h"  const static std::string ADHOC_NAME_SUFFIX(" Conference"); @@ -79,6 +79,10 @@ const static std::string NEARBY_P2P_BY_AGENT("nearby_P2P_by_agent");  /** Timeout of outgoing session initialization (in seconds) */  const static U32 SESSION_INITIALIZATION_TIMEOUT = 30; +void startConfrenceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents); +void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType); +void start_deprecated_conference_chat(const LLUUID& temp_session_id, const LLUUID& creator_id, const LLUUID& other_participant_id, const LLSD& agents_to_invite); +  std::string LLCallDialogManager::sPreviousSessionlName = "";  LLIMModel::LLIMSession::SType LLCallDialogManager::sPreviousSessionType = LLIMModel::LLIMSession::P2P_SESSION;  std::string LLCallDialogManager::sCurrentSessionlName = ""; @@ -110,7 +114,7 @@ void process_dnd_im(const LLSD& notification)  {      LLSD data = notification["substitutions"];      LLUUID sessionID = data["SESSION_ID"].asUUID(); -	LLUUID fromID = data["FROM_ID"].asUUID(); +    LLUUID fromID = data["FROM_ID"].asUUID();      //re-create the IM session if needed       //(when coming out of DND mode upon app restart) @@ -131,12 +135,10 @@ void process_dnd_im(const LLSD& notification)              fromID,               false,               false); //will need slight refactor to retrieve whether offline message or not (assume online for now) -		} - -	notify_of_message(data, true);      } - +    notify_of_message(data, true); +}  static void on_avatar_name_cache_toast(const LLUUID& agent_id, @@ -387,6 +389,130 @@ void on_new_message(const LLSD& msg)  	notify_of_message(msg, false);  } +void startConfrenceCoro(std::string url, +    LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD postData; +    postData["method"] = "start conference"; +    postData["session-id"] = tempSessionId; +    postData["params"] = agents; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("LLIMModel") << "Failed to start conference" << LL_ENDL; +        //try an "old school" way. +        // *TODO: What about other error status codes?  4xx 5xx? +        if (status == LLCore::HttpStatus(HTTP_BAD_REQUEST)) +        { +            start_deprecated_conference_chat( +                tempSessionId, +                creatorId, +                otherParticipantId, +                agents); +        } + +        //else throw an error back to the client? +        //in theory we should have just have these error strings +        //etc. set up in this file as opposed to the IMMgr, +        //but the error string were unneeded here previously +        //and it is not worth the effort switching over all +        //the possible different language translations +    } +} + +void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD postData; +    postData["method"] = "accept invitation"; +    postData["session-id"] = sessionId; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!gIMMgr) +    { +        LL_WARNS("") << "Global IM Manager is NULL" << LL_ENDL; +        return; +    } + +    if (!status) +    { +        LL_WARNS("LLIMModel") << "Bad HTTP response in chatterBoxInvitationCoro" << LL_ENDL; +        //throw something back to the viewer here? + +        gIMMgr->clearPendingAgentListUpdates(sessionId); +        gIMMgr->clearPendingInvitation(sessionId); + +        if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) +        { +            static const std::string error_string("session_does_not_exist_error"); +            gIMMgr->showSessionStartError(error_string, sessionId); +        } +        return; +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + +    LLIMSpeakerMgr* speakerMgr = LLIMModel::getInstance()->getSpeakerManager(sessionId); +    if (speakerMgr) +    { +        //we've accepted our invitation +        //and received a list of agents that were +        //currently in the session when the reply was sent +        //to us.  Now, it is possible that there were some agents +        //to slip in/out between when that message was sent to us +        //and now. + +        //the agent list updates we've received have been +        //accurate from the time we were added to the session +        //but unfortunately, our base that we are receiving here +        //may not be the most up to date.  It was accurate at +        //some point in time though. +        speakerMgr->setSpeakers(result); + +        //we now have our base of users in the session +        //that was accurate at some point, but maybe not now +        //so now we apply all of the updates we've received +        //in case of race conditions +        speakerMgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(sessionId)); +    } + +    if (LLIMMgr::INVITATION_TYPE_VOICE == invitationType) +    { +        gIMMgr->startCall(sessionId, LLVoiceChannel::INCOMING_CALL); +    } + +    if ((invitationType == LLIMMgr::INVITATION_TYPE_VOICE +        || invitationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) +        && LLIMModel::getInstance()->findIMSession(sessionId)) +    { +        // TODO remove in 2010, for voice calls we do not open an IM window +        //LLFloaterIMSession::show(mSessionID); +    } + +    gIMMgr->clearPendingAgentListUpdates(sessionId); +    gIMMgr->clearPendingInvitation(sessionId); + +} + +  LLIMModel::LLIMModel()   {  	addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); @@ -1459,54 +1585,6 @@ void start_deprecated_conference_chat(  	delete[] bucket;  } -class LLStartConferenceChatResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLStartConferenceChatResponder); -public: -	LLStartConferenceChatResponder( -		const LLUUID& temp_session_id, -		const LLUUID& creator_id, -		const LLUUID& other_participant_id, -		const LLSD& agents_to_invite) -	{ -		mTempSessionID = temp_session_id; -		mCreatorID = creator_id; -		mOtherParticipantID = other_participant_id; -		mAgents = agents_to_invite; -	} - -protected: -	virtual void httpFailure() -	{ -		//try an "old school" way. -		// *TODO: What about other error status codes?  4xx 5xx? -		if ( getStatus() == HTTP_BAD_REQUEST ) -		{ -			start_deprecated_conference_chat( -				mTempSessionID, -				mCreatorID, -				mOtherParticipantID, -				mAgents); -		} - -		LL_WARNS() << dumpResponse() << LL_ENDL; - -		//else throw an error back to the client? -		//in theory we should have just have these error strings -		//etc. set up in this file as opposed to the IMMgr, -		//but the error string were unneeded here previously -		//and it is not worth the effort switching over all -		//the possible different language translations -	} - -private: -	LLUUID mTempSessionID; -	LLUUID mCreatorID; -	LLUUID mOtherParticipantID; - -	LLSD mAgents; -}; -  // Returns true if any messages were sent, false otherwise.  // Is sort of equivalent to "does the server need to do anything?"  bool LLIMModel::sendStartSession( @@ -1543,20 +1621,10 @@ bool LLIMModel::sendStartSession(  		{  			std::string url = region->getCapability(  				"ChatSessionRequest"); -			LLSD data; -			data["method"] = "start conference"; -			data["session-id"] = temp_session_id; - -			data["params"] = agents; -			LLHTTPClient::post( -				url, -				data, -				new LLStartConferenceChatResponder( -					temp_session_id, -					gAgent.getID(), -					other_participant_id, -					data["params"])); +            LLCoros::instance().launch("startConfrenceCoro", +                boost::bind(&startConfrenceCoro, url, +                temp_session_id, gAgent.getID(), other_participant_id, agents));  		}  		else  		{ @@ -1574,97 +1642,6 @@ bool LLIMModel::sendStartSession(  	return false;  } -// -// Helper Functions -// - -class LLViewerChatterBoxInvitationAcceptResponder : -	public LLHTTPClient::Responder -{ -	LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder); -public: -	LLViewerChatterBoxInvitationAcceptResponder( -		const LLUUID& session_id, -		LLIMMgr::EInvitationType invitation_type) -	{ -		mSessionID = session_id; -		mInvitiationType = invitation_type; -	} - -private: -	void httpSuccess() -	{ -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		if ( gIMMgr) -		{ -			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); -			if (speaker_mgr) -			{ -				//we've accepted our invitation -				//and received a list of agents that were -				//currently in the session when the reply was sent -				//to us.  Now, it is possible that there were some agents -				//to slip in/out between when that message was sent to us -				//and now. - -				//the agent list updates we've received have been -				//accurate from the time we were added to the session -				//but unfortunately, our base that we are receiving here -				//may not be the most up to date.  It was accurate at -				//some point in time though. -				speaker_mgr->setSpeakers(content); - -				//we now have our base of users in the session -				//that was accurate at some point, but maybe not now -				//so now we apply all of the udpates we've received -				//in case of race conditions -				speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID)); -			} - -			if (LLIMMgr::INVITATION_TYPE_VOICE == mInvitiationType) -			{ -				gIMMgr->startCall(mSessionID, LLVoiceChannel::INCOMING_CALL); -			} - -			if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE  -				|| mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) -				&& LLIMModel::getInstance()->findIMSession(mSessionID)) -			{ -				// TODO remove in 2010, for voice calls we do not open an IM window -				//LLFloaterIMSession::show(mSessionID); -			} - -			gIMMgr->clearPendingAgentListUpdates(mSessionID); -			gIMMgr->clearPendingInvitation(mSessionID); -		} -	} - -	void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -		//throw something back to the viewer here? -		if ( gIMMgr ) -		{ -			gIMMgr->clearPendingAgentListUpdates(mSessionID); -			gIMMgr->clearPendingInvitation(mSessionID); -			if ( HTTP_NOT_FOUND == getStatus() ) -			{ -				static const std::string error_string("session_does_not_exist_error"); -				gIMMgr->showSessionStartError(error_string, mSessionID); -			} -		} -	} - -private: -	LLUUID mSessionID; -	LLIMMgr::EInvitationType mInvitiationType; -}; -  // the other_participant_id is either an agent_id, a group_id, or an inventory  // folder item_id (collection of calling cards) @@ -2490,15 +2467,9 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload  			if (voice)  			{ -				LLSD data; -				data["method"] = "accept invitation"; -				data["session-id"] = session_id; -				LLHTTPClient::post( -					url, -					data, -					new LLViewerChatterBoxInvitationAcceptResponder( -						session_id, -						inv_type)); +                LLCoros::instance().launch("chatterBoxInvitationCoro", +                    boost::bind(&chatterBoxInvitationCoro, url, +                    session_id, inv_type));  				// send notification message to the corresponding chat   				if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") @@ -2533,10 +2504,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload  			LLSD data;  			data["method"] = "decline invitation";  			data["session-id"] = session_id; -			LLHTTPClient::post( -				url, -				data, -				NULL); + +            LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, +                "Invitation declined",  +                "Invitation decline failed.");  		}  	} @@ -2583,15 +2554,9 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  				std::string url = gAgent.getRegion()->getCapability(  					"ChatSessionRequest"); -				LLSD data; -				data["method"] = "accept invitation"; -				data["session-id"] = session_id; -				LLHTTPClient::post( -					url, -					data, -					new LLViewerChatterBoxInvitationAcceptResponder( -						session_id, -						inv_type)); +                LLCoros::instance().launch("chatterBoxInvitationCoro", +                    boost::bind(&chatterBoxInvitationCoro, url, +                    session_id, inv_type));  			}  		}  		break; @@ -2621,10 +2586,9 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  			LLSD data;  			data["method"] = "decline invitation";  			data["session-id"] = session_id; -			LLHTTPClient::post( -				url, -				data, -				NULL);				 +            LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data,  +                "Invitation declined.",  +                "Invitation decline failed.");  		}  	} @@ -3681,15 +3645,9 @@ public:  			if ( url != "" )  			{ -				LLSD data; -				data["method"] = "accept invitation"; -				data["session-id"] = session_id; -				LLHTTPClient::post( -					url, -					data, -					new LLViewerChatterBoxInvitationAcceptResponder( -						session_id, -						LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); +                LLCoros::instance().launch("chatterBoxInvitationCoro", +                    boost::bind(&chatterBoxInvitationCoro, url, +                    session_id, LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE));  			}  		} //end if invitation has instant message  		else if ( input["body"].has("voice") ) diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index f92eff4845..41a8813acb 100755 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,6 +34,9 @@  #include "lllogchat.h"  #include "llvoicechannel.h" +#include "llcoros.h" +#include "lleventcoro.h" +  class LLAvatarName;  class LLFriendObserver;  class LLCallDialogManager;	 @@ -292,6 +295,7 @@ private:  	 * Add message to a list of message associated with session specified by session_id  	 */  	bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); +  };  class LLIMSessionObserver diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index f92332dea5..25450f2317 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -524,59 +524,6 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp  	return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID());  } -class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLCreateInventoryCategoryResponder); -public: -	LLCreateInventoryCategoryResponder(LLInventoryModel* model,  -									   boost::optional<inventory_func_type> callback): -		mModel(model), -		mCallback(callback)  -	{ -	} -	 -protected: -	virtual void httpFailure() -	{ -		LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL; -	} -	 -	virtual void httpSuccess() -	{ -		//Server has created folder. -		const LLSD& content = getContent(); -		if (!content.isMap() || !content.has("folder_id")) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		LLUUID category_id = content["folder_id"].asUUID(); -		 -		LL_DEBUGS(LOG_INV) << ll_pretty_print_sd(content) << LL_ENDL; -		// Add the category to the internal representation -		LLPointer<LLViewerInventoryCategory> cat = -		new LLViewerInventoryCategory( category_id,  -									  content["parent_id"].asUUID(), -									  (LLFolderType::EType)content["type"].asInteger(), -									  content["name"].asString(),  -									  gAgent.getID() ); -		cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); -		cat->setDescendentCount(0); -		LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); -		mModel->accountForUpdate(update); -		mModel->updateCategory(cat); - -		if (mCallback) -		{ -			mCallback.get()(category_id); -		} -	} -	 -private: -	boost::optional<inventory_func_type> mCallback; -	LLInventoryModel* mModel; -}; -  // Convenience function to create a new category. You could call  // updateCategory() with a newly generated UUID category, but this  // version will take care of details like what the name should be @@ -584,7 +531,7 @@ private:  LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  										   LLFolderType::EType preferred_type,  										   const std::string& pname, -										   boost::optional<inventory_func_type> callback) +										   inventory_func_type callback)  {  	LLUUID id; @@ -616,7 +563,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  	if ( viewer_region )  		url = viewer_region->getCapability("CreateInventoryCategory"); -	if (!url.empty() && callback.get_ptr()) +	if (!url.empty() && callback)  	{  		//Let's use the new capability. @@ -630,11 +577,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  		request["payload"] = body;  		LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; -		//		viewer_region->getCapAPI().post(request); -		LLHTTPClient::post( -			url, -			body, -			new LLCreateInventoryCategoryResponder(this, callback) ); +        LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", +            boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback));  		return LLUUID::null;  	} @@ -663,6 +607,57 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,  	return id;  } +void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("createNewCategoryCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); +     + +    httpOpts->setWantHeaders(true); + +    LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL; +        return; +    } + +    if (!result.has("folder_id")) +    { +        LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL; +        return; +    } + +    LLUUID categoryId = result["folder_id"].asUUID(); + +    // Add the category to the internal representation +    LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(categoryId, +        result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), +        result["name"].asString(), gAgent.getID()); + +    cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); +    cat->setDescendentCount(0); +    LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); +     +    accountForUpdate(update); +    updateCategory(cat); + +    if (callback) +    { +        callback(categoryId); +    } + +} +  // This is optimized for the case that we just want to know whether a  // category has any immediate children meeting a condition, without  // needing to recurse or build up any lists. diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index ac336e347c..1f1c686ef1 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -46,6 +46,8 @@  #include "httpoptions.h"  #include "httpheaders.h"  #include "httphandler.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLInventoryObserver;  class LLInventoryObject; @@ -207,14 +209,14 @@ private:   **/  	//-------------------------------------------------------------------- -	// Descendents +	// Descendants  	//--------------------------------------------------------------------  public: -	// Make sure we have the descendents in the structure.  Returns true +	// Make sure we have the descendants in the structure.  Returns true  	// if a fetch was performed.  	bool fetchDescendentsOf(const LLUUID& folder_id) const; -	// Return the direct descendents of the id provided.Set passed +	// Return the direct descendants of the id provided.Set passed  	// in values to NULL if the call fails.  	//    NOTE: The array provided points straight into the guts of  	//    this object, and should only be used for read operations, since @@ -223,10 +225,10 @@ public:  								cat_array_t*& categories,  								item_array_t*& items) const; -	// Compute a hash of direct descendent names (for detecting child name changes) +	// Compute a hash of direct descendant names (for detecting child name changes)  	LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; -	// Starting with the object specified, add its descendents to the +	// Starting with the object specified, add its descendants to the  	// array provided, but do not add the inventory object specified  	// by id. There is no guaranteed order.   	//    NOTE: Neither array will be erased before adding objects to it.  @@ -340,7 +342,7 @@ public:  	U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0);  	// Change an existing item with the matching id or add -	// the category. No notifcation will be sent to observers. This +	// the category. No notification will be sent to observers. This  	// method will only generate network traffic if the item had to be  	// reparented.  	//    NOTE: In usage, you will want to perform cache accounting @@ -378,7 +380,7 @@ public:  								   bool update_parent_version = true,  								   bool do_notify_observers = true); -	// Update model after all descendents removed from server. +	// Update model after all descendants removed from server.  	void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);  	// Update model after an existing item gets updated on server. @@ -409,7 +411,7 @@ public:  	// Changes items order by insertion of the item identified by src_item_id  	// before (or after) the item identified by dest_item_id. Both items must exist in items array.  	// Sorting is stored after method is finished. Only src_item_id is moved before (or after) dest_item_id. -	// The parameter "insert_before" controls on which side of dest_item_id src_item_id gets rensinserted. +	// The parameter "insert_before" controls on which side of dest_item_id src_item_id gets reinserted.  	static void updateItemsOrder(LLInventoryModel::item_array_t& items,   								 const LLUUID& src_item_id,   								 const LLUUID& dest_item_id, @@ -433,7 +435,7 @@ public:  	LLUUID createNewCategory(const LLUUID& parent_id,  							 LLFolderType::EType preferred_type,  							 const std::string& name, -							 boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>()); +							 inventory_func_type callback = NULL);  protected:  	// Internal methods that add inventory and make sure that all of  	// the internal data structures are consistent. These methods @@ -441,6 +443,8 @@ protected:  	// instance will take over the memory management from there.  	void addCategory(LLViewerInventoryCategory* category);  	void addItem(LLViewerInventoryItem* item); + +    void createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback);  /**                    Mutators   **                                                                            ** diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 4a7a4e268d..38c4382654 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -36,7 +36,9 @@  #include "llviewercontrol.h"  #include "llviewermedia.h"  #include "llviewernetwork.h" - +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h"  //  // Helpers @@ -117,11 +119,76 @@ namespace LLMarketplaceImport  	static S32 sImportResultStatus = 0;  	static LLSD sImportResults = LLSD::emptyMap(); +#if 0  	static LLTimer slmGetTimer;  	static LLTimer slmPostTimer; - +#endif  	// Responders -	 + +#if 1 +    void marketplacePostCoro(std::string url) +    { +        LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +        LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +            httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("marketplacePostCoro", httpPolicy)); +        LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +        LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +        LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +        httpOpts->setWantHeaders(true); +        httpOpts->setFollowRedirects(true); + +        httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); +        httpHeaders->append(HTTP_OUT_HEADER_CONNECTION, "Keep-Alive"); +        httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie); +        httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML); +        httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent()); + +        LLSD result = httpAdapter->postAndYield(httpRequest, url, LLSD(), httpOpts, httpHeaders); + +        LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +        S32 httpCode = status.getType(); +        if ((httpCode == MarketplaceErrorCodes::IMPORT_REDIRECT) || +            (httpCode == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || +            // MAINT-2301 : we determined we can safely ignore that error in that context +            (httpCode == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) +        { +            if (gSavedSettings.getBOOL("InventoryOutboxLogging")) +            { +                LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL; +            } +            httpCode = MarketplaceErrorCodes::IMPORT_DONE; +        } + +        if (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) +        { +            if (gSavedSettings.getBOOL("InventoryOutboxLogging")) +            { +                LL_INFOS() << " SLM POST clearing marketplace cookie due to client or server error" << LL_ENDL; +            } +            sMarketplaceCookie.clear(); +        } + +        sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_DONE); +        sImportPostPending = false; +        sImportResultStatus = httpCode; + +        { +            std::stringstream str; +            LLSDSerialize::toPrettyXML(result, str); + +            LL_INFOS() << "Full results:\n" << str.str() << "\n" << LL_ENDL; +        } + +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        sImportId = result; + +    } + + +#else  	class LLImportPostResponder : public LLHTTPClient::Responder  	{  		LOG_CLASS(LLImportPostResponder); @@ -167,7 +234,75 @@ namespace LLMarketplaceImport  			sImportId = getContent();  		}  	}; -	 +#endif + +#if 1 +    void marketplaceGetCoro(std::string url, bool buildHeaders) +    { +        LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +        LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +            httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("marketplaceGetCoro", httpPolicy)); +        LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +        LLCore::HttpHeaders::ptr_t httpHeaders;  +        LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +        httpOpts->setWantHeaders(true); +        httpOpts->setFollowRedirects(!sMarketplaceCookie.empty()); + +        if (buildHeaders) +        { +            httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); + +            httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); +            httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie); +            httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); +            httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent()); +        } +        else +        { +            httpHeaders = LLViewerMedia::getHttpHeaders(); +        } + +        LLSD result = httpAdapter->getAndYield(httpRequest, url, httpOpts, httpHeaders); + +        LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +        LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + +        if (sMarketplaceCookie.empty() && resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE)) +        { +            sMarketplaceCookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asString(); +        } + +        // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions +        // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty +        S32 httpCode = status.getType(); +        if ((httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && +            (httpCode != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && +            (httpCode != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) +        { +            if (gSavedSettings.getBOOL("InventoryOutboxLogging")) +            { +                LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL; +            } +            sMarketplaceCookie.clear(); +        } +        else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)) +        { +            LL_INFOS() << " SLM GET : Got error status = " << httpCode << ", but marketplace cookie not cleared." << LL_ENDL; +        } + +        sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_PROCESSING); +        sImportGetPending = false; +        sImportResultStatus = httpCode; + +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        sImportResults = result; + + +    } + +#else  	class LLImportGetResponder : public LLHTTPClient::Responder  	{  		LOG_CLASS(LLImportGetResponder); @@ -193,7 +328,7 @@ namespace LLMarketplaceImport  			}              // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions -            // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initally empty +            // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty  			S32 status = getStatus();  			if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&                  (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && @@ -216,6 +351,7 @@ namespace LLMarketplaceImport  			sImportResults = getContent();  		}  	}; +#endif  	// Basic API @@ -266,8 +402,13 @@ namespace LLMarketplaceImport  		sImportGetPending = true;  		std::string url = getInventoryImportURL(); -		 -		if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + +#if 1 +        LLCoros::instance().launch("marketplaceGetCoro", +            boost::bind(&marketplaceGetCoro, url, false)); + +#else +    	if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  		{              LL_INFOS() << " SLM GET: establishMarketplaceSessionCookie, LLHTTPClient::get, url = " << url << LL_ENDL;              LLSD headers = LLViewerMedia::getHeaders(); @@ -279,7 +420,7 @@ namespace LLMarketplaceImport  		slmGetTimer.start();  		LLHTTPClient::get(url, new LLImportGetResponder(), LLViewerMedia::getHeaders()); -		 +#endif		  		return true;  	} @@ -296,6 +437,11 @@ namespace LLMarketplaceImport  		url += sImportId.asString(); +#if 1 +        LLCoros::instance().launch("marketplaceGetCoro", +            boost::bind(&marketplaceGetCoro, url, true)); +         +#else  		// Make the headers for the post  		LLSD headers = LLSD::emptyMap();  		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; @@ -315,7 +461,7 @@ namespace LLMarketplaceImport  		slmGetTimer.start();  		LLHTTPClient::get(url, new LLImportGetResponder(), headers); -		 +#endif		  		return true;  	} @@ -334,6 +480,11 @@ namespace LLMarketplaceImport  		std::string url = getInventoryImportURL(); +#if 1 +        LLCoros::instance().launch("marketplacePostCoro", +            boost::bind(&marketplacePostCoro, url)); + +#else  		// Make the headers for the post  		LLSD headers = LLSD::emptyMap();  		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; @@ -353,7 +504,7 @@ namespace LLMarketplaceImport  		slmPostTimer.start();          LLHTTPClient::post(url, LLSD(), new LLImportPostResponder(), headers); -		 +#endif		  		return true;  	}  } @@ -362,7 +513,6 @@ namespace LLMarketplaceImport  //  // Interface class  // -  static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 1.0f;  //static diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index a1f6a01aa0..aef5bcf0dd 100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -36,6 +36,9 @@  #include "llviewerobjectlist.h"  #include "llviewerregion.h"  #include "llworld.h" +#include "llhttpsdhandler.h" +#include "httpcommon.h" +#include "llcorehttputil.h"  /**   * Materials cap parameters @@ -59,56 +62,51 @@  #define MATERIALS_PUT_THROTTLE_SECS               1.f  #define MATERIALS_PUT_MAX_ENTRIES                 50 -/** - * LLMaterialsResponder helper class - */ -class LLMaterialsResponder : public LLHTTPClient::Responder + +class LLMaterialHttpHandler : public LLHttpSDHandler  { -public: -	typedef boost::function<void (bool, const LLSD&)> CallbackFunction; +public:  +	typedef boost::function<void(bool, const LLSD&)> CallbackFunction; +	typedef boost::shared_ptr<LLMaterialHttpHandler> ptr_t; + +	LLMaterialHttpHandler(const std::string& method, CallbackFunction cback); -	LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback); -	virtual ~LLMaterialsResponder(); +	virtual ~LLMaterialHttpHandler(); -	virtual void httpSuccess(); -	virtual void httpFailure(); +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);  private:  	std::string      mMethod; -	std::string      mCapabilityURL;  	CallbackFunction mCallback;  }; -LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback) -	: LLHTTPClient::Responder() -	, mMethod(pMethod) -	, mCapabilityURL(pCapabilityURL) -	, mCallback(pCallback) +LLMaterialHttpHandler::LLMaterialHttpHandler(const std::string& method, CallbackFunction cback): +	LLHttpSDHandler(), +	mMethod(method), +	mCallback(cback)  { +  } -LLMaterialsResponder::~LLMaterialsResponder() +LLMaterialHttpHandler::~LLMaterialHttpHandler()  {  } -void LLMaterialsResponder::httpSuccess() +void LLMaterialHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)  { -	const LLSD& pContent = getContent(); -  	LL_DEBUGS("Materials") << LL_ENDL; -	mCallback(true, pContent); +	mCallback(true, content);  } -void LLMaterialsResponder::httpFailure() +void LLMaterialHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)  { -	U32 pStatus = (U32) getStatus(); -	const std::string& pReason = getReason(); -	  	LL_WARNS("Materials")  		<< "\n--------------------------------------------------------------------------\n" -		<< mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME -		<< "'\n  with url '" << mCapabilityURL	<< "' because " << pReason  +		<< mMethod << " Error[" << status.toULong() << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME +		<< "'\n  with url '" << response->getRequestURL() << "' because " << status.toString()  		<< "\n--------------------------------------------------------------------------"  		<< LL_ENDL; @@ -116,12 +114,35 @@ void LLMaterialsResponder::httpFailure()  	mCallback(false, emptyResult);  } + +  /**   * LLMaterialMgr class   */ - -LLMaterialMgr::LLMaterialMgr() +LLMaterialMgr::LLMaterialMgr(): +	mGetQueue(), +	mGetPending(), +	mGetCallbacks(), +	mGetTECallbacks(), +	mGetAllQueue(), +	mGetAllRequested(), +	mGetAllPending(), +	mGetAllCallbacks(), +	mPutQueue(), +	mMaterials(), +	mHttpRequest(), +	mHttpHeaders(), +	mHttpOptions(), +	mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +	mHttpPriority(0)  { +	LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + +	mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +	mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); +	mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); +	mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_MATERIALS); +  	mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL)));  	gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL);  	LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1)); @@ -554,6 +575,8 @@ void LLMaterialMgr::onIdle(void*)  	{  		instancep->processPutQueue();  	} + +	instancep->mHttpRequest->update(0L);  }  void LLMaterialMgr::processGetQueue() @@ -629,10 +652,26 @@ void LLMaterialMgr::processGetQueue()  		LLSD postData = LLSD::emptyMap();  		postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary; -		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id)); -		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials."  +		LLMaterialHttpHandler * handler =  +				new LLMaterialHttpHandler("POST", +				boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id) +				); + +		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '" << capURL << " for " << materialsData.size() << " materials."  			<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL; -		LLHTTPClient::post(capURL, postData, materialsResponder); + +		LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,  +				mHttpPolicy, mHttpPriority, capURL,  +				postData, mHttpOptions, mHttpHeaders, handler); + +		if (handle == LLCORE_HTTP_HANDLE_INVALID) +		{ +			delete handler; +			LLCore::HttpStatus status = mHttpRequest->getStatus(); +			LL_ERRS("Meterials") << "Failed to execute material POST. Status = " << +				status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; +		} +  		regionp->resetMaterialsCapThrottle();  	}  } @@ -667,8 +706,22 @@ void LLMaterialMgr::processGetAllQueue()  		}  		LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL; -		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)); -		LLHTTPClient::get(capURL, materialsResponder); +		LLMaterialHttpHandler *handler =  +			new LLMaterialHttpHandler("GET", +			boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion) +			); + +		LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority, capURL, +				mHttpOptions.get(), mHttpHeaders.get(), handler); + +		if (handle == LLCORE_HTTP_HANDLE_INVALID) +		{ +			delete handler; +			LLCore::HttpStatus status = mHttpRequest->getStatus(); +			LL_ERRS("Meterials") << "Failed to execute material GET. Status = " << +				status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; +		} +  		regionp->resetMaterialsCapThrottle();  		mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));  		mGetAllQueue.erase(itRegion);	// Invalidates region_id @@ -755,8 +808,24 @@ void LLMaterialMgr::processPutQueue()  			putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;  			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL; -			LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)); -			LLHTTPClient::put(capURL, putData, materialsResponder); + +			LLMaterialHttpHandler * handler = +					new LLMaterialHttpHandler("PUT", +					boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2) +					); + +			LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD( +				mHttpRequest, mHttpPolicy, mHttpPriority, capURL, +				putData, mHttpOptions, mHttpHeaders, handler); + +			if (handle == LLCORE_HTTP_HANDLE_INVALID) +			{ +				delete handler; +				LLCore::HttpStatus status = mHttpRequest->getStatus(); +				LL_ERRS("Meterials") << "Failed to execute material PUT. Status = " <<  +					status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; +			} +  			regionp->resetMaterialsCapThrottle();  		}  		else diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index e83f1f4e01..ef202d24ba 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -30,6 +30,9 @@  #include "llmaterial.h"  #include "llmaterialid.h"  #include "llsingleton.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h"  class LLViewerRegion; @@ -56,7 +59,7 @@ public:  	void put(const LLUUID& object_id, const U8 te, const LLMaterial& material);  	void remove(const LLUUID& object_id, const U8 te); -protected: +private:  	void clearGetQueues(const LLUUID& region_id);  	bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const;  	bool isGetAllPending(const LLUUID& region_id) const; @@ -72,16 +75,7 @@ protected:  	void onPutResponse(bool success, const LLSD& content);  	void onRegionRemoved(LLViewerRegion* regionp); -protected: -	typedef std::set<LLMaterialID> material_queue_t; -	typedef std::map<LLUUID, material_queue_t> get_queue_t; -	get_queue_t        mGetQueue; -	typedef std::pair<const LLUUID, LLMaterialID> pending_material_t; -	typedef std::map<const pending_material_t, F64> get_pending_map_t; -	get_pending_map_t  mGetPending; -	typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t; -	get_callback_map_t mGetCallbacks; - +private:  	// struct for TE-specific material ID query  	class TEMaterialPair  	{ @@ -108,22 +102,37 @@ protected:  		bool   operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; }  	}; -	typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t; -	get_callback_te_map_t mGetTECallbacks; +	typedef std::set<LLMaterialID> material_queue_t; +	typedef std::map<LLUUID, material_queue_t> get_queue_t; +	typedef std::pair<const LLUUID, LLMaterialID> pending_material_t; +	typedef std::map<const pending_material_t, F64> get_pending_map_t; +	typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t; + +	typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;  	typedef std::set<LLUUID> getall_queue_t; -	getall_queue_t        mGetAllQueue; -	getall_queue_t        mGetAllRequested;  	typedef std::map<LLUUID, F64> getall_pending_map_t; -	getall_pending_map_t  mGetAllPending;  	typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t; -	getall_callback_map_t mGetAllCallbacks; -  	typedef std::map<U8, LLMaterial> facematerial_map_t;  	typedef std::map<LLUUID, facematerial_map_t> put_queue_t; -	put_queue_t mPutQueue; -	material_map_t mMaterials; +	get_queue_t				mGetQueue; +	get_pending_map_t		mGetPending; +	get_callback_map_t		mGetCallbacks; + +	get_callback_te_map_t	mGetTECallbacks; +	getall_queue_t			mGetAllQueue; +	getall_queue_t			mGetAllRequested; +	getall_pending_map_t	mGetAllPending; +	getall_callback_map_t	mGetAllCallbacks; +	put_queue_t				mPutQueue; +	material_map_t			mMaterials; + +	LLCore::HttpRequest::ptr_t		mHttpRequest; +	LLCore::HttpHeaders::ptr_t		mHttpHeaders; +	LLCore::HttpOptions::ptr_t		mHttpOptions; +	LLCore::HttpRequest::policy_t	mHttpPolicy; +	LLCore::HttpRequest::priority_t	mHttpPriority;  	U32 getMaxEntries(const LLViewerRegion* regionp);  }; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index 2fb9e60b29..b8ff76aa6d 100755 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -33,6 +33,7 @@  #pragma warning (disable:4702)  #endif +#include <algorithm>  #include <boost/lexical_cast.hpp>  #include "llhttpconstants.h" @@ -40,6 +41,7 @@  #include "llmediaentry.h"  #include "lltextureentry.h"  #include "llviewerregion.h" +#include "llcorehttputil.h"  //  // When making a request @@ -91,52 +93,74 @@ const U32 LLMediaDataClient::MAX_ROUND_ROBIN_QUEUE_SIZE = 10000;  std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q);  std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q); -template <typename T> -typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type) + +//========================================================================= +/// Uniary Predicate for matching requests in collections by either the request +/// or by UUID +///  +class PredicateMatchRequest  { -	for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter) -	{ -		if(request->isMatch(*iter, match_type)) -		{ -			return iter; -		} -	} -	 -	return c.end(); +public: +    PredicateMatchRequest(const LLMediaDataClient::Request::ptr_t &request, LLMediaDataClient::Request::Type matchType = LLMediaDataClient::Request::ANY); +    PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType = LLMediaDataClient::Request::ANY); + +    PredicateMatchRequest(const PredicateMatchRequest &other); + +    bool operator()(const LLMediaDataClient::Request::ptr_t &test) const; + +private: +    LLMediaDataClient::Request::ptr_t mRequest; +    LLMediaDataClient::Request::Type  mMatchType; +    LLUUID                            mId; +}; + + +PredicateMatchRequest::PredicateMatchRequest(const LLMediaDataClient::Request::ptr_t &request, LLMediaDataClient::Request::Type matchType) : +    mRequest(request), +    mMatchType(matchType), +    mId() +{} +     +PredicateMatchRequest::PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType) : +    mRequest(), +    mMatchType(matchType), +    mId(id) +{} + +PredicateMatchRequest::PredicateMatchRequest(const PredicateMatchRequest &other) +{ +    mRequest = other.mRequest; +    mMatchType = other.mMatchType; +    mId = other.mId;  } -template <typename T> -typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) +bool PredicateMatchRequest::operator()(const LLMediaDataClient::Request::ptr_t &test) const  { -	for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter) -	{ -		if(((*iter)->getID() == id) && ((match_type == LLMediaDataClient::Request::ANY) || (match_type == (*iter)->getType()))) -		{ -			return iter; -		} -	} -	 -	return c.end(); +    if (mRequest) +        return (mRequest->isMatch(test, mMatchType)); +    else if (!mId.isNull()) +        return ((test->getID() == mId) && ((mMatchType == LLMediaDataClient::Request::ANY) || (mMatchType == test->getType()))); +    return false;  } -// NOTE: remove_matching_requests will not work correctly for containers where deleting an element may invalidate iterators -// to other elements in the container (such as std::vector). -// If the implementation is changed to use a container with this property, this will need to be revisited. +//========================================================================= +///   template <typename T> -void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) +void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred)  { -	for(typename T::iterator iter = c.begin(); iter != c.end();) -	{ -		typename T::value_type i = *iter; -		typename T::iterator next = iter; -		next++; -		if((i->getID() == id) && ((match_type == LLMediaDataClient::Request::ANY) || (match_type == i->getType()))) -		{ -			i->markDead(); -			c.erase(iter); -		} -		iter = next; -	} +    for (typename T::iterator it = c.begin(); it != c.end();) +    { +        if (matchPred(*it)) +        { +            (*it)->markDead(); +            // *TDOO: When C++11 is in change the following line to: it = c.erase(it); +            c.erase(it++); +        } +        else +        { +            ++it; +        } +    }  }  ////////////////////////////////////////////////////////////////////////////////////// @@ -145,18 +169,20 @@ void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request  //  ////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, -									 F32 retry_timer_delay, -									 U32 max_retries, -									 U32 max_sorted_queue_size, -									 U32 max_round_robin_queue_size) -	: mQueueTimerDelay(queue_timer_delay), -	  mRetryTimerDelay(retry_timer_delay), -	  mMaxNumRetries(max_retries), -	  mMaxSortedQueueSize(max_sorted_queue_size), -	  mMaxRoundRobinQueueSize(max_round_robin_queue_size), -	  mQueueTimerIsRunning(false) +LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay,   +        U32 max_retries, U32 max_sorted_queue_size, U32 max_round_robin_queue_size): +    mQueueTimerDelay(queue_timer_delay), +    mRetryTimerDelay(retry_timer_delay), +    mMaxNumRetries(max_retries), +    mMaxSortedQueueSize(max_sorted_queue_size), +    mMaxRoundRobinQueueSize(max_round_robin_queue_size), +    mQueueTimerIsRunning(false), +    mHttpRequest(new LLCore::HttpRequest()), +    mHttpHeaders(new LLCore::HttpHeaders()), +    mHttpOpts(new LLCore::HttpOptions()), +    mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID)  { +    // *TODO: Look up real Policy ID  }  LLMediaDataClient::~LLMediaDataClient() @@ -171,20 +197,23 @@ bool LLMediaDataClient::isEmpty() const  bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object)  { -	if(find_matching_request(mQueue, object->getID(), LLMediaDataClient::Request::ANY) != mQueue.end()) -		return true; -	 -	if(find_matching_request(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY) != mUnQueuedRequests.end()) -		return true; -	 +    PredicateMatchRequest upred(object->getID()); + +    if (std::find_if(mQueue.begin(), mQueue.end(), upred) != mQueue.end()) +        return true; +    if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end()) +        return true; +      	return false;  }  void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object)  {  	LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; -	remove_matching_requests(mQueue, object->getID(), LLMediaDataClient::Request::ANY); -	remove_matching_requests(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY); +    PredicateMatchRequest upred(object->getID()); + +    mark_dead_and_remove_if(mQueue, upred); +    mark_dead_and_remove_if(mUnQueuedRequests, upred);  }  void LLMediaDataClient::startQueueTimer()  @@ -207,23 +236,24 @@ void LLMediaDataClient::stopQueueTimer()  bool LLMediaDataClient::processQueueTimer()  { -	if(isEmpty()) +    if (isDoneProcessing())  		return true;  	LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is:	  " << mQueue.size() << LL_ENDL;  	LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is:	  " << mQueue << LL_ENDL;  	serviceQueue(); -	 +    serviceHttp(); +  	LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is:	  " << mQueue.size() << LL_ENDL;  	LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is:	  " << mQueue << LL_ENDL; -	return isEmpty(); +    return isDoneProcessing();  } -LLMediaDataClient::request_ptr_t LLMediaDataClient::dequeue() +LLMediaDataClient::Request::ptr_t LLMediaDataClient::dequeue()  { -	request_ptr_t request; +	Request::ptr_t request;  	request_queue_t *queue_p = getQueue();  	if (queue_p->empty()) @@ -242,20 +272,20 @@ LLMediaDataClient::request_ptr_t LLMediaDataClient::dequeue()  		else  		{  			// Don't return this request -- it's not ready to be serviced. -			request = NULL; +            request.reset();  		}  	}  	return request;  } -void LLMediaDataClient::pushBack(request_ptr_t request) +void LLMediaDataClient::pushBack(Request::ptr_t request)  {  	request_queue_t *queue_p = getQueue();  	queue_p->push_front(request);  } -void LLMediaDataClient::trackRequest(request_ptr_t request) +void LLMediaDataClient::trackRequest(Request::ptr_t request)  {  	request_set_t::iterator iter = mUnQueuedRequests.find(request); @@ -269,7 +299,7 @@ void LLMediaDataClient::trackRequest(request_ptr_t request)  	}  } -void LLMediaDataClient::stopTrackingRequest(request_ptr_t request) +void LLMediaDataClient::stopTrackingRequest(Request::ptr_t request)  {  	request_set_t::iterator iter = mUnQueuedRequests.find(request); @@ -283,16 +313,22 @@ void LLMediaDataClient::stopTrackingRequest(request_ptr_t request)  	}  } +bool LLMediaDataClient::isDoneProcessing() const +{ +    return (isEmpty() && mUnQueuedRequests.empty()); +} + +  void LLMediaDataClient::serviceQueue()  {	  	// Peel one off of the items from the queue and execute it -	request_ptr_t request; +	Request::ptr_t request;  	do  	{  		request = dequeue(); -		if(request.isNull()) +		if(!request)  		{  			// Queue is empty.  			return; @@ -317,7 +353,18 @@ void LLMediaDataClient::serviceQueue()  		trackRequest(request);  		// and make the post -		LLHTTPClient::post(url, sd_payload, request->createResponder()); +        LLHttpSDHandler *handler = request->createHandler(); +        LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, mHttpPolicy, 0, +            url, sd_payload, mHttpOpts, mHttpHeaders, handler); + +        if (handle == LLCORE_HTTP_HANDLE_INVALID) +        { +            // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers.  Requires change in LLCore::HTTP +            delete handler; +            LLCore::HttpStatus status = mHttpRequest->getStatus(); +            LL_WARNS("LLMediaDataClient") << "'" << url << "' request POST failed. Reason " +                << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL; +        }  	}  	else   	{ @@ -332,13 +379,17 @@ void LLMediaDataClient::serviceQueue()  		}  		else  		{ -			// This request has exceeded its maxumim retry count.  It will be dropped. +			// This request has exceeded its maximum retry count.  It will be dropped.  			LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL;   		}  	}  } +void LLMediaDataClient::serviceHttp() +{ +    mHttpRequest->update(0); +}  // dump the queue  std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q) @@ -395,7 +446,7 @@ BOOL LLMediaDataClient::QueueTimer::tick()  //  ////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::RetryTimer::RetryTimer(F32 time, request_ptr_t request) +LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request)  : LLEventTimer(time), mRequest(request)  {  	mRequest->startTracking(); @@ -417,7 +468,7 @@ BOOL LLMediaDataClient::RetryTimer::tick()  	}  	// Release the ref to the request. -	mRequest = NULL; +    mRequest.reset();  	// Don't fire again  	return TRUE; @@ -490,7 +541,7 @@ void LLMediaDataClient::Request::reEnqueue()  {  	if(mMDC)  	{ -		mMDC->enqueue(this); +		mMDC->enqueue(shared_from_this());  	}  } @@ -533,13 +584,13 @@ bool LLMediaDataClient::Request::isDead()  void LLMediaDataClient::Request::startTracking()   {   	if(mMDC)  -		mMDC->trackRequest(this);  +        mMDC->trackRequest(shared_from_this());  }  void LLMediaDataClient::Request::stopTracking()   {   	if(mMDC)  -		mMDC->stopTrackingRequest(this);  +        mMDC->stopTrackingRequest(shared_from_this());  }  std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) @@ -551,79 +602,67 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)  	<< " #retries=" << r.getRetryCount();  	return s;  } -			 -////////////////////////////////////////////////////////////////////////////////////// -// -// LLMediaDataClient::Responder -// -////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::Responder::Responder(const request_ptr_t &request) -: mRequest(request) +//======================================================================== + +LLMediaDataClient::Handler::Handler(const Request::ptr_t &request): +    mRequest(request)  {  } -/*virtual*/ -void LLMediaDataClient::Responder::httpFailure() + +void LLMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)  { -	mRequest->stopTracking(); +    mRequest->stopTracking(); -	if(mRequest->isDead()) -	{ -		LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL; -		return; -	} -	 -	if (getStatus() == HTTP_SERVICE_UNAVAILABLE) -	{ -		F32 retry_timeout; -#if 0 -		// *TODO: Honor server Retry-After header. -		if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) -			|| !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) -#endif -		{ -			retry_timeout = mRequest->getRetryTimerDelay(); -		} -		 -		mRequest->incRetryCount(); -		 -		if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())  -		{ -			LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; -			 -			// Start timer (instances are automagically tracked by -			// InstanceTracker<> and LLEventTimer) -			new RetryTimer(F32(retry_timeout/*secs*/), mRequest); -		} -		else  -		{ -			LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count "  -				<< mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; -		} -	} -	// *TODO: Redirect on 3xx status codes. -	else  -	{ -		LL_WARNS("LLMediaDataClient") << *mRequest << " http failure " -				<< dumpResponse() << LL_ENDL; -	} +    if (mRequest->isDead()) +    { +        LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL; +        return; +    } + +    LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << LL_ENDL;  } -/*virtual*/ -void LLMediaDataClient::Responder::httpSuccess() +void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)  { -	mRequest->stopTracking(); +    mRequest->stopTracking(); -	if(mRequest->isDead()) -	{ -		LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL; -		return; -	} +    if (status == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE)) +    { +        F32 retry_timeout; +#if 0 +        // *TODO: Honor server Retry-After header. +        if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) +            || !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) +#endif +        { +            retry_timeout = mRequest->getRetryTimerDelay(); +        } + +        mRequest->incRetryCount(); -	LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL; +        if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())  +        { +            LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; + +            // Start timer (instances are automagically tracked by +            // InstanceTracker<> and LLEventTimer) +            new RetryTimer(F32(retry_timeout/*secs*/), mRequest); +        } +        else  +        { +            LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count "  +                << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; +        } +    } +    else +    { +        LL_WARNS("LLMediaDataClient") << *mRequest << " HTTP failure " << LL_ENDL; +    }  } +  //////////////////////////////////////////////////////////////////////////////////////  //  // LLObjectMediaDataClient @@ -634,7 +673,7 @@ void LLMediaDataClient::Responder::httpSuccess()  void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object)  {  	// Create a get request and put it in the queue. -	enqueue(new RequestGet(object, this)); +	enqueue(Request::ptr_t(new RequestGet(object, this)));  }  const char *LLObjectMediaDataClient::getCapabilityName() const  @@ -678,14 +717,14 @@ void LLObjectMediaDataClient::sortQueue()  }  // static -bool LLObjectMediaDataClient::compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2) +bool LLObjectMediaDataClient::compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2)  { -	if (o2.isNull()) return true; -	if (o1.isNull()) return false; +	if (!o2) return true; +	if (!o1) return false;  	return ( o1->getScore() > o2->getScore() );  } -void LLObjectMediaDataClient::enqueue(Request *request) +void LLObjectMediaDataClient::enqueue(Request::ptr_t request)  {  	if(request->isDead())  	{ @@ -703,9 +742,10 @@ void LLObjectMediaDataClient::enqueue(Request *request)  	{  		// For GET requests that are not new, if a matching request is already in the round robin queue,   		// in flight, or being retried, leave it at its current position. -		request_queue_t::iterator iter = find_matching_request(mRoundRobinQueue, request->getID(), Request::GET); -		request_set_t::iterator iter2 = find_matching_request(mUnQueuedRequests, request->getID(), Request::GET); -		 +        PredicateMatchRequest upred(request->getID(), Request::GET); +        request_queue_t::iterator iter = std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), upred); +        request_set_t::iterator iter2 = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); +  		if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) )  		{  			LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; @@ -718,9 +758,11 @@ void LLObjectMediaDataClient::enqueue(Request *request)  	// IF the update will cause an object update message to be sent out at some point in the future, it probably should.  	// Remove any existing requests of this type for this object -	remove_matching_requests(mQueue, request->getID(), request->getType()); -	remove_matching_requests(mRoundRobinQueue, request->getID(), request->getType()); -	remove_matching_requests(mUnQueuedRequests, request->getID(), request->getType()); +    PredicateMatchRequest upred(request->getID(), request->getType()); + +    mark_dead_and_remove_if(mQueue, upred); +    mark_dead_and_remove_if(mRoundRobinQueue, upred); +    mark_dead_and_remove_if(mUnQueuedRequests, upred);  	if (is_new)  	{ @@ -749,7 +791,7 @@ void LLObjectMediaDataClient::enqueue(Request *request)  	startQueueTimer();  } -bool LLObjectMediaDataClient::canServiceRequest(request_ptr_t request)  +bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request)   {  	if(mCurrentQueueIsTheSortedQueue)  	{ @@ -785,9 +827,9 @@ bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &ob  	if(LLMediaDataClient::isInQueue(object))  		return true; -	if(find_matching_request(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY) != mRoundRobinQueue.end()) -		return true; -	 +    if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end()) +        return true; +  	return false;  } @@ -796,12 +838,12 @@ void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr  	// First, call parent impl.  	LLMediaDataClient::removeFromQueue(object); -	remove_matching_requests(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY); +    mark_dead_and_remove_if(mRoundRobinQueue, PredicateMatchRequest(object->getID()));  }  bool LLObjectMediaDataClient::processQueueTimer()  { -	if(isEmpty()) +    if (isDoneProcessing())  		return true;  	LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is:	  " << mQueue.size()  @@ -816,6 +858,7 @@ bool LLObjectMediaDataClient::processQueueTimer()  	LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is:	  " << mQueue << LL_ENDL;  	serviceQueue(); +    serviceHttp();  	swapCurrentQueue(); @@ -824,7 +867,7 @@ bool LLObjectMediaDataClient::processQueueTimer()  	LL_DEBUGS("LLMediaDataClientQueue") << "    SORTED queue is:	  " << mQueue << LL_ENDL;  	LL_DEBUGS("LLMediaDataClientQueue") << "    RR queue is:	  " << mRoundRobinQueue << LL_ENDL; -	return isEmpty(); +    return isDoneProcessing();  }  LLObjectMediaDataClient::RequestGet::RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): @@ -841,16 +884,16 @@ LLSD LLObjectMediaDataClient::RequestGet::getPayload() const  	return result;  } -LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestGet::createResponder() +LLHttpSDHandler *LLObjectMediaDataClient::RequestGet::createHandler()  { -	return new LLObjectMediaDataClient::Responder(this); +	return new LLObjectMediaDataClient::Handler(shared_from_this());  }  void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object)  {  	// Create an update request and put it in the queue. -	enqueue(new RequestUpdate(object, this)); +	enqueue(Request::ptr_t(new RequestUpdate(object, this)));  }  LLObjectMediaDataClient::RequestUpdate::RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): @@ -877,60 +920,58 @@ LLSD LLObjectMediaDataClient::RequestUpdate::getPayload() const  	return result;  } -LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResponder() +LLHttpSDHandler *LLObjectMediaDataClient::RequestUpdate::createHandler()  {  	// This just uses the base class's responder. -	return new LLMediaDataClient::Responder(this); +	return new LLMediaDataClient::Handler(shared_from_this());  } - -/*virtual*/ -void LLObjectMediaDataClient::Responder::httpSuccess() +void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)  { -	getRequest()->stopTracking(); - -	if(getRequest()->isDead()) -	{ -		LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL; -		return; -	} - -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} +    LLMediaDataClient::Handler::onSuccess(response, content); + +    if (getRequest()->isDead()) +    {   // warning emitted from base method. +        return; +    } + +    if (!content.isMap()) +    { +        onFailure(response, LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents")); +        return; +    } + +    // This responder is only used for GET requests, not UPDATE. +    LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << LL_ENDL; + +    // Look for an error +    if (content.has("error")) +    { +        const LLSD &error = content["error"]; +        LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" <<  +            error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + +        // XXX Warn user? +    } +    else  +    { +        // Check the data +        const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; +        if (object_id != getRequest()->getObject()->getID())  +        { +            // NOT good, wrong object id!! +            LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; +            return; +        } + +        // Otherwise, update with object media data +        getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], +            content[LLTextureEntry::MEDIA_VERSION_KEY]); +    } -	// This responder is only used for GET requests, not UPDATE. -	LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; - -	// Look for an error -	if (content.has("error")) -	{ -		const LLSD &error = content["error"]; -		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" <<  -			error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; -		 -		// XXX Warn user? -	} -	else  -	{ -		// Check the data -		const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; -		if (object_id != getRequest()->getObject()->getID())  -		{ -			// NOT good, wrong object id!! -			LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; -			return; -		} -		 -		// Otherwise, update with object media data -		getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], -														 content[LLTextureEntry::MEDIA_VERSION_KEY]); -	}  } +  //////////////////////////////////////////////////////////////////////////////////////  //  // LLObjectMediaNavigateClient @@ -943,16 +984,18 @@ const char *LLObjectMediaNavigateClient::getCapabilityName() const  	return "ObjectMediaNavigate";  } -void LLObjectMediaNavigateClient::enqueue(Request *request) +void LLObjectMediaNavigateClient::enqueue(Request::ptr_t request)  {  	if(request->isDead())  	{ -		LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL; +		LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL;  		return;  	} +    PredicateMatchRequest upred(request); +  	// If there's already a matching request in the queue, remove it. -	request_queue_t::iterator iter = find_matching_request(mQueue, request, LLMediaDataClient::Request::ANY); +    request_queue_t::iterator iter = std::find_if(mQueue.begin(), mQueue.end(), upred);  	if(iter != mQueue.end())  	{  		LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; @@ -960,7 +1003,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request)  	}  	else  	{ -		request_set_t::iterator set_iter = find_matching_request(mUnQueuedRequests, request, LLMediaDataClient::Request::ANY); +        request_set_t::iterator set_iter = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred);  		if(set_iter != mUnQueuedRequests.end())  		{  			LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; @@ -979,7 +1022,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request)  	else  #endif  	{ -		LL_DEBUGS("LLMediaDataClient") << "queueing new request " << (*request) << LL_ENDL; +		LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL;  		mQueue.push_back(request);  		// Start the timer if not already running @@ -993,7 +1036,7 @@ void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 t  //	LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL;  	// Create a get request and put it in the queue. -	enqueue(new RequestNavigate(object, this, texture_index, url)); +	enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url)));  }  LLObjectMediaNavigateClient::RequestNavigate::RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url): @@ -1012,75 +1055,67 @@ LLSD LLObjectMediaNavigateClient::RequestNavigate::getPayload() const  	return result;  } -LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::createResponder() +LLHttpSDHandler *LLObjectMediaNavigateClient::RequestNavigate::createHandler()  { -	return new LLObjectMediaNavigateClient::Responder(this); +	return new LLObjectMediaNavigateClient::Handler(shared_from_this());  } -/*virtual*/ -void LLObjectMediaNavigateClient::Responder::httpFailure() +void LLObjectMediaNavigateClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)  { -	getRequest()->stopTracking(); +    LLMediaDataClient::Handler::onSuccess(response, content); -	if(getRequest()->isDead()) -	{ -		LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL; -		return; -	} +    if (getRequest()->isDead()) +    {   // already warned. +        return; +    } + +    LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned" << LL_ENDL; + +    if (content.has("error")) +    { +        const LLSD &error = content["error"]; +        int error_code = error["code"]; + +        if (ERROR_PERMISSION_DENIED_CODE == error_code) +        { +            mediaNavigateBounceBack(); +        } +        else +        { +            LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << +                error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; +        } + +        // XXX Warn user? +    } +    else +    { +        // No action required. +        LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << LL_ENDL; +    } -	// Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base -	// class -	if (getStatus() == HTTP_SERVICE_UNAVAILABLE) -	{ -		LLMediaDataClient::Responder::httpFailure(); -	} -	else -	{ -		// bounce the face back -		LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL; -		const LLSD &payload = getRequest()->getPayload(); -		// bounce the face back -		getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); -	}  } -/*virtual*/ -void LLObjectMediaNavigateClient::Responder::httpSuccess() +void LLObjectMediaNavigateClient::Handler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)  { -	getRequest()->stopTracking(); +    LLMediaDataClient::Handler::onFailure(response, status); -	if(getRequest()->isDead()) -	{ -		LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL; -		return; -	} +    if (getRequest()->isDead()) +    {   // already warned. +        return; +    } -	LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL; -	 -	const LLSD& content = getContent(); -	if (content.has("error")) -	{ -		const LLSD &error = content["error"]; -		int error_code = error["code"]; -		 -		if (ERROR_PERMISSION_DENIED_CODE == error_code) -		{ -			LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL; -			const LLSD &payload = getRequest()->getPayload(); -			// bounce the face back -			getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); -		} -		else -		{ -			LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" <<  -				error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; -		}			  +    if (status != LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE)) +    { +        mediaNavigateBounceBack(); +    } +} -		// XXX Warn user? -	} -	else  -	{ -		// No action required. -		LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; -	} +void LLObjectMediaNavigateClient::Handler::mediaNavigateBounceBack() +{ +    LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating or denied." << LL_ENDL; +    const LLSD &payload = getRequest()->getPayload(); +     +    // bounce the face back +    getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]);  } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 80dd519812..9907897613 100755 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -27,12 +27,15 @@  #ifndef LL_LLMEDIADATACLIENT_H  #define LL_LLMEDIADATACLIENT_H -#include "llhttpclient.h"  #include <set>  #include "llrefcount.h"  #include "llpointer.h"  #include "lleventtimer.h" - +#include "llhttpsdhandler.h" +#include "httpcommon.h" +#include "httprequest.h" +#include "httpoptions.h" +#include "httpheaders.h"  // Link seam for LLVOVolume  class LLMediaDataClientObject : public LLRefCount @@ -74,6 +77,8 @@ public:  // Abstracts the Cap URL, the request, and the responder  class LLMediaDataClient : public LLRefCount  { +    friend class PredicateMatchRequest; +  protected:      LOG_CLASS(LLMediaDataClient);  public: @@ -109,26 +114,30 @@ protected:  	// Destructor  	virtual ~LLMediaDataClient(); // use unref -	class Responder; -	  	// Request (pure virtual base class for requests in the queue) -	class Request : public LLRefCount -	{ -	public: -		// Subclasses must implement this to build a payload for their request type. -		virtual LLSD getPayload() const = 0; -		// and must create the correct type of responder. -		virtual Responder *createResponder() = 0; +    class Request:  +        public boost::enable_shared_from_this<Request> +    { +    public: +        typedef boost::shared_ptr<Request> ptr_t; -		virtual std::string getURL() { return ""; } +        // Subclasses must implement this to build a payload for their request type. +        virtual LLSD getPayload() const = 0; +        // and must create the correct type of responder. +        virtual LLHttpSDHandler *createHandler() = 0; + +        virtual std::string getURL() { return ""; }          enum Type {              GET,              UPDATE,              NAVIGATE, -			ANY +            ANY          }; -         + +        virtual ~Request() +        { } +  	protected:  		// The only way to create one of these is through a subclass.  		Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1); @@ -166,7 +175,7 @@ protected:  		const LLUUID &getID() const { return mObjectID; }  		S32 getFace() const { return mFace; } -		bool isMatch (const Request* other, Type match_type = ANY) const  +		bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const   		{   			return ((match_type == ANY) || (mType == other->mType)) &&   					(mFace == other->mFace) &&  @@ -188,61 +197,62 @@ protected:  		// Back pointer to the MDC...not a ref!  		LLMediaDataClient *mMDC;  	}; -	typedef LLPointer<Request> request_ptr_t; +	//typedef LLPointer<Request> request_ptr_t; -	// Responder -	class Responder : public LLHTTPClient::Responder -	{ -		LOG_CLASS(Responder); -	public: -		Responder(const request_ptr_t &request); -		request_ptr_t &getRequest() { return mRequest; } +    class Handler : public LLHttpSDHandler +    { +        LOG_CLASS(Handler); +    public: +        Handler(const Request::ptr_t &request); +        Request::ptr_t getRequest() const { return mRequest; } -	protected: -		//If we get back an error (not found, etc...), handle it here -		virtual void httpFailure(); -		//If we get back a normal response, handle it here.	 Default just logs it. -		virtual void httpSuccess(); +    protected: +        virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +        virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + +    private: +        Request::ptr_t mRequest; +    }; -	private: -		request_ptr_t mRequest; -	};  	class RetryTimer : public LLEventTimer  	{  	public: -		RetryTimer(F32 time, request_ptr_t); +		RetryTimer(F32 time, Request::ptr_t);  		virtual BOOL tick();  	private:  		// back-pointer -		request_ptr_t mRequest; +		Request::ptr_t mRequest;  	};  protected: -	typedef std::list<request_ptr_t> request_queue_t; -	typedef std::set<request_ptr_t> request_set_t; +	typedef std::list<Request::ptr_t> request_queue_t; +	typedef std::set<Request::ptr_t> request_set_t;  	// Subclasses must override to return a cap name  	virtual const char *getCapabilityName() const = 0;  	// Puts the request into a queue, appropriately handling duplicates, etc. -	virtual void enqueue(Request*) = 0; +    virtual void enqueue(Request::ptr_t) = 0;  	virtual void serviceQueue(); +    virtual void serviceHttp();  	virtual request_queue_t *getQueue() { return &mQueue; };  	// Gets the next request, removing it from the queue -	virtual request_ptr_t dequeue(); +	virtual Request::ptr_t dequeue(); -	virtual bool canServiceRequest(request_ptr_t request) { return true; }; +	virtual bool canServiceRequest(Request::ptr_t request) { return true; };  	// Returns a request to the head of the queue (should only be used for requests that came from dequeue -	virtual void pushBack(request_ptr_t request); +	virtual void pushBack(Request::ptr_t request); -	void trackRequest(request_ptr_t request); -	void stopTrackingRequest(request_ptr_t request); +	void trackRequest(Request::ptr_t request); +	void stopTrackingRequest(Request::ptr_t request); + +    bool isDoneProcessing() const;  	request_queue_t mQueue; @@ -260,6 +270,11 @@ protected:  	void startQueueTimer();  	void stopQueueTimer(); +    LLCore::HttpRequest::ptr_t  mHttpRequest; +    LLCore::HttpHeaders::ptr_t  mHttpHeaders; +    LLCore::HttpOptions::ptr_t  mHttpOpts; +    LLCore::HttpRequest::policy_t mHttpPolicy; +  private:  	static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); @@ -281,9 +296,9 @@ private:  	bool mQueueTimerIsRunning; -	template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); -	template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); -	template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); +// 	template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); +// 	template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); +// 	template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type);  };  // MediaDataClient specific for the ObjectMedia cap @@ -309,7 +324,7 @@ public:  	public:  		RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);  		/*virtual*/ LLSD getPayload() const; -		/*virtual*/ Responder *createResponder(); +        /*virtual*/ LLHttpSDHandler *createHandler();  	};  	class RequestUpdate: public Request @@ -317,7 +332,7 @@ public:  	public:  		RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc);  		/*virtual*/ LLSD getPayload() const; -		/*virtual*/ Responder *createResponder(); +        /*virtual*/ LLHttpSDHandler *createHandler();  	};  	// Returns true iff the queue is empty @@ -331,7 +346,7 @@ public:  	virtual bool processQueueTimer(); -	virtual bool canServiceRequest(request_ptr_t request); +	virtual bool canServiceRequest(Request::ptr_t request);  protected:  	// Subclasses must override to return a cap name @@ -340,17 +355,20 @@ protected:  	virtual request_queue_t *getQueue();  	// Puts the request into the appropriate queue -	virtual void enqueue(Request*); +	virtual void enqueue(Request::ptr_t); -    class Responder : public LLMediaDataClient::Responder +    class Handler: public LLMediaDataClient::Handler      { -        LOG_CLASS(Responder); +        LOG_CLASS(Handler);      public: -        Responder(const request_ptr_t &request) -            : LLMediaDataClient::Responder(request) {} +        Handler(const Request::ptr_t &request): +            LLMediaDataClient::Handler(request) +        {} +      protected: -        virtual void httpSuccess(); +        virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content);      }; +  private:  	// The Get/Update data client needs a second queue to avoid object updates starving load-ins.  	void swapCurrentQueue(); @@ -359,7 +377,7 @@ private:  	bool mCurrentQueueIsTheSortedQueue;  	// Comparator for sorting -	static bool compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2); +	static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2);  	void sortQueue();  }; @@ -384,14 +402,14 @@ public:      void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);  	// Puts the request into the appropriate queue -	virtual void enqueue(Request*); +    virtual void enqueue(Request::ptr_t);  	class RequestNavigate: public Request  	{  	public:  		RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url);  		/*virtual*/ LLSD getPayload() const; -		/*virtual*/ Responder *createResponder(); +        /*virtual*/ LLHttpSDHandler *createHandler();  		/*virtual*/ std::string getURL() { return mURL; }  	private:  		std::string mURL; @@ -401,15 +419,18 @@ protected:  	// Subclasses must override to return a cap name  	virtual const char *getCapabilityName() const; -    class Responder : public LLMediaDataClient::Responder +    class Handler : public LLMediaDataClient::Handler      { -        LOG_CLASS(Responder); +        LOG_CLASS(Handler);      public: -        Responder(const request_ptr_t &request) -            : LLMediaDataClient::Responder(request) {} +        Handler(const Request::ptr_t &request): +            LLMediaDataClient::Handler(request) +        {} +      protected: -        virtual void httpFailure(); -        virtual void httpSuccess(); +        virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +        virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); +      private:          void mediaNavigateBounceBack();      }; diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 878f1af9ef..5d1ae4ff10 100755 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -34,14 +34,12 @@  #include "lldispatcher.h"  #include "llfloaterreg.h" -#include "llhttpclient.h"  #include "llnotifications.h"  #include "llnotificationsutil.h"  #include "llparcel.h"  #include "llagent.h"  #include "llclassifiedflags.h" -#include "llclassifiedstatsresponder.h"  #include "llcommandhandler.h" // for classified HTML detail page click tracking  #include "lliconctrl.h"  #include "lllineeditor.h" @@ -57,6 +55,7 @@  #include "llscrollcontainer.h"  #include "llstatusbar.h"  #include "llviewertexture.h" +#include "llcorehttputil.h"  const S32 MINIMUM_PRICE_FOR_LISTING = 50;	// L$ @@ -91,19 +90,6 @@ public:  };  static LLDispatchClassifiedClickThrough sClassifiedClickThrough; -// Just to debug errors. Can be thrown away later. -class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLClassifiedClickMessageResponder); - -protected: -	// If we get back an error (not found, etc...), handle it here -	virtual void httpFailure() -	{ -		LL_WARNS() << "Sending click message failed " << dumpResponse() << LL_ENDL; -	} -}; -  //////////////////////////////////////////////////////////////////////////  //////////////////////////////////////////////////////////////////////////  ////////////////////////////////////////////////////////////////////////// @@ -229,8 +215,10 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key)  	{  		LL_INFOS() << "Classified stat request via capability" << LL_ENDL;  		LLSD body; -		body["classified_id"] = getClassifiedId(); -		LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(getClassifiedId())); +        LLUUID classifiedId = getClassifiedId(); +		body["classified_id"] = classifiedId; +        LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, +            boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1));  	}  	// Update classified click stats. @@ -240,6 +228,23 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key)  	setInfoLoaded(false);  } +/*static*/ +void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result) +{ +    S32 teleport = result["teleport_clicks"].asInteger(); +    S32 map = result["map_clicks"].asInteger(); +    S32 profile = result["profile_clicks"].asInteger(); +    S32 search_teleport = result["search_teleport_clicks"].asInteger(); +    S32 search_map = result["search_map_clicks"].asInteger(); +    S32 search_profile = result["search_profile_clicks"].asInteger(); + +    LLPanelClassifiedInfo::setClickThrough(classifiedId, +        teleport + search_teleport, +        map + search_map, +        profile + search_profile, +        true); +} +  void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type)  {  	if(APT_CLASSIFIED_INFO == type) @@ -548,7 +553,8 @@ void LLPanelClassifiedInfo::sendClickMessage(  	std::string url = gAgent.getRegion()->getCapability("SearchStatTracking");  	LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL;  	LL_INFOS() << "body: [" << body << "]" << LL_ENDL; -	LLHTTPClient::post(url, body, new LLClassifiedClickMessageResponder()); +    LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, +        "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent.");  }  void LLPanelClassifiedInfo::sendClickMessage(const std::string& type) diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h index cedd65c405..b292782615 100755 --- a/indra/newview/llpanelclassified.h +++ b/indra/newview/llpanelclassified.h @@ -37,6 +37,8 @@  #include "llrect.h"  #include "lluuid.h"  #include "v3dmath.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLScrollContainer;  class LLTextureCtrl; @@ -193,6 +195,9 @@ private:  	S32 mMapClicksNew;  	S32 mProfileClicksNew; +    static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + +  	typedef std::list<LLPanelClassifiedInfo*> panel_list_t;  	static panel_list_t sAllPanels;  }; diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index 70d826a407..c7a353a6af 100644 --- a/indra/newview/llpanelexperiencepicker.cpp +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -42,6 +42,7 @@  #include "llviewercontrol.h"  #include "llfloater.h"  #include "lltrans.h" +#include "llhttpclient.h"  // *TODO: Rider, remove when converting  #define BTN_FIND		"find"  #define BTN_OK			"ok_btn" diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 1d73d4bd6e..cd1dc0f070 100755 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -1352,17 +1352,8 @@ void LLLandmarksPanel::doCreatePick(LLLandmark* landmark)  	std::string url = region->getCapability("RemoteParcelRequest");  	if (!url.empty())  	{ -		body["location"] = ll_sd_from_vector3(region_pos); -		if (!region_id.isNull()) -		{ -			body["region_id"] = region_id; -		} -		if (!pos_global.isExactlyZero()) -		{ -			U64 region_handle = to_region_handle(pos_global); -			body["region_handle"] = ll_sd_from_U64(region_handle); -		} -		LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); +        LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, +            region_id, region_pos, pos_global, getObserverHandle());  	}  	else  	{ diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index cc8c3edd51..99c9fad82d 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -59,7 +59,6 @@  #include "llviewernetwork.h"  #include "llviewerwindow.h"			// to link into child list  #include "lluictrlfactory.h" -#include "llhttpclient.h"  #include "llweb.h"  #include "llmediactrl.h"  #include "llrootview.h" diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp index cedd3025fc..55e4ffff5e 100755 --- a/indra/newview/llpanelme.cpp +++ b/indra/newview/llpanelme.cpp @@ -37,7 +37,6 @@  #include "llfloaterreg.h"  #include "llhints.h"  #include "llviewercontrol.h" -#include "llviewerdisplayname.h"  // Linden libraries  #include "llavatarnamecache.h"		// IDEVO diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index e62b5a4f1d..cec56a7ae7 100755 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -45,6 +45,7 @@  #include "llpanelpick.h"  #include "lltexturectrl.h"  #include "llviewerregion.h" +#include "llhttpconstants.h"  LLPanelPlaceInfo::LLPanelPlaceInfo()  :	LLPanel(), @@ -150,17 +151,8 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id,  	std::string url = region->getCapability("RemoteParcelRequest");  	if (!url.empty())  	{ -		body["location"] = ll_sd_from_vector3(mPosRegion); -		if (!region_id.isNull()) -		{ -			body["region_id"] = region_id; -		} -		if (!pos_global.isExactlyZero()) -		{ -			U64 region_handle = to_region_handle(pos_global); -			body["region_handle"] = ll_sd_from_U64(region_handle); -		} -		LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); +        LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, +            region_id, mPosRegion, pos_global, getObserverHandle());  	}  	else  	{ diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 4977a72dc6..2e6937a79f 100755 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -39,7 +39,6 @@  #include <boost/signals2.hpp>  #include "llagent.h" -#include "llhttpclient.h"  #include "llhttpnode.h"  #include "llnotificationsutil.h"  #include "llpathfindingcharacterlist.h" @@ -55,6 +54,8 @@  #include "lluuid.h"  #include "llviewerregion.h"  #include "llweb.h" +#include "llcorehttputil.h" +#include "llworld.h"  #define CAP_SERVICE_RETRIEVE_NAVMESH        "RetrieveNavMeshSrc" @@ -98,82 +99,6 @@ public:  LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode(SIM_MESSAGE_AGENT_STATE_UPDATE);  //--------------------------------------------------------------------------- -// NavMeshStatusResponder -//--------------------------------------------------------------------------- - -class NavMeshStatusResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(NavMeshStatusResponder); -public: -	NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly); -	virtual ~NavMeshStatusResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -private: -	LLViewerRegion *mRegion; -	LLUUID         mRegionUUID; -	bool           mIsGetStatusOnly; -}; - -//--------------------------------------------------------------------------- -// NavMeshResponder -//--------------------------------------------------------------------------- - -class NavMeshResponder : public LLHTTPClient::Responder -{ -    LOG_CLASS(NavMeshResponder); -public: -	NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); -	virtual ~NavMeshResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -private: -	U32                     mNavMeshVersion; -	LLPathfindingNavMeshPtr mNavMeshPtr; -}; - -//--------------------------------------------------------------------------- -// AgentStateResponder -//--------------------------------------------------------------------------- - -class AgentStateResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(AgentStateResponder); -public: -	AgentStateResponder(); -	virtual ~AgentStateResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); -}; - - -//--------------------------------------------------------------------------- -// NavMeshRebakeResponder -//--------------------------------------------------------------------------- -class NavMeshRebakeResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(NavMeshRebakeResponder); -public: -	NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); -	virtual ~NavMeshRebakeResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -private: -	LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback; -}; - -//---------------------------------------------------------------------------  // LinksetsResponder  //--------------------------------------------------------------------------- @@ -188,6 +113,8 @@ public:  	void handleTerrainLinksetsResult(const LLSD &pContent);  	void handleTerrainLinksetsError(); +    typedef boost::shared_ptr<LinksetsResponder> ptr_t; +  protected:  private: @@ -214,64 +141,6 @@ private:  typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;  //--------------------------------------------------------------------------- -// ObjectLinksetsResponder -//--------------------------------------------------------------------------- - -class ObjectLinksetsResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(ObjectLinksetsResponder); -public: -	ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); -	virtual ~ObjectLinksetsResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -private: -	LinksetsResponderPtr mLinksetsResponsderPtr; -}; - -//--------------------------------------------------------------------------- -// TerrainLinksetsResponder -//--------------------------------------------------------------------------- - -class TerrainLinksetsResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(TerrainLinksetsResponder); -public: -	TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); -	virtual ~TerrainLinksetsResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -private: -	LinksetsResponderPtr mLinksetsResponsderPtr; -}; - -//--------------------------------------------------------------------------- -// CharactersResponder -//--------------------------------------------------------------------------- - -class CharactersResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(TerrainLinksetsResponder); -public: -	CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); -	virtual ~CharactersResponder(); - -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); - -private: -	LLPathfindingManager::request_id_t              mRequestId; -	LLPathfindingManager::object_request_callback_t mCharactersCallback; -}; - -//---------------------------------------------------------------------------  // LLPathfindingManager  //--------------------------------------------------------------------------- @@ -350,11 +219,13 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b  	}  	else  	{ -		std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); -		llassert(!navMeshStatusURL.empty()); -		navMeshPtr->handleNavMeshCheckVersion(); -		LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly); -		LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); +        std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); +        llassert(!navMeshStatusURL.empty()); +        navMeshPtr->handleNavMeshCheckVersion(); + +        U64 regionHandle = pRegion->getHandle(); +        std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navMeshStatusRequestCoro", +            boost::bind(&LLPathfindingManager::navMeshStatusRequestCoro, this, navMeshStatusURL, regionHandle, pIsGetStatusOnly));  	}  } @@ -385,15 +256,15 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re  			pLinksetsCallback(pRequestId, kRequestStarted, emptyLinksetListPtr);  			bool doRequestTerrain = isAllowViewTerrainProperties(); -			LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); +			LinksetsResponder::ptr_t linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); -			LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); -			LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); +            std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetObjectsCoro", +                boost::bind(&LLPathfindingManager::linksetObjectsCoro, this, objectLinksetsURL, linksetsResponderPtr, LLSD())); -			if (doRequestTerrain) +            if (doRequestTerrain)  			{ -				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); -				LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); +                std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetTerrainCoro", +                    boost::bind(&LLPathfindingManager::linksetTerrainCoro, this, terrainLinksetsURL, linksetsResponderPtr, LLSD()));  			}  		}  	} @@ -432,18 +303,18 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP  		{  			pLinksetsCallback(pRequestId, kRequestStarted, emptyLinksetListPtr); -			LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined())); +			LinksetsResponder::ptr_t linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined()));  			if (!objectPostData.isUndefined())  			{ -				LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); -				LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); +                std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetObjectsCoro", +                    boost::bind(&LLPathfindingManager::linksetObjectsCoro, this, objectLinksetsURL, linksetsResponderPtr, objectPostData));  			}  			if (!terrainPostData.isUndefined())  			{ -				LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); -				LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); +                std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetTerrainCoro", +                    boost::bind(&LLPathfindingManager::linksetTerrainCoro, this, terrainLinksetsURL, linksetsResponderPtr, terrainPostData));  			}  		}  	} @@ -475,8 +346,8 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_  		{  			pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); -			LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback); -			LLHTTPClient::get(charactersURL, charactersResponder); +            std::string coroname = LLCoros::instance().launch("LLPathfindingManager::charactersCoro", +                boost::bind(&LLPathfindingManager::charactersCoro, this, charactersURL, pRequestId, pCharactersCallback));  		}  	}  } @@ -508,8 +379,9 @@ void LLPathfindingManager::requestGetAgentState()  		{  			std::string agentStateURL = getAgentStateURLForRegion(currentRegion);  			llassert(!agentStateURL.empty()); -			LLHTTPClient::ResponderPtr responder = new AgentStateResponder(); -			LLHTTPClient::get(agentStateURL, responder); + +            std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navAgentStateRequestCoro", +                boost::bind(&LLPathfindingManager::navAgentStateRequestCoro, this, agentStateURL));  		}  	}  } @@ -530,35 +402,9 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak  	{  		std::string navMeshStatusURL = getNavMeshStatusURLForCurrentRegion();  		llassert(!navMeshStatusURL.empty()); -		LLSD postData;			 -		postData["command"] = "rebuild"; -		LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback); -		LLHTTPClient::post(navMeshStatusURL, postData, responder); -	} -} - -void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, const LLPathfindingNavMeshStatus &pNavMeshStatus) -{ -	if ((pRegion == NULL) || !pRegion->isAlive()) -	{ -		navMeshPtr->handleNavMeshNotEnabled(); -	} -	else -	{ -		std::string navMeshURL = getRetrieveNavMeshURLForRegion(pRegion); - -		if (navMeshURL.empty()) -		{ -			navMeshPtr->handleNavMeshNotEnabled(); -		} -		else -		{ -			navMeshPtr->handleNavMeshStart(pNavMeshStatus); -			LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr); -			LLSD postData; -			LLHTTPClient::post(navMeshURL, postData, responder); -		} +        std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navMeshRebakeCoro", +                boost::bind(&LLPathfindingManager::navMeshRebakeCoro, this, navMeshStatusURL, pRebakeNavMeshCallback));  	}  } @@ -602,29 +448,250 @@ void LLPathfindingManager::handleDeferredGetCharactersForRegion(const LLUUID &pR  	}  } -void LLPathfindingManager::handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly) +void LLPathfindingManager::navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly)  { -	LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pNavMeshStatus.getRegionUUID()); +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavMeshStatusRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +    if (!region) +    { +        LL_WARNS("PathfindingManager") << "Attempting to retrieve navmesh status for region that has gone away." << LL_ENDL; +        return; +    } +    LLUUID regionUUID = region->getRegionID(); + +    region = NULL; +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    region = LLWorld::getInstance()->getRegionFromHandle(regionHandle); -	if (!pNavMeshStatus.isValid()) -	{ -		navMeshPtr->handleNavMeshError(); -	} -	else -	{ -		if (navMeshPtr->hasNavMeshVersion(pNavMeshStatus)) -		{ -			navMeshPtr->handleRefresh(pNavMeshStatus); -		} -		else if (pIsGetStatusOnly) -		{ -			navMeshPtr->handleNavMeshNewVersion(pNavMeshStatus); -		} -		else -		{ -			sendRequestGetNavMeshForRegion(navMeshPtr, pRegion, pNavMeshStatus); -		} -	} +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    LLPathfindingNavMeshStatus navMeshStatus(regionUUID); +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() <<  +            ". Building using empty status." << LL_ENDL; +    } +    else +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        navMeshStatus = LLPathfindingNavMeshStatus(regionUUID, result); +    } + +    LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(regionUUID); + +    if (!navMeshStatus.isValid()) +    { +        navMeshPtr->handleNavMeshError(); +        return; +    } +    else if (navMeshPtr->hasNavMeshVersion(navMeshStatus)) +    { +        navMeshPtr->handleRefresh(navMeshStatus); +        return; +    } +    else if (isGetStatusOnly) +    { +        navMeshPtr->handleNavMeshNewVersion(navMeshStatus); +        return; +    } + +    if ((!region) || !region->isAlive()) +    { +        LL_WARNS("PathfindingManager") << "About to update navmesh status for region that has gone away." << LL_ENDL; +        navMeshPtr->handleNavMeshNotEnabled(); +        return; +    } + +    std::string navMeshURL = getRetrieveNavMeshURLForRegion(region); + +    if (navMeshURL.empty()) +    { +        navMeshPtr->handleNavMeshNotEnabled(); +        return; +    } + +    navMeshPtr->handleNavMeshStart(navMeshStatus); + +    LLSD postData; +    result = httpAdapter->postAndYield(httpRequest, navMeshURL, postData); + +    U32 navMeshVersion = navMeshStatus.getVersion(); + +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << +            ". reporting error." << LL_ENDL; +        navMeshPtr->handleNavMeshError(navMeshVersion); +    } +    else +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        navMeshPtr->handleNavMeshResult(result, navMeshVersion); + +    } + +} + +void LLPathfindingManager::navAgentStateRequestCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavAgentStateRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    bool canRebake = false; +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << +            ". Building using empty status." << LL_ENDL; +    } +    else +    { +        llassert(result.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); +        llassert(result.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); +        canRebake = result.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); +    } + +    handleAgentState(canRebake); +} + +void LLPathfindingManager::navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavMeshRebake", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + +    LLSD postData = LLSD::emptyMap(); +    postData["command"] = "rebuild"; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    bool success = true; +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << +            ". Rebake failed." << LL_ENDL; +        success = false; +    } +        +    rebakeNavMeshCallback(success); +} + +// If called with putData undefined this coroutine will issue a get.  If there  +// is data in putData it will be PUT to the URL. +void LLPathfindingManager::linksetObjectsCoro(std::string url, LinksetsResponder::ptr_t linksetsResponsderPtr, LLSD putData) const +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetObjects", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result; + +    if (putData.isUndefined()) +    { +        result = httpAdapter->getAndYield(httpRequest, url); +    } +    else  +    { +        result = httpAdapter->putAndYield(httpRequest, url, putData); +    } + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << +            ". linksetObjects failed." << LL_ENDL; +        linksetsResponsderPtr->handleObjectLinksetsError(); +    } +    else +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        linksetsResponsderPtr->handleObjectLinksetsResult(result); +    } +} + +// If called with putData undefined this coroutine will issue a GET.  If there  +// is data in putData it will be PUT to the URL. +void LLPathfindingManager::linksetTerrainCoro(std::string url, LinksetsResponder::ptr_t linksetsResponsderPtr, LLSD putData) const +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result; + +    if (putData.isUndefined()) +    { +        result = httpAdapter->getAndYield(httpRequest, url); +    } +    else  +    { +        result = httpAdapter->putAndYield(httpRequest, url, putData); +    } + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << +            ". linksetTerrain failed." << LL_ENDL; +        linksetsResponsderPtr->handleTerrainLinksetsError(); +    } +    else +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        linksetsResponsderPtr->handleTerrainLinksetsResult(result); +    } + +} + +void LLPathfindingManager::charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << +            ". characters failed." << LL_ENDL; + +        LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); +        callback(requestId, LLPathfindingManager::kRequestError, characterListPtr); +    } +    else +    { +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(result)); +        callback(requestId, LLPathfindingManager::kRequestCompleted, characterListPtr); +    }  }  void LLPathfindingManager::handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus) @@ -765,121 +832,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c  }  //--------------------------------------------------------------------------- -// NavMeshStatusResponder -//--------------------------------------------------------------------------- - -NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly) -	: LLHTTPClient::Responder(), -	mRegion(pRegion), -	mRegionUUID(), -	mIsGetStatusOnly(pIsGetStatusOnly) -{ -	if (mRegion != NULL) -	{ -		mRegionUUID = mRegion->getRegionID(); -	} -} - -NavMeshStatusResponder::~NavMeshStatusResponder() -{ -} - -void NavMeshStatusResponder::httpSuccess() -{ -	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent()); -	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); -} - -void NavMeshStatusResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -	LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID); -	LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); -} - -//--------------------------------------------------------------------------- -// NavMeshResponder -//--------------------------------------------------------------------------- - -NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) -	: LLHTTPClient::Responder(), -	mNavMeshVersion(pNavMeshVersion), -	mNavMeshPtr(pNavMeshPtr) -{ -} - -NavMeshResponder::~NavMeshResponder() -{ -} - -void NavMeshResponder::httpSuccess() -{ -	mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion); -} - -void NavMeshResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -	mNavMeshPtr->handleNavMeshError(mNavMeshVersion); -} - -//--------------------------------------------------------------------------- -// AgentStateResponder -//--------------------------------------------------------------------------- - -AgentStateResponder::AgentStateResponder() -: LLHTTPClient::Responder() -{ -} - -AgentStateResponder::~AgentStateResponder() -{ -} - -void AgentStateResponder::httpSuccess() -{ -	const LLSD& pContent = getContent(); -	llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); -	llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); -	BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); -	LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion); -} - -void AgentStateResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -	LLPathfindingManager::getInstance()->handleAgentState(FALSE); -} - - -//--------------------------------------------------------------------------- -// navmesh rebake responder -//--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) -	: LLHTTPClient::Responder(), -	mRebakeNavMeshCallback(pRebakeNavMeshCallback) -{ -} - -NavMeshRebakeResponder::~NavMeshRebakeResponder() -{ -} - -void NavMeshRebakeResponder::httpSuccess() -{ -	mRebakeNavMeshCallback(true); -} - -void NavMeshRebakeResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -	mRebakeNavMeshCallback(false); -} - -//---------------------------------------------------------------------------  // LinksetsResponder  //--------------------------------------------------------------------------- -  LinksetsResponder::LinksetsResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested)  	: mRequestId(pRequestId),  	mLinksetsCallback(pLinksetsCallback), @@ -957,82 +911,3 @@ void LinksetsResponder::sendCallback()  	mLinksetsCallback(mRequestId, requestStatus, mObjectLinksetListPtr);  } - -//--------------------------------------------------------------------------- -// ObjectLinksetsResponder -//--------------------------------------------------------------------------- - -ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) -	: LLHTTPClient::Responder(), -	mLinksetsResponsderPtr(pLinksetsResponsderPtr) -{ -} - -ObjectLinksetsResponder::~ObjectLinksetsResponder() -{ -} - -void ObjectLinksetsResponder::httpSuccess() -{ -	mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent()); -} - -void ObjectLinksetsResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -	mLinksetsResponsderPtr->handleObjectLinksetsError(); -} - -//--------------------------------------------------------------------------- -// TerrainLinksetsResponder -//--------------------------------------------------------------------------- - -TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) -	: LLHTTPClient::Responder(), -	mLinksetsResponsderPtr(pLinksetsResponsderPtr) -{ -} - -TerrainLinksetsResponder::~TerrainLinksetsResponder() -{ -} - -void TerrainLinksetsResponder::httpSuccess() -{ -	mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent()); -} - -void TerrainLinksetsResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; -	mLinksetsResponsderPtr->handleTerrainLinksetsError(); -} - -//--------------------------------------------------------------------------- -// CharactersResponder -//--------------------------------------------------------------------------- - -CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) -	: LLHTTPClient::Responder(), -	mRequestId(pRequestId), -	mCharactersCallback(pCharactersCallback) -{ -} - -CharactersResponder::~CharactersResponder() -{ -} - -void CharactersResponder::httpSuccess() -{ -	LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent())); -	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr); -} - -void CharactersResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; - -	LLPathfindingObjectListPtr characterListPtr =  LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); -	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); -} diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h index c61ff244fc..e8fad590ba 100755 --- a/indra/newview/llpathfindingmanager.h +++ b/indra/newview/llpathfindingmanager.h @@ -37,11 +37,15 @@  #include "llpathfindingobjectlist.h"  #include "llpathfindingnavmesh.h"  #include "llsingleton.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLPathfindingNavMeshStatus;  class LLUUID;  class LLViewerRegion; +class LinksetsResponder; +  class LLPathfindingManager : public LLSingleton<LLPathfindingManager>  {  	friend class LLNavMeshSimStateChangeNode; @@ -92,16 +96,22 @@ public:  protected:  private: -	typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap; -	void sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, const LLPathfindingNavMeshStatus &pNavMeshStatus); +	typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap;  	void handleDeferredGetAgentStateForRegion(const LLUUID &pRegionUUID);  	void handleDeferredGetNavMeshForRegion(const LLUUID &pRegionUUID, bool pIsGetStatusOnly);  	void handleDeferredGetLinksetsForRegion(const LLUUID &pRegionUUID, request_id_t pRequestId, object_request_callback_t pLinksetsCallback) const;  	void handleDeferredGetCharactersForRegion(const LLUUID &pRegionUUID, request_id_t pRequestId, object_request_callback_t pCharactersCallback) const; -	void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly); +    void navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly); +    void navAgentStateRequestCoro(std::string url); +    void navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback); +    void linksetObjectsCoro(std::string url, boost::shared_ptr<LinksetsResponder> linksetsResponsderPtr, LLSD putData) const; +    void linksetTerrainCoro(std::string url, boost::shared_ptr<LinksetsResponder> linksetsResponsderPtr, LLSD putData) const; +    void charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const; + +	//void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly);  	void handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus);  	void handleAgentState(BOOL pCanRebakeRegion); diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index e92bf4590d..467e9df482 100755 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -32,31 +32,10 @@  #include "llagent.h"  // for gAgent  #include "lltrans.h"  #include "llviewerregion.h" +#include "llcorehttputil.h" -class LLProductInfoRequestResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLProductInfoRequestResponder); -private: -	//If we get back a normal response, handle it here -	/* virtual */ void httpSuccess() -	{ -		const LLSD& content = getContent(); -		if (!content.isArray()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		LLProductInfoRequestManager::instance().setSkuDescriptions(getContent()); -	} - -	//If we get back an error (not found, etc...), handle it here -	/* virtual */ void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -	} -}; - -LLProductInfoRequestManager::LLProductInfoRequestManager() : mSkuDescriptions() +LLProductInfoRequestManager::LLProductInfoRequestManager():  +    mSkuDescriptions()  {  } @@ -65,15 +44,11 @@ void LLProductInfoRequestManager::initSingleton()  	std::string url = gAgent.getRegion()->getCapability("ProductInfoRequest");  	if (!url.empty())  	{ -		LLHTTPClient::get(url, new LLProductInfoRequestResponder()); +        LLCoros::instance().launch("LLProductInfoRequestManager::getLandDescriptionsCoro", +            boost::bind(&LLProductInfoRequestManager::getLandDescriptionsCoro, this, url));  	}  } -void LLProductInfoRequestManager::setSkuDescriptions(const LLSD& content) -{ -	mSkuDescriptions = content; -} -  std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string& sku)  {  	// The description LLSD is an array of maps; each array entry @@ -90,3 +65,31 @@ std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string&  	}  	return LLTrans::getString("land_type_unknown");  } + +void LLProductInfoRequestManager::getLandDescriptionsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        return; +    } + +    if (result.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT) && +        result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT].isArray()) +    { +        mSkuDescriptions = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; +    } +    else +    { +        LL_WARNS() << "Land SKU description response is malformed" << LL_ENDL; +    } +} diff --git a/indra/newview/llproductinforequest.h b/indra/newview/llproductinforequest.h index fe8f7093b0..75dbf220d1 100755 --- a/indra/newview/llproductinforequest.h +++ b/indra/newview/llproductinforequest.h @@ -28,27 +28,29 @@  #ifndef LL_LLPRODUCTINFOREQUEST_H  #define LL_LLPRODUCTINFOREQUEST_H -#include "llhttpclient.h"  #include "llmemory.h" +#include "lleventcoro.h" +#include "llcoros.h" -/*  - This is a singleton to manage a cache of information about land types. - The land system provides a capability to get information about the - set of possible land sku, name, and description information. - We use description in the UI, but the sku is provided in the various - messages; this tool provides translation between the systems. +/**  + * This is a singleton to manage a cache of information about land types. + * The land system provides a capability to get information about the + * set of possible land sku, name, and description information. + * We use description in the UI, but the sku is provided in the various + * messages; this tool provides translation between the systems.   */ -  class LLProductInfoRequestManager : public LLSingleton<LLProductInfoRequestManager>  {  public:  	LLProductInfoRequestManager(); -	void setSkuDescriptions(const LLSD& content);  	std::string getDescriptionForSku(const std::string& sku); +  private:  	friend class LLSingleton<LLProductInfoRequestManager>;	  	/* virtual */ void initSingleton(); -	LLSD mSkuDescriptions; + +    void getLandDescriptionsCoro(std::string url); +    LLSD mSkuDescriptions;  };  #endif // LL_LLPRODUCTINFOREQUEST_H diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 29dcc12f9e..06bf90c7cb 100755 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -31,55 +31,16 @@  #include "message.h"  #include "llpanel.h" -#include "llhttpclient.h"  #include "llsdserialize.h"  #include "llurlentry.h"  #include "llviewerregion.h"  #include "llview.h" - +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llregionhandle.h"  #include "llagent.h"  #include "llremoteparcelrequest.h" - - -LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle) -	 : mObserverHandle(observer_handle) -{} - -//If we get back a normal response, handle it here -//virtual -void LLRemoteParcelRequestResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap() || !content.has("parcel_id")) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	LLUUID parcel_id = getContent()["parcel_id"]; - -	// Panel inspecting the information may be closed and destroyed -	// before this response is received. -	LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); -	if (observer) -	{ -		observer->setParcelID(parcel_id); -	} -} - -//If we get back an error (not found, etc...), handle it here -//virtual -void LLRemoteParcelRequestResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; - -	// Panel inspecting the information may be closed and destroyed -	// before this response is received. -	LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); -	if (observer) -	{ -		observer->setErrorStatus(getStatus(), getReason()); -	} -} +#include "llcorehttputil.h"  void LLRemoteParcelInfoProcessor::addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer)  { @@ -200,3 +161,64 @@ void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id)  	msg->addUUID("ParcelID", parcel_id);  	gAgent.sendReliableMessage();  } + +bool LLRemoteParcelInfoProcessor::requestRegionParcelInfo(const std::string &url,  +    const LLUUID ®ionId, const LLVector3 ®ionPos, const LLVector3d&globalPos, +    LLHandle<LLRemoteParcelInfoObserver> observerHandle) +{ + +    if (!url.empty()) +    { +        LLCoros::instance().launch("LLRemoteParcelInfoProcessor::regionParcelInfoCoro", +            boost::bind(&LLRemoteParcelInfoProcessor::regionParcelInfoCoro, this, url, +            regionId, regionPos, globalPos, observerHandle)); +        return true; +    } + +    return false; +} + +void LLRemoteParcelInfoProcessor::regionParcelInfoCoro(std::string url,  +    LLUUID regionId, LLVector3 posRegion, LLVector3d posGlobal,  +    LLHandle<LLRemoteParcelInfoObserver> observerHandle) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("RemoteParcelRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD bodyData; + +    bodyData["location"] = ll_sd_from_vector3(posRegion); +    if (!regionId.isNull()) +    { +        bodyData["region_id"] = regionId; +    } +    if (!posGlobal.isExactlyZero()) +    { +        U64 regionHandle = to_region_handle(posGlobal); +        bodyData["region_handle"] = ll_sd_from_U64(regionHandle); +    } + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, bodyData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    LLRemoteParcelInfoObserver* observer = observerHandle.get(); +    // Panel inspecting the information may be closed and destroyed +    // before this response is received. +    if (!observer) +        return; + +    if (!status) +    { +        observer->setErrorStatus(status.getStatus(), status.getMessage()); +    } +    else  +    { +        LLUUID parcel_id = result["parcel_id"]; +        observer->setParcelID(parcel_id); +    } + +} diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index 35348b69ff..cb5af50c5f 100755 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -29,29 +29,14 @@  #ifndef LL_LLREMOTEPARCELREQUEST_H  #define LL_LLREMOTEPARCELREQUEST_H -#include "llhttpclient.h"  #include "llhandle.h"  #include "llsingleton.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLMessageSystem;  class LLRemoteParcelInfoObserver; -class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLRemoteParcelRequestResponder); -public: -	LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle); - -private: -	//If we get back a normal response, handle it here -	/*virtual*/ void httpSuccess(); - -	//If we get back an error (not found, etc...), handle it here -	/*virtual*/ void httpFailure(); - -	LLHandle<LLRemoteParcelInfoObserver> mObserverHandle; -}; -  struct LLParcelData  {  	LLUUID		parcel_id; @@ -99,9 +84,14 @@ public:  	static void processParcelInfoReply(LLMessageSystem* msg, void**); +    bool requestRegionParcelInfo(const std::string &url, const LLUUID ®ionId,  +        const LLVector3 ®ionPos, const LLVector3d& globalPos, LLHandle<LLRemoteParcelInfoObserver> observerHandle); +  private:  	typedef std::multimap<LLUUID, LLHandle<LLRemoteParcelInfoObserver> > observer_multimap_t;  	observer_multimap_t mObservers; + +    void regionParcelInfoCoro(std::string url, LLUUID regionId, LLVector3 posRegion, LLVector3d posGlobal, LLHandle<LLRemoteParcelInfoObserver> observerHandle);  };  #endif // LL_LLREMOTEPARCELREQUEST_H diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 0ae8a338e0..bbb5db4a0a 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -1004,9 +1004,23 @@ void LLSnapshotLivePreview::saveTexture()  		LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL);  		std::string who_took_it;  		LLAgentUI::buildFullname(who_took_it); -		LLAssetStorage::LLStoreAssetCallback callback = NULL;  		S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); -		void *userdata = NULL; +#if 1 +        std::string name = "Snapshot: " + pos_string; +        std::string desc = "Taken by " + who_took_it + " at " + pos_string; + +        NewResourceUploadInfo::ptr_t assetUploadInfo(new NewResourceUploadInfo( +            tid, LLAssetType::AT_TEXTURE, name, desc, 0, +            LLFolderType::FT_SNAPSHOT_CATEGORY, LLInventoryType::IT_SNAPSHOT, +            PERM_ALL, LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), +            expected_upload_cost)); + +        upload_new_resource(assetUploadInfo); + +#else +        LLAssetStorage::LLStoreAssetCallback callback = NULL; +        void *userdata = NULL; +  		upload_new_resource(tid,	// tid  			LLAssetType::AT_TEXTURE,  			"Snapshot : " + pos_string, @@ -1019,6 +1033,7 @@ void LLSnapshotLivePreview::saveTexture()  			LLFloaterPerms::getEveryonePerms("Uploads"),  			"Snapshot : " + pos_string,  			callback, expected_upload_cost, userdata); +#endif  		gViewerWindow->playSnapshotAnimAndSound();  	}  	else diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 7867e1573c..3b060d8343 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -34,11 +34,11 @@  #include "llgroupmgr.h"  #include "llsdutil.h"  #include "lluicolortable.h" -#include "llhttpclient.h"  #include "llviewerobjectlist.h"  #include "llviewerregion.h"  #include "llvoavatar.h"  #include "llworld.h" +#include "llcorehttputil.h"  extern LLControlGroup gSavedSettings; @@ -265,49 +265,6 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id)  }  // -// ModerationResponder -// - -class ModerationResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(ModerationResponder); -public: -	ModerationResponder(const LLUUID& session_id) -	{ -		mSessionID = session_id; -	} -	 -protected: -	virtual void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -		 -		if ( gIMMgr ) -		{ -			//403 == you're not a mod -			//should be disabled if you're not a moderator -			if ( HTTP_FORBIDDEN == getStatus() ) -			{ -				gIMMgr->showSessionEventError( -											  "mute", -											  "not_a_mod_error", -											  mSessionID); -			} -			else -			{ -				gIMMgr->showSessionEventError( -											  "mute", -											  "generic_request_error", -											  mSessionID); -			} -		} -	} -	 -private: -	LLUUID mSessionID; -}; - -//  // LLSpeakerMgr  // @@ -883,7 +840,8 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id)  	//current value represents ability to type, so invert  	data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; -	LLHTTPClient::post(url, data, new ModerationResponder(getSessionID())); +    LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", +        boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data));  }  void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute) @@ -907,10 +865,50 @@ void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmu  	data["params"]["mute_info"] = LLSD::emptyMap();  	data["params"]["mute_info"]["voice"] = !unmute; -	LLHTTPClient::post( -		url, -		data, -		new ModerationResponder(getSessionID())); +    LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", +        boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); +} + +void LLIMSpeakerMgr::moderationActionCoro(std::string url, LLSD action) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("moderationActionCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); + +    LLUUID sessionId = action["session-id"]; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, action, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        if (gIMMgr) +        { +            //403 == you're not a mod +            //should be disabled if you're not a moderator +            if (status == LLCore::HttpStatus(HTTP_FORBIDDEN)) +            { +                gIMMgr->showSessionEventError( +                    "mute", +                    "not_a_mod_error", +                    sessionId); +            } +            else +            { +                gIMMgr->showSessionEventError( +                    "mute", +                    "generic_request_error", +                    sessionId); +            } +        } +        return; +    }  }  void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone ) @@ -949,7 +947,8 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo  	data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap();  	data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; -	LLHTTPClient::post(url, data, new ModerationResponder(session_id)); +    LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", +        boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data));  }  void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted) diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 0e69184125..5cff70f377 100755 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -30,6 +30,8 @@  #include "llevent.h"  #include "lleventtimer.h"  #include "llvoicechannel.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLSpeakerMgr; @@ -333,6 +335,8 @@ protected:  	 */  	void forceVoiceModeratedMode(bool should_be_muted); +    void moderationActionCoro(std::string url, LLSD action); +  };  class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr> diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index 802dff1ead..7f286044d6 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -31,70 +31,11 @@  #include "llsyntaxid.h"  #include "llagent.h"  #include "llappviewer.h" -#include "llhttpclient.h"  #include "llsdserialize.h"  #include "llviewerregion.h" +#include "llcorehttputil.h"  //----------------------------------------------------------------------------- -// fetchKeywordsFileResponder -//----------------------------------------------------------------------------- -class fetchKeywordsFileResponder : public LLHTTPClient::Responder -{ -public: -	fetchKeywordsFileResponder(const std::string& filespec) -	: mFileSpec(filespec) -	{ -		LL_DEBUGS("SyntaxLSL") << "Instantiating with file saving to: '" << filespec << "'" << LL_ENDL; -	} - -	/* virtual */ void httpFailure() -	{ -		LL_WARNS("SyntaxLSL") << "failed to fetch syntax file [status:" << getStatus() << "]: " << getContent() << LL_ENDL; -	} - -	/* virtual */ void httpSuccess() -	{ -		// Continue only if a valid LLSD object was returned. -		const LLSD& content = getContent(); -		if (content.isMap()) -		{ -			if (LLSyntaxIdLSL::getInstance()->isSupportedVersion(content)) -			{ -				LLSyntaxIdLSL::getInstance()->setKeywordsXml(content); - -				cacheFile(content); -				LLSyntaxIdLSL::getInstance()->handleFileFetched(mFileSpec); -			} -			else -			{ -				LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL; -			} -		} -		else -		{ -			LL_WARNS("SyntaxLSL") << "Syntax file '" << mFileSpec << "' contains invalid LLSD." << LL_ENDL; -		} -	} - -	void cacheFile(const LLSD& content_ref) -	{ -		std::stringstream str; -		LLSDSerialize::toXML(content_ref, str); -		const std::string xml = str.str(); - -		// save the str to disk, usually to the cache. -		llofstream file(mFileSpec.c_str(), std::ios_base::out); -		file.write(xml.c_str(), str.str().size()); -		file.close(); - -		LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << mFileSpec << "'" << LL_ENDL; -	} -	 -private: -	std::string mFileSpec; -}; -	 -//-----------------------------------------------------------------------------  // LLSyntaxIdLSL  //-----------------------------------------------------------------------------  const std::string SYNTAX_ID_CAPABILITY_NAME = "LSLSyntax"; @@ -166,13 +107,72 @@ bool LLSyntaxIdLSL::syntaxIdChanged()  //-----------------------------------------------------------------------------  void LLSyntaxIdLSL::fetchKeywordsFile(const std::string& filespec)  { -	mInflightFetches.push_back(filespec); -	LLHTTPClient::get(mCapabilityURL, -					  new fetchKeywordsFileResponder(filespec), -					  LLSD(), 30.f); +    LLCoros::instance().launch("LLSyntaxIdLSL::fetchKeywordsFileCoro", +        boost::bind(&LLSyntaxIdLSL::fetchKeywordsFileCoro, this, mCapabilityURL, filespec));  	LL_DEBUGS("SyntaxLSL") << "LSLSyntaxId capability URL is: " << mCapabilityURL << ". Filename to use is: '" << filespec << "'." << LL_ENDL;  } +//----------------------------------------------------------------------------- +// fetchKeywordsFileCoro +//----------------------------------------------------------------------------- +void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    std::pair<std::set<std::string>::iterator, bool> insrt = mInflightFetches.insert(fileSpec); +    if (!insrt.second) +    { +        LL_WARNS("SyntaxLSL") << "Already downloading keyword file called \"" << fileSpec << "\"." << LL_ENDL; +        return; +    } + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    mInflightFetches.erase(fileSpec); + +    if (!status) +    { +        LL_WARNS("SyntaxLSL") << "Failed to fetch syntax file \"" << fileSpec << "\"" << LL_ENDL; +        return; +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + +    if (isSupportedVersion(result)) +    { +        setKeywordsXml(result); +        cacheFile(fileSpec, result); +        loadKeywordsIntoLLSD(); +    } +    else +    { +        LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL; +    } + +} + +//----------------------------------------------------------------------------- +// cacheFile +//----------------------------------------------------------------------------- +void LLSyntaxIdLSL::cacheFile(const std::string &fileSpec, const LLSD& content_ref) +{ +    std::stringstream str; +    LLSDSerialize::toXML(content_ref, str); +    const std::string xml = str.str(); + +    // save the str to disk, usually to the cache. +    llofstream file(fileSpec.c_str(), std::ios_base::out); +    file.write(xml.c_str(), str.str().size()); +    file.close(); + +    LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << fileSpec << "'" << LL_ENDL; +}  //-----------------------------------------------------------------------------  // initialize @@ -260,8 +260,8 @@ void LLSyntaxIdLSL::loadDefaultKeywordsIntoLLSD()  // loadKeywordsFileIntoLLSD  //-----------------------------------------------------------------------------  /** - * @brief	Load xml serialised LLSD - * @desc	Opens the specified filespec and attempts to deserialise the + * @brief	Load xml serialized LLSD + * @desc	Opens the specified filespec and attempts to deserializes the   *			contained data to the specified LLSD object. indicate success/failure with   *			sLoaded/sLoadFailed members.   */ @@ -276,7 +276,7 @@ void LLSyntaxIdLSL::loadKeywordsIntoLLSD()  		{  			if (isSupportedVersion(content))  			{ -				LL_DEBUGS("SyntaxLSL") << "Deserialised: " << mFullFileSpec << LL_ENDL; +				LL_DEBUGS("SyntaxLSL") << "Deserialized: " << mFullFileSpec << LL_ENDL;  			}  			else  			{ @@ -317,12 +317,6 @@ void LLSyntaxIdLSL::handleCapsReceived(const LLUUID& region_uuid)  	}  } -void LLSyntaxIdLSL::handleFileFetched(const std::string& filepath) -{ -	mInflightFetches.remove(filepath); -	loadKeywordsIntoLLSD(); -} -  boost::signals2::connection LLSyntaxIdLSL::addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb)  {  	return mSyntaxIDChangedSignal.connect(cb); diff --git a/indra/newview/llsyntaxid.h b/indra/newview/llsyntaxid.h index 504fb0997e..0afa6dc04b 100644 --- a/indra/newview/llsyntaxid.h +++ b/indra/newview/llsyntaxid.h @@ -31,6 +31,8 @@  #include "llviewerprecompiledheaders.h"  #include "llsingleton.h" +#include "lleventcoro.h" +#include "llcoros.h"  class fetchKeywordsFileResponder; @@ -40,7 +42,7 @@ class LLSyntaxIdLSL : public LLSingleton<LLSyntaxIdLSL>  	friend class fetchKeywordsFileResponder;  private: -	std::list<std::string> mInflightFetches; +    std::set<std::string> mInflightFetches;  	typedef boost::signals2::signal<void()> syntax_id_changed_signal_t;  	syntax_id_changed_signal_t mSyntaxIDChangedSignal;  	boost::signals2::connection mRegionChangedCallback; @@ -49,13 +51,15 @@ private:  	bool	isSupportedVersion(const LLSD& content);  	void	handleRegionChanged();  	void	handleCapsReceived(const LLUUID& region_uuid); -	void	handleFileFetched(const std::string& filepath);  	void	setKeywordsXml(const LLSD& content) { mKeywordsXml = content; };  	void	buildFullFileSpec();  	void	fetchKeywordsFile(const std::string& filespec);  	void	loadDefaultKeywordsIntoLLSD();  	void	loadKeywordsIntoLLSD(); -	 + +    void    fetchKeywordsFileCoro(std::string url, std::string fileSpec); +    void    cacheFile(const std::string &fileSpec, const LLSD& content_ref); +  	std::string		mCapabilityURL;  	std::string		mFullFileSpec;  	ELLPath			mFilePath; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index fab4203ec3..f4b1ff7313 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -35,7 +35,6 @@  #include "lltexturefetch.h"  #include "lldir.h" -#include "llhttpclient.h"  #include "llhttpconstants.h"  #include "llimage.h"  #include "llimagej2c.h" diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp index e983bc883f..c6a0a15759 100644 --- a/indra/newview/lltwitterconnect.cpp +++ b/indra/newview/lltwitterconnect.cpp @@ -32,7 +32,6 @@  #include "llagent.h"  #include "llcallingcard.h"			// for LLAvatarTracker  #include "llcommandhandler.h" -#include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llurlaction.h"  #include "llimagepng.h" @@ -43,6 +42,7 @@  #include "llfloaterwebcontent.h"  #include "llfloaterreg.h" +#include "llcorehttputil.h"  boost::scoped_ptr<LLEventPump> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState"));  boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo")); @@ -67,228 +67,311 @@ void toast_user_for_twitter_success()  ///////////////////////////////////////////////////////////////////////////////  // -class LLTwitterConnectResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterConnectCoro(std::string requestToken, std::string oauthVerifier)  { -	LOG_CLASS(LLTwitterConnectResponder); -public: -	 -    LLTwitterConnectResponder() +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    LLSD body; +    if (!requestToken.empty()) +        body["request_token"] = requestToken; +    if (!oauthVerifier.empty()) +        body["oauth_verifier"] = oauthVerifier; + +    setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); + +    LLSD result = httpAdapter->putAndYield(httpRequest, getTwitterConnectURL("/connection"), body, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status)      { -        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); +        if ( status == LLCore::HttpStatus(HTTP_FOUND) ) +        { +            std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +            if (location.empty()) +            { +                LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; +            } +            else +            { +                openTwitterWeb(location); +            } +        } +        else +        { +            LL_WARNS("TwitterConnect") << "Connection failed " << status.toString() << LL_ENDL; +            setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); +            log_twitter_connect_error("Connect", status.getStatus(), status.toString(), +                result.get("error_code"), result.get("error_description")); +        }      } -     -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; -        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); -	} -     -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -                LLTwitterConnect::instance().openTwitterWeb(location); -			} -		} -		else -		{ -			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; -			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); -			const LLSD& content = getContent(); -			log_twitter_connect_error("Connect", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    else +    { +        LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL; +        setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLTwitterShareResponder : public LLHTTPClient::Responder +bool LLTwitterConnect::testShareStatus(LLSD &result)  { -	LOG_CLASS(LLTwitterShareResponder); -public: -     -	LLTwitterShareResponder() -	{ -		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTING); -	} -	 -	/* virtual */ void httpSuccess() -	{ +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status) +        return true; + +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openTwitterWeb(location); +        } +    } +    if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) +    { +        LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL; +        connectToTwitter(); +    } +    else +    { +        LL_WARNS("TwitterConnect") << "HTTP Status error " << status.toString() << LL_ENDL; +        setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED); +        log_twitter_connect_error("Share", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    return false; +} + +void LLTwitterConnect::twitterShareCoro(std::string route, LLSD share) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    setConnectionState(LLTwitterConnect::TWITTER_POSTING); + +    LLSD result = httpAdapter->postAndYield(httpRequest, getTwitterConnectURL(route, true), share, httpOpts); + +    if (testShareStatus(result)) +    {          toast_user_for_twitter_success(); -		LL_DEBUGS("TwitterConnect") << "Post successful. " << dumpResponse() << LL_ENDL; -        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTED); -	} -     -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -                LLTwitterConnect::instance().openTwitterWeb(location); -			} -		} -		else if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LLTwitterConnect::instance().connectToTwitter(); -		} -		else -		{ -			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; -            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED); -			const LLSD& content = getContent(); -			log_twitter_connect_error("Share", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +        LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL; +        setConnectionState(LLTwitterConnect::TWITTER_POSTED); +    } +} + +void LLTwitterConnect::twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    std::string imageFormat; +    if (dynamic_cast<LLImagePNG*>(image.get())) +    { +        imageFormat = "png"; +    } +    else if (dynamic_cast<LLImageJPEG*>(image.get())) +    { +        imageFormat = "jpg"; +    } +    else +    { +        LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; +        return; +    } + +    // All this code is mostly copied from LLWebProfile::post() +    const std::string boundary = "----------------------------0123abcdefab"; + +    std::string contentType = "multipart/form-data; boundary=" + boundary; +    httpHeaders->append("Content-Type", contentType.c_str()); + +    LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); //  +    LLCore::BufferArrayStream body(raw.get()); + +    // *NOTE: The order seems to matter. +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"status\"\r\n\r\n" +        << status << "\r\n"; + +    body << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" +        << "Content-Type: image/" << imageFormat << "\r\n\r\n"; + +    // Insert the image data. +    // *FIX: Treating this as a string will probably screw it up ... +    U8* image_data = image->getData(); +    for (S32 i = 0; i < image->getDataSize(); ++i) +    { +        body << image_data[i]; +    } + +    body << "\r\n--" << boundary << "--\r\n"; + +    LLSD result = httpAdapter->postAndYield(httpRequest, getTwitterConnectURL("/share/photo", true), raw, httpOpts, httpHeaders); + +    if (testShareStatus(result)) +    { +        toast_user_for_twitter_success(); +        LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL; +        setConnectionState(LLTwitterConnect::TWITTER_POSTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLTwitterDisconnectResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterDisconnectCoro()  { -	LOG_CLASS(LLTwitterDisconnectResponder); -public: -  -	LLTwitterDisconnectResponder() -	{ -		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING); -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	void setUserDisconnected() -	{ -		// Clear data -		LLTwitterConnect::instance().clearInfo(); +    httpOpts->setFollowRedirects(false); -		//Notify state change -		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); -	} +    setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING); -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; -		setUserDisconnected(); -	} -     -	/* virtual */ void httpFailure() -	{ -		//User not found so already disconnected -		if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LL_DEBUGS("TwitterConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; -			setUserDisconnected(); -		} -		else -		{ -			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; -			LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED); -			const LLSD& content = getContent(); -			log_twitter_connect_error("Disconnect", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    LLSD result = httpAdapter->deleteAndYield(httpRequest, getTwitterConnectURL("/connection"), httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND))) +    { +        LL_WARNS("TwitterConnect") << "Disconnect failed!" << LL_ENDL; +        setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED); + +        log_twitter_connect_error("Disconnect", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else +    { +        LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << LL_ENDL; +        clearInfo(); +        setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLTwitterConnectedResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterConnectedCoro(bool autoConnect)  { -	LOG_CLASS(LLTwitterConnectedResponder); -public: -     -	LLTwitterConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + +    httpOpts->setFollowRedirects(false); +    setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); + +    LLSD result = httpAdapter->getAndYield(httpRequest, getTwitterConnectURL("/connection", true), httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status)      { -		LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); +        if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) +        { +            LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL; +            if (autoConnect) +            { +                connectToTwitter(); +            } +            else +            { +                setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); +            } +        } +        else +        { +            LL_WARNS("TwitterConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; + +            setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); +            log_twitter_connect_error("Connected", status.getStatus(), status.toString(), +                result.get("error_code"), result.get("error_description")); +        } +    } +    else +    { +        LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL; +        setConnectionState(LLTwitterConnect::TWITTER_CONNECTED);      } -     -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; -        LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); -	} -     -	/* virtual */ void httpFailure() -	{ -		// show the facebook login page if not connected yet -		if ( HTTP_NOT_FOUND == getStatus() ) -		{ -			LL_DEBUGS("TwitterConnect") << "Not connected. " << dumpResponse() << LL_ENDL; -			if (mAutoConnect) -			{ -                LLTwitterConnect::instance().connectToTwitter(); -			} -			else -			{ -                LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); -			} -		} -		else -		{ -			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; -            LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); -			const LLSD& content = getContent(); -			log_twitter_connect_error("Connected", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -     -private: -	bool mAutoConnect; -}; + +}  ///////////////////////////////////////////////////////////////////////////////  // -class LLTwitterInfoResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterInfoCoro()  { -	LOG_CLASS(LLTwitterInfoResponder); -public: +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); -	/* virtual */ void httpSuccess() -	{ -		LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL; -		LL_DEBUGS("TwitterConnect") << "Getting Twitter info successful. " << dumpResponse() << LL_ENDL; -        LLTwitterConnect::instance().storeInfo(getContent()); -	} -     -	/* virtual */ void httpFailure() -	{ -		if ( HTTP_FOUND == getStatus() ) -		{ -			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (location.empty()) -			{ -				LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse() -                << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			} -			else -			{ -                LLTwitterConnect::instance().openTwitterWeb(location); -			} -		} -		else -		{ -			LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; -			const LLSD& content = getContent(); -			log_twitter_connect_error("Info", getStatus(), getReason(), -									   content.get("error_code"), content.get("error_description")); -		} -	} -}; +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); + +    LLSD result = httpAdapter->getAndYield(httpRequest, getTwitterConnectURL("/info", true), httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status == LLCore::HttpStatus(HTTP_FOUND)) +    { +        std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; +        if (location.empty()) +        { +            LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL; +        } +        else +        { +            openTwitterWeb(location); +        } +    } +    else if (!status) +    { +        LL_WARNS("TwitterConnect") << "Twitter Info failed: " << status.toString() << LL_ENDL; +        log_twitter_connect_error("Info", status.getStatus(), status.toString(), +            result.get("error_code"), result.get("error_description")); +    } +    else +    { +        LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL; +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +        storeInfo(result); +    } +}  ///////////////////////////////////////////////////////////////////////////////  // @@ -341,36 +424,28 @@ std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, boo  void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier)  { -	LLSD body; -	if (!request_token.empty()) -		body["request_token"] = request_token; -	if (!oauth_verifier.empty()) -		body["oauth_verifier"] = oauth_verifier; -     -	LLHTTPClient::put(getTwitterConnectURL("/connection"), body, new LLTwitterConnectResponder()); +    LLCoros::instance().launch("LLTwitterConnect::twitterConnectCoro", +        boost::bind(&LLTwitterConnect::twitterConnectCoro, this, request_token, oauth_verifier));  }  void LLTwitterConnect::disconnectFromTwitter()  { -	LLHTTPClient::del(getTwitterConnectURL("/connection"), new LLTwitterDisconnectResponder()); +    LLCoros::instance().launch("LLTwitterConnect::twitterDisconnectCoro", +        boost::bind(&LLTwitterConnect::twitterDisconnectCoro, this));  }  void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect)  { -	const bool follow_redirects = false; -	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -	LLHTTPClient::get(getTwitterConnectURL("/connection", true), new LLTwitterConnectedResponder(auto_connect), -						LLSD(), timeout, follow_redirects); +    LLCoros::instance().launch("LLTwitterConnect::twitterConnectedCoro", +        boost::bind(&LLTwitterConnect::twitterConnectedCoro, this, auto_connect));  }  void LLTwitterConnect::loadTwitterInfo()  {  	if(mRefreshInfo)  	{ -		const bool follow_redirects = false; -		const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; -		LLHTTPClient::get(getTwitterConnectURL("/info", true), new LLTwitterInfoResponder(), -			LLSD(), timeout, follow_redirects); +        LLCoros::instance().launch("LLTwitterConnect::twitterInfoCoro", +            boost::bind(&LLTwitterConnect::twitterInfoCoro, this));  	}  } @@ -379,62 +454,15 @@ void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::stri  	LLSD body;  	body["image"] = image_url;  	body["status"] = status; -	 -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::post(getTwitterConnectURL("/share/photo", true), body, new LLTwitterShareResponder()); + +    LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro", +        boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/photo", body));  }  void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status)  { -	std::string imageFormat; -	if (dynamic_cast<LLImagePNG*>(image.get())) -	{ -		imageFormat = "png"; -	} -	else if (dynamic_cast<LLImageJPEG*>(image.get())) -	{ -		imageFormat = "jpg"; -	} -	else -	{ -		LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; -		return; -	} -	 -	// All this code is mostly copied from LLWebProfile::post() -	const std::string boundary = "----------------------------0123abcdefab"; - -	LLSD headers; -	headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; - -	std::ostringstream body; - -	// *NOTE: The order seems to matter. -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"status\"\r\n\r\n" -			<< status << "\r\n"; - -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" -			<< "Content-Type: image/" << imageFormat << "\r\n\r\n"; - -	// Insert the image data. -	// *FIX: Treating this as a string will probably screw it up ... -	U8* image_data = image->getData(); -	for (S32 i = 0; i < image->getDataSize(); ++i) -	{ -		body << image_data[i]; -	} - -	body <<	"\r\n--" << boundary << "--\r\n"; - -	// postRaw() takes ownership of the buffer and releases it later. -	size_t size = body.str().size(); -	U8 *data = new U8[size]; -	memcpy(data, body.str().data(), size); -	 -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::postRaw(getTwitterConnectURL("/share/photo", true), data, size, new LLTwitterShareResponder(), headers); +    LLCoros::instance().launch("LLTwitterConnect::twitterShareImageCoro", +        boost::bind(&LLTwitterConnect::twitterShareImageCoro, this, image, status));  }  void LLTwitterConnect::updateStatus(const std::string& status) @@ -442,8 +470,8 @@ void LLTwitterConnect::updateStatus(const std::string& status)  	LLSD body;  	body["status"] = status; -    // Note: we can use that route for different publish action. We should be able to use the same responder. -	LLHTTPClient::post(getTwitterConnectURL("/share/status", true), body, new LLTwitterShareResponder()); +    LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro", +        boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/status", body));  }  void LLTwitterConnect::storeInfo(const LLSD& info) diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h index c1df13f18c..be481a17c1 100644 --- a/indra/newview/lltwitterconnect.h +++ b/indra/newview/lltwitterconnect.h @@ -30,6 +30,8 @@  #include "llsingleton.h"  #include "llimage.h" +#include "llcoros.h" +#include "lleventcoro.h"  class LLEventPump; @@ -94,6 +96,14 @@ private:  	static boost::scoped_ptr<LLEventPump> sStateWatcher;  	static boost::scoped_ptr<LLEventPump> sInfoWatcher;  	static boost::scoped_ptr<LLEventPump> sContentWatcher; + +    bool testShareStatus(LLSD &result); +    void twitterConnectCoro(std::string requestToken, std::string oauthVerifier); +    void twitterDisconnectCoro(); +    void twitterConnectedCoro(bool autoConnect); +    void twitterInfoCoro(); +    void twitterShareCoro(std::string route, LLSD share); +    void twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status);  };  #endif // LL_LLTWITTERCONNECT_H diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp deleted file mode 100755 index 69b9b1f9f1..0000000000 --- a/indra/newview/lluploadfloaterobservers.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file lluploadfloaterobservers.cpp - * @brief LLUploadModelPermissionsResponder definition - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lluploadfloaterobservers.h" - -LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) -:mObserverHandle(observer) -{ -} - -void LLUploadModelPermissionsResponder::httpFailure() -{ -	LL_WARNS() << dumpResponse() << LL_ENDL; - -	LLUploadPermissionsObserver* observer = mObserverHandle.get(); - -	if (observer) -	{ -		observer->setPermissonsErrorStatus(getStatus(), getReason()); -	} -} - -void LLUploadModelPermissionsResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	LLUploadPermissionsObserver* observer = mObserverHandle.get(); - -	if (observer) -	{ -		observer->onPermissionsReceived(content); -	} -} - diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 4ff4a827a5..02baf8f1c0 100755 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -79,18 +79,4 @@ protected:  	LLRootHandle<LLWholeModelUploadObserver> mWholeModelUploadObserverHandle;  }; - -class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLUploadModelPermissionsResponder); -public: -	LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); - -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); - -	LLHandle<LLUploadPermissionsObserver> mObserverHandle; -}; -  #endif /* LL_LLUPLOADFLOATEROBSERVERS_H */ diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp new file mode 100644 index 0000000000..717b14bb72 --- /dev/null +++ b/indra/newview/llviewerassetupload.cpp @@ -0,0 +1,205 @@ +/** +* @file llviewerassetupload.cpp +* @author optional +* @brief brief description of the file +* +* $LicenseInfo:firstyear=2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2011, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "linden_common.h" +#include "llviewerassetupload.h" +#include "llviewertexturelist.h" +#include "llimage.h" +#include "lltrans.h" +#include "lluuid.h" +#include "llvorbisencode.h" +#include "lluploaddialog.h" +#include "llpreviewscript.h" +#include "llnotificationsutil.h" +#include "lleconomy.h" +#include "llagent.h" +#include "llfloaterreg.h" +#include "llstatusbar.h" +#include "llinventorypanel.h" +#include "llsdutil.h" + +//========================================================================= +/*static*/ +void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, const LLUUID &id, +    std::string url, NewResourceUploadInfo::ptr_t uploadInfo) +{ +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = uploadInfo->prepareUpload(); +    uploadInfo->logPreparedUpload(); + +    if (result.has("error")) +    { +        HandleUploadError(LLCore::HttpStatus(499), result, uploadInfo); +        return; +    } + +    //self.yield(); + +    std::string uploadMessage = "Uploading...\n\n"; +    uploadMessage.append(uploadInfo->getDisplayName()); +    LLUploadDialog::modalUploadDialog(uploadMessage); + +    LLSD body = uploadInfo->generatePostBody(); + +    result = httpAdapter->postAndYield(httpRequest, url, body); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if ((!status) || (result.has("error"))) +    { +        HandleUploadError(status, result, uploadInfo); +        LLUploadDialog::modalUploadFinished(); +        return; +    } + +    std::string uploader = result["uploader"].asString(); + +    result = httpAdapter->postFileAndYield(httpRequest, uploader, uploadInfo->getAssetId(), uploadInfo->getAssetType()); +    httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        HandleUploadError(status, result, uploadInfo); +        LLUploadDialog::modalUploadFinished(); +        return; +    } + +    S32 uploadPrice = 0; + +    // Update L$ and ownership credit information +    // since it probably changed on the server +    if (uploadInfo->getAssetType() == LLAssetType::AT_TEXTURE || +        uploadInfo->getAssetType() == LLAssetType::AT_SOUND || +        uploadInfo->getAssetType() == LLAssetType::AT_ANIMATION || +        uploadInfo->getAssetType() == LLAssetType::AT_MESH) +    { +        uploadPrice = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); +    } + +    bool success = false; + +    if (uploadPrice > 0) +    { +        // this upload costed us L$, update our balance +        // and display something saying that it cost L$ +        LLStatusBar::sendMoneyBalanceRequest(); + +        LLSD args; +        args["AMOUNT"] = llformat("%d", uploadPrice); +        LLNotificationsUtil::add("UploadPayment", args); +    } + +    LLUUID serverInventoryItem = uploadInfo->finishUpload(result); + +    if (serverInventoryItem.notNull()) +    { +        success = true; + +        // Show the preview panel for textures and sounds to let +        // user know that the image (or snapshot) arrived intact. +        LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); +        if (panel) +        { +            LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); +            panel->setSelection(serverInventoryItem, TAKE_FOCUS_NO); + +            // restore keyboard focus +            gFocusMgr.setKeyboardFocus(focus); +        } +    } +    else +    { +        LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; +    } + +    // remove the "Uploading..." message +    LLUploadDialog::modalUploadFinished(); + +    // Let the Snapshot floater know we have finished uploading a snapshot to inventory. +    LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); +    if (uploadInfo->getAssetType() == LLAssetType::AT_TEXTURE && floater_snapshot) +    { +        floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory"))); +    } +} + +//========================================================================= +/*static*/ +void LLViewerAssetUpload::HandleUploadError(LLCore::HttpStatus status, LLSD &result, NewResourceUploadInfo::ptr_t &uploadInfo) +{ +    std::string reason; +    std::string label("CannotUploadReason"); + +    LL_WARNS() << ll_pretty_print_sd(result) << LL_ENDL; + +    if (result.has("label")) +    { +        label = result["label"].asString(); +    } + +    if (result.has("message")) +    { +        reason = result["message"].asString(); +    } +    else +    { +        if (status.getType() == 499) +        { +            reason = "The server is experiencing unexpected difficulties."; +        } +        else +        { +            reason = "Error in upload request.  Please visit " +                "http://secondlife.com/support for help fixing this problem."; +        } +    } + +    LLSD args; +    args["FILE"] = uploadInfo->getDisplayName(); +    args["REASON"] = reason; + +    LLNotificationsUtil::add(label, args); + +    // unfreeze script preview +    if (uploadInfo->getAssetType() == LLAssetType::AT_LSL_TEXT) +    { +        LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script",  +            uploadInfo->getItemId()); +        if (preview) +        { +            LLSD errors; +            errors.append(LLTrans::getString("UploadFailed") + reason); +            preview->callbackLSLCompileFailed(errors); +        } +    } + +} diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h new file mode 100644 index 0000000000..38167fc0c7 --- /dev/null +++ b/indra/newview/llviewerassetupload.h @@ -0,0 +1,51 @@ +/** +* @file llviewerassetupload.h +* @author optional +* @brief brief description of the file +* +* $LicenseInfo:firstyear=2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2011, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#ifndef LL_VIEWER_ASSET_UPLOAD_H +#define LL_VIEWER_ASSET_UPLOAD_H + +#include "llfoldertype.h" +#include "llassettype.h" +#include "llinventorytype.h" +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h" + +#include "llviewermenufile.h" + +class LLViewerAssetUpload +{ +public: + +    static void AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, const LLUUID &id, +        std::string url, NewResourceUploadInfo::ptr_t uploadInfo); + +private: +    static void HandleUploadError(LLCore::HttpStatus status, LLSD &result, NewResourceUploadInfo::ptr_t &uploadInfo); +}; + +#endif // !VIEWER_ASSET_UPLOAD_H diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp deleted file mode 100755 index e390e8776d..0000000000 --- a/indra/newview/llviewerdisplayname.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/**  - * @file llviewerdisplayname.cpp - * @brief Wrapper for display name functionality - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerdisplayname.h" - -// viewer includes -#include "llagent.h" -#include "llviewerregion.h" -#include "llvoavatar.h" - -// library includes -#include "llavatarnamecache.h" -#include "llhttpclient.h" -#include "llhttpnode.h" -#include "llnotificationsutil.h" -#include "llui.h"					// getLanguage() - -namespace LLViewerDisplayName -{ -	// Fired when viewer receives server response to display name change -	set_name_signal_t sSetDisplayNameSignal; - -	// Fired when there is a change in the agent's name -	name_changed_signal_t sNameChangedSignal; - -	void addNameChangedCallback(const name_changed_signal_t::slot_type& cb)  -	{  -		sNameChangedSignal.connect(cb);  -	} - -	void doNothing() { } -} - -class LLSetDisplayNameResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLSetDisplayNameResponder); -private: -	// only care about errors -	/*virtual*/ void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -		LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); -		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); -	} -}; - -void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) -{ -	// TODO: simple validation here - -	LLViewerRegion* region = gAgent.getRegion(); -	llassert(region); -	std::string cap_url = region->getCapability("SetDisplayName"); -	if (cap_url.empty()) -	{ -		// this server does not support display names, report error -		slot(false, "unsupported", LLSD()); -		return; -	} - -	// People API can return localized error messages.  Indicate our -	// language preference via header. -	LLSD headers; -	headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage(); - -	// People API requires both the old and new value to change a variable. -	// Our display name will be in cache before the viewer's UI is available -	// to request a change, so we can use direct lookup without callback. -	LLAvatarName av_name; -	if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) -	{ -		slot(false, "name unavailable", LLSD()); -		return; -	} - -	// People API expects array of [ "old value", "new value" ] -	LLSD change_array = LLSD::emptyArray(); -	change_array.append(av_name.getDisplayName()); -	change_array.append(display_name); -	 -	LL_INFOS() << "Set name POST to " << cap_url << LL_ENDL; - -	// Record our caller for when the server sends back a reply -	sSetDisplayNameSignal.connect(slot); -	 -	// POST the requested change.  The sim will not send a response back to -	// this request directly, rather it will send a separate message after it -	// communicates with the back-end. -	LLSD body; -	body["display_name"] = change_array; -	LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); -} - -class LLSetDisplayNameReply : public LLHTTPNode -{ -	LOG_CLASS(LLSetDisplayNameReply); -public: -	/*virtual*/ void post( -		LLHTTPNode::ResponsePtr response, -		const LLSD& context, -		const LLSD& input) const -	{ -		LLSD body = input["body"]; - -		S32 status = body["status"].asInteger(); -		bool success = (status == HTTP_OK); -		std::string reason = body["reason"].asString(); -		LLSD content = body["content"]; - -		LL_INFOS() << "status " << status << " reason " << reason << LL_ENDL; - -		// If viewer's concept of display name is out-of-date, the set request -		// will fail with 409 Conflict.  If that happens, fetch up-to-date -		// name information. -		if (status == HTTP_CONFLICT) -		{ -			LLUUID agent_id = gAgent.getID(); -			// Flush stale data -			LLAvatarNameCache::erase( agent_id ); -			// Queue request for new data: nothing to do on callback though... -			// Note: no need to disconnect the callback as it never gets out of scope -			LLAvatarNameCache::get(agent_id, boost::bind(&LLViewerDisplayName::doNothing)); -			// Kill name tag, as it is wrong -			LLVOAvatar::invalidateNameTag( agent_id ); -		} - -		// inform caller of result -		LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content); -		LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); -	} -}; - - -class LLDisplayNameUpdate : public LLHTTPNode -{ -	/*virtual*/ void post( -		LLHTTPNode::ResponsePtr response, -		const LLSD& context, -		const LLSD& input) const -	{ -		LLSD body = input["body"]; -		LLUUID agent_id = body["agent_id"]; -		std::string old_display_name = body["old_display_name"]; -		// By convention this record is called "agent" in the People API -		LLSD name_data = body["agent"]; - -		// Inject the new name data into cache -		LLAvatarName av_name; -		av_name.fromLLSD( name_data ); - -		LL_INFOS() << "name-update now " << LLDate::now() -			<< " next_update " << LLDate(av_name.mNextUpdate) -			<< LL_ENDL; - -		// Name expiration time may be provided in headers, or we may use a -		// default value -		// *TODO: get actual headers out of ResponsePtr -		//LLSD headers = response->mHeaders; -		LLSD headers; -		av_name.mExpires =  -			LLAvatarNameCache::nameExpirationFromHeaders(headers); - -		LLAvatarNameCache::insert(agent_id, av_name); - -		// force name tag to update -		LLVOAvatar::invalidateNameTag(agent_id); - -		LLSD args; -		args["OLD_NAME"] = old_display_name; -		args["SLID"] = av_name.getUserName(); -		args["NEW_NAME"] = av_name.getDisplayName(); -		LLNotificationsUtil::add("DisplayNameUpdate", args); -		if (agent_id == gAgent.getID()) -		{ -			LLViewerDisplayName::sNameChangedSignal(); -		} -	} -}; - -LLHTTPRegistration<LLSetDisplayNameReply> -    gHTTPRegistrationMessageSetDisplayNameReply( -		"/message/SetDisplayNameReply"); - -LLHTTPRegistration<LLDisplayNameUpdate> -    gHTTPRegistrationMessageDisplayNameUpdate( -		"/message/DisplayNameUpdate"); diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h deleted file mode 100755 index 16d59ae43b..0000000000 --- a/indra/newview/llviewerdisplayname.h +++ /dev/null @@ -1,53 +0,0 @@ -/**  - * @file llviewerdisplayname.h - * @brief Wrapper for display name functionality - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LLVIEWERDISPLAYNAME_H -#define LLVIEWERDISPLAYNAME_H - -#include <boost/signals2.hpp> - -class LLSD; -class LLUUID; - -namespace LLViewerDisplayName -{ -	typedef boost::signals2::signal< -		void (bool success, const std::string& reason, const LLSD& content)> -			set_name_signal_t; -	typedef set_name_signal_t::slot_type set_name_slot_t; -	 -	typedef boost::signals2::signal<void (void)> name_changed_signal_t; -	typedef name_changed_signal_t::slot_type name_changed_slot_t; - -	// Sends an update to the server to change a display name -	// and call back when done.  May not succeed due to service -	// unavailable or name not available. -	void set(const std::string& display_name, const set_name_slot_t& slot);  -	 -	void addNameChangedCallback(const name_changed_signal_t::slot_type& cb); -} - -#endif // LLVIEWERDISPLAYNAME_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 1dad9dd506..8627c848b5 100755 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -56,7 +56,6 @@  #include "llfloaterconversationpreview.h"  #include "llfloaterdeleteenvpreset.h"  #include "llfloaterdestinations.h" -#include "llfloaterdisplayname.h"  #include "llfloatereditdaycycle.h"  #include "llfloatereditsky.h"  #include "llfloatereditwater.h" @@ -244,7 +243,6 @@ void LLViewerFloaterReg::registerFloaters()  	LLInspectRemoteObjectUtil::registerFloater();  	LLFloaterVoiceVolumeUtil::registerFloater();  	LLNotificationsUI::registerFloater(); -	LLFloaterDisplayNameUtil::registerFloater();  	LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>);  	LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d112118082..9a20dea2aa 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1750,27 +1750,20 @@ void copy_inventory_from_notecard(const LLUUID& destination_id,          return;      } -	// check capability to prevent a crash while LL_ERRS in LLCapabilityListener::capListener. See EXT-8459. -	std::string url = viewer_region->getCapability("CopyInventoryFromNotecard"); -	if (url.empty()) -	{ -        LL_WARNS(LOG_NOTECARD) << "There is no 'CopyInventoryFromNotecard' capability" -							   << " for region: " << viewer_region->getName() -							   << LL_ENDL; -		return; -	} - -    LLSD request, body; +    LLSD body;      body["notecard-id"] = notecard_inv_id;      body["object-id"] = object_id;      body["item-id"] = src->getUUID();  	body["folder-id"] = destination_id;      body["callback-id"] = (LLSD::Integer)callback_id; -    request["message"] = "CopyInventoryFromNotecard"; -    request["payload"] = body; - -    viewer_region->getCapAPI().post(request); +    /// *TODO: RIDER: This posts the request under the agents policy.   +    /// When I convert the inventory over this call should be moved under that  +    /// policy as well. +    if (!gAgent.requestPostCapability("CopyInventoryFromNotecard", body)) +    { +        LL_WARNS() << "SIM does not have the capability to copy from notecard." << LL_ENDL; +    }  }  void create_new_item(const std::string& name, diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 3eae0f8d86..f332a4e98e 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -69,6 +69,7 @@  #include "llwebprofile.h"  #include "llwindow.h"  #include "llvieweraudio.h" +#include "llcorehttputil.h"  #include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows. @@ -152,190 +153,6 @@ LLViewerMediaObserver::~LLViewerMediaObserver()  } -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLMimeDiscoveryResponder); -public: -	LLMimeDiscoveryResponder( viewer_media_t media_impl) -		: mMediaImpl(media_impl), -		  mInitialized(false) -	{ -		if(mMediaImpl->mMimeTypeProbe != NULL) -		{ -			LL_ERRS() << "impl already has an outstanding responder" << LL_ENDL; -		} -		 -		mMediaImpl->mMimeTypeProbe = this; -	} - -	~LLMimeDiscoveryResponder() -	{ -		disconnectOwner(); -	} - -private: -	/* virtual */ void httpCompleted() -	{ -		if (!isGoodStatus()) -		{ -			LL_WARNS() << dumpResponse() -					<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; -		} -		const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); -		std::string::size_type idx1 = media_type.find_first_of(";"); -		std::string mime_type = media_type.substr(0, idx1); - -		LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL; -		 -		// 2xx status codes indicate success. -		// Most 4xx status codes are successful enough for our purposes. -		// 499 is the error code for host not found, timeout, etc. -		// 500 means "Internal Server error" but we decided it's okay to  -		//     accept this and go past it in the MIME type probe -		// 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com -		// 499 is a code specifc to join.secondlife.com apparently safe to ignore -//		if(	((status >= 200) && (status < 300))	|| -//			((status >= 400) && (status < 499))	||  -//			(status == 500) || -//			(status == 302) || -//			(status == 499)  -//			) -		// We now no longer check the error code returned from the probe. -		// If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting. -		//if(1) -		{ -			// The probe was successful. -			if(mime_type.empty()) -			{ -				// Some sites don't return any content-type header at all. -				// Treat an empty mime type as text/html. -				mime_type = HTTP_CONTENT_TEXT_HTML; -			} -		} -		//else -		//{ -		//	LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL; -		// -		//	if(mMediaImpl) -		//	{ -		//		mMediaImpl->mMediaSourceFailed = true; -		//	} -		//	return; -		//} - -		// the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. -		// Make a local copy so we can call loadURI() afterwards. -		LLViewerMediaImpl *impl = mMediaImpl; -		 -		if(impl && !mInitialized && ! mime_type.empty()) -		{ -			if(impl->initializeMedia(mime_type)) -			{ -				mInitialized = true; -				impl->loadURI(); -				disconnectOwner(); -			} -		} -	} -	 -public: -	void cancelRequest() -	{ -		disconnectOwner(); -	} -	 -private: -	void disconnectOwner() -	{ -		if(mMediaImpl) -		{ -			if(mMediaImpl->mMimeTypeProbe != this) -			{ -				LL_ERRS() << "internal error: mMediaImpl->mMimeTypeProbe != this" << LL_ENDL; -			} - -			mMediaImpl->mMimeTypeProbe = NULL; -		} -		mMediaImpl = NULL; -	} -	 -	 -public: -		LLViewerMediaImpl *mMediaImpl; -		bool mInitialized; -}; - -class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLViewerMediaOpenIDResponder); -public: -	LLViewerMediaOpenIDResponder( ) -	{ -	} - -	~LLViewerMediaOpenIDResponder() -	{ -	} - -	/* virtual */ void completedRaw( -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer) -	{ -		// We don't care about the content of the response, only the Set-Cookie header. -		LL_DEBUGS("MediaAuth") << dumpResponse()  -				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; -		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); -		 -		// *TODO: What about bad status codes?  Does this destroy previous cookies? -		LLViewerMedia::openIDCookieResponse(cookie); -	} - -}; - -class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLViewerMediaWebProfileResponder); -public: -	LLViewerMediaWebProfileResponder(std::string host) -	{ -		mHost = host; -	} - -	~LLViewerMediaWebProfileResponder() -	{ -	} - -	 void completedRaw( -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer) -	{ -		// We don't care about the content of the response, only the set-cookie header. -		LL_WARNS("MediaAuth") << dumpResponse()  -				<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - -		LLSD stripped_content = getResponseHeaders(); -		// *TODO: Check that this works. -		stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE); -		LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; - -		const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); -		LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; - -		// *TODO: What about bad status codes?  Does this destroy previous cookies? -		LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); - -		// Set cookie for snapshot publishing. -		std::string auth_cookie = cookie.substr(0, cookie.find(";")); // strip path -		LLWebProfile::setAuthCookie(auth_cookie); -	} - -	std::string mHost; -}; - -  LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;  LLURL LLViewerMedia::sOpenIDURL;  std::string LLViewerMedia::sOpenIDCookie; @@ -1388,87 +1205,172 @@ LLSD LLViewerMedia::getHeaders()  	return headers;  } +LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders() +{ +    LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders); + +    headers->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); +    headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML); +    headers->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie); +    headers->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent()); + +    return headers; +} +  /////////////////////////////////////////////////////////////////////////////////////////  // static  void LLViewerMedia::setOpenIDCookie()  {  	if(!sOpenIDCookie.empty())  	{ -		// The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] -		// We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. -		// We therefore do it here. -		std::string authority = sOpenIDURL.mAuthority; -		std::string::size_type host_start = authority.find('@');  -		if(host_start == std::string::npos) -		{ -			// no username/password -			host_start = 0; -		} -		else -		{ -			// Hostname starts after the @.  -			// (If the hostname part is empty, this may put host_start at the end of the string.  In that case, it will end up passing through an empty hostname, which is correct.) -			++host_start; -		} -		std::string::size_type host_end = authority.rfind(':');  -		if((host_end == std::string::npos) || (host_end < host_start)) -		{ -			// no port -			host_end = authority.size(); -		} -		 -		getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); +        std::string profileUrl = getProfileURL(""); + +        LLCoros::instance().launch("LLViewerMedia::getOpenIDCookieCoro", +            boost::bind(&LLViewerMedia::getOpenIDCookieCoro, profileUrl)); +	} +} + +/*static*/ +void LLViewerMedia::getOpenIDCookieCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getOpenIDCookieCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +     +    httpOpts->setFollowRedirects(true); +    httpOpts->setWantHeaders(true); + +    LLURL hostUrl(url.c_str()); +    std::string hostAuth = hostUrl.getAuthority(); + +    // *TODO: Expand LLURL to split and extract this information better.  +    // The structure of a URL is well defined and needing to retrieve parts of it are common. +    // original comment: +    // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] +    // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. +    // We therefore do it here. +    std::string authority = sOpenIDURL.mAuthority; +    std::string::size_type hostStart = authority.find('@'); +    if (hostStart == std::string::npos) +    {   // no username/password +        hostStart = 0; +    } +    else +    {   // Hostname starts after the @.  +        // (If the hostname part is empty, this may put host_start at the end of the string.  In that case, it will end up passing through an empty hostname, which is correct.) +        ++hostStart; +    } +    std::string::size_type hostEnd = authority.rfind(':'); +    if ((hostEnd == std::string::npos) || (hostEnd < hostStart)) +    {   // no port +        hostEnd = authority.size(); +    } -		// Do a web profile get so we can store the cookie  -		LLSD headers = LLSD::emptyMap(); -		headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; -		headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; -		headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); +    getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(hostStart, hostEnd - hostStart)); -		std::string profile_url = getProfileURL(""); -		LLURL raw_profile_url( profile_url.c_str() ); +    // Do a web profile get so we can store the cookie  +    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); +    httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie); +    httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent()); + + +    LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL; +    LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL; +     +    LLSD result = httpAdapter->getRawAndYield(httpRequest, url, httpOpts, httpHeaders); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("MediaAuth") << "Error getting web profile." << LL_ENDL; +        return; +    } + +    LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +    if (!resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE)) +    { +        LL_WARNS("MediaAuth") << "No cookie in response." << LL_ENDL; +        return; +    } + +    const std::string& cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asStringRef(); +    LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; + +    // *TODO: What about bad status codes?  Does this destroy previous cookies? +    LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, hostAuth); + +    // Set cookie for snapshot publishing. +    std::string authCookie = cookie.substr(0, cookie.find(";")); // strip path +    LLWebProfile::setAuthCookie(authCookie); -		LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << LL_ENDL; -		LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL; -		LLHTTPClient::get(profile_url,   -			new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), -			headers); -	}  }  /////////////////////////////////////////////////////////////////////////////////////////  // static -void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +void LLViewerMedia::openIDSetup(const std::string &openidUrl, const std::string &openidToken)  { -	LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; +	LL_DEBUGS("MediaAuth") << "url = \"" << openidUrl << "\", token = \"" << openidToken << "\"" << LL_ENDL; -	// post the token to the url  -	// the responder will need to extract the cookie(s). +    LLCoros::instance().launch("LLViewerMedia::openIDSetupCoro", +        boost::bind(&LLViewerMedia::openIDSetupCoro, openidUrl, openidToken)); +} -	// Save the OpenID URL for later -- we may need the host when adding the cookie. -	sOpenIDURL.init(openid_url.c_str()); -	 -	// We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. -	sOpenIDCookie.clear(); +/*static*/ +void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidToken) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("openIDSetupCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); -	LLSD headers = LLSD::emptyMap(); -	// Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header -	headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; -	// and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" -	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded"; - -	// postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. -	size_t size = openid_token.size(); -	U8 *data = new U8[size]; -	memcpy(data, openid_token.data(), size); - -	LLHTTPClient::postRaw(  -		openid_url,  -		data,  -		size,  -		new LLViewerMediaOpenIDResponder(), -		headers); -			 +    httpOpts->setWantHeaders(true); + +    // post the token to the url  +    // the responder will need to extract the cookie(s). +    // Save the OpenID URL for later -- we may need the host when adding the cookie. +    sOpenIDURL.init(openidUrl.c_str()); +    // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. +    sOpenIDCookie.clear(); + +    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); +    httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded"); + +    LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); +    LLCore::BufferArrayStream bas(rawbody.get()); + +    bas << std::noskipws << openidToken; + +    LLSD result = httpAdapter->postRawAndYield(httpRequest, openidUrl, rawbody, httpOpts, httpHeaders); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("MediaAuth") << "Error getting Open ID cookie" << LL_ENDL; +        return; +    } + +    LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +    if (!resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE)) +    { +        LL_WARNS("MediaAuth") << "No cookie in response." << LL_ENDL; +        return; +    } + +    // We don't care about the content of the response, only the Set-Cookie header. +    const std::string &cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE]; + +    // *TODO: What about bad status codes?  Does this destroy previous cookies? +    LLViewerMedia::openIDCookieResponse(cookie); +    LL_DEBUGS("MediaAuth") << "OpenID cookie set." << LL_ENDL;  }  ///////////////////////////////////////////////////////////////////////////////////////// @@ -1661,7 +1563,6 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,  	mIsParcelMedia(false),  	mProximity(-1),  	mProximityDistance(0.0f), -	mMimeTypeProbe(NULL),  	mMediaAutoPlay(false),  	mInNearbyMediaList(false),  	mClearCache(false), @@ -1671,8 +1572,10 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,  	mIsUpdated(false),  	mTrustedBrowser(false),  	mZoomFactor(1.0), -    mCleanBrowser(false) -{  +    mCleanBrowser(false), +    mMimeProbe(), +    mCanceling(false) +{  	// Set up the mute list observer if it hasn't been set up already.  	if(!sViewerMediaMuteListObserverInitialized) @@ -2610,7 +2513,8 @@ void LLViewerMediaImpl::navigateInternal()  		return;  	} -	if(mMimeTypeProbe != NULL) +     +    if (!mMimeProbe.expired())  	{  		LL_WARNS() << "MIME type probe already in progress -- bailing out." << LL_ENDL;  		return; @@ -2648,14 +2552,8 @@ void LLViewerMediaImpl::navigateInternal()  		if(scheme.empty() || "http" == scheme || "https" == scheme)  		{ -			// If we don't set an Accept header, LLHTTPClient will add one like this: -			//    Accept: application/llsd+xml -			// which is really not what we want. -			LLSD headers = LLSD::emptyMap(); -			headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; -			// Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com -			headers[HTTP_OUT_HEADER_COOKIE] = ""; -			LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); +            LLCoros::instance().launch("LLViewerMediaImpl::mimeDiscoveryCoro", +                boost::bind(&LLViewerMediaImpl::mimeDiscoveryCoro, this, mMediaURL));  		}  		else if("data" == scheme || "file" == scheme || "about" == scheme)  		{ @@ -2685,6 +2583,66 @@ void LLViewerMediaImpl::navigateInternal()  	}  } +void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("mimeDiscoveryCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + +    mMimeProbe = httpAdapter; + +    httpOpts->setFollowRedirects(true); +    httpOpts->setHeadersOnly(true); + +    httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); +    httpHeaders->append(HTTP_OUT_HEADER_COOKIE, ""); + +    LLSD result = httpAdapter->getRawAndYield(httpRequest, url, httpOpts, httpHeaders); + +    mMimeProbe.reset(); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS() << "Error retrieving media headers." << LL_ENDL; +    } + +    LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; +     +    const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE].asStringRef(); + +    std::string::size_type idx1 = mediaType.find_first_of(";"); +    std::string mimeType = mediaType.substr(0, idx1); + +    // We now no longer need to check the error code returned from the probe. +    // If we have a mime type, use it.  If not, default to the web plugin and let it handle error reporting. +    // The probe was successful. +    if (mimeType.empty()) +    { +        // Some sites don't return any content-type header at all. +        // Treat an empty mime type as text/html. +        mimeType = HTTP_CONTENT_TEXT_HTML; +    } + +    LL_DEBUGS() << "Media type \"" << mediaType << "\", mime type is \"" << mimeType << "\"" << LL_ENDL; + +    // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. +    // Make a local copy so we can call loadURI() afterwards. + +    if (!mimeType.empty()) +    { +        if (initializeMedia(mimeType)) +        { +            loadURI(); +        } +    } +} +  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::navigateStop()  { @@ -2783,7 +2741,7 @@ void LLViewerMediaImpl::update()  		{  			// Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state.  		} -		else if(mMimeTypeProbe != NULL) +        else if (!mMimeProbe.expired())  		{  			// this media source is doing a MIME type probe -- don't try loading it again.  		} @@ -3673,18 +3631,10 @@ void LLViewerMediaImpl::setNavigateSuspended(bool suspend)  void LLViewerMediaImpl::cancelMimeTypeProbe()  { -	if(mMimeTypeProbe != NULL) -	{ -		// There doesn't seem to be a way to actually cancel an outstanding request. -		// Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. -		mMimeTypeProbe->cancelRequest(); -		 -		// The above should already have set mMimeTypeProbe to NULL. -		if(mMimeTypeProbe != NULL) -		{ -			LL_ERRS() << "internal error: mMimeTypeProbe is not NULL after cancelling request." << LL_ENDL; -		} -	} +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t probeAdapter = mMimeProbe.lock(); + +    if (probeAdapter) +        probeAdapter->cancelYieldingOperation();  }  void LLViewerMediaImpl::addObject(LLVOVolume* obj)  diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 6803adfaa2..92d644c900 100755 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -40,6 +40,9 @@  #include "llnotificationptr.h"  #include "llurl.h" +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h"  class LLViewerMediaImpl;  class LLUUID; @@ -161,11 +164,15 @@ public:  	static void setOnlyAudibleMediaTextureID(const LLUUID& texture_id);  	static LLSD getHeaders(); +    static LLCore::HttpHeaders::ptr_t getHttpHeaders();  private:  	static void setOpenIDCookie();  	static void onTeleportFinished(); -	 + +    static void openIDSetupCoro(std::string openidUrl, std::string openidToken); +    static void getOpenIDCookieCoro(std::string url); +  	static LLPluginCookieStore *sCookieStore;  	static LLURL sOpenIDURL;  	static std::string sOpenIDCookie; @@ -180,7 +187,6 @@ class LLViewerMediaImpl  public:  	friend class LLViewerMedia; -	friend class LLMimeDiscoveryResponder;  	LLViewerMediaImpl(  		const LLUUID& texture_id, @@ -453,7 +459,6 @@ private:  	S32 mProximity;  	F64 mProximityDistance;  	F64 mProximityCamera; -	LLMimeDiscoveryResponder *mMimeTypeProbe;  	bool mMediaAutoPlay;  	std::string mMediaEntryURL;  	bool mInNearbyMediaList;	// used by LLPanelNearbyMedia::refreshList() for performance reasons @@ -470,6 +475,10 @@ private:  	BOOL mIsUpdated ;  	std::list< LLVOVolume* > mObjectList ; +    void mimeDiscoveryCoro(std::string url); +    LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mMimeProbe; +    bool mCanceling; +  private:  	LLViewerMediaTexture *updatePlaceholderImage();  }; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index f8e50ba463..20fbfaf71a 100755 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -62,6 +62,8 @@  #include "lluploaddialog.h"  #include "lltrans.h"  #include "llfloaterbuycurrency.h" +#include "llcoproceduremanager.h" +#include "llviewerassetupload.h"  // linden libraries  #include "llassetuploadresponders.h" @@ -83,8 +85,9 @@ class LLFileEnableUpload : public view_listener_t  {  	bool handleEvent(const LLSD& userdata)  	{ -		bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); -		return new_value; +        return true; +// 		bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); +// 		return new_value;  	}  }; @@ -410,7 +413,6 @@ class LLFileUploadBulk : public view_listener_t  		}  		// TODO: -		// Iterate over all files  		// Check extensions for uploadability, cost  		// Check user balance for entire cost  		// Charge user entire cost @@ -422,6 +424,34 @@ class LLFileUploadBulk : public view_listener_t  		LLFilePicker& picker = LLFilePicker::instance();  		if (picker.getMultipleOpenFiles())  		{ +            std::string filename = picker.getFirstFile(); +            S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + +            while (!filename.empty()) +            { +                std::string name = gDirUtilp->getBaseFileName(filename, true); + +                std::string asset_name = name; +                LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); +                LLStringUtil::replaceChar(asset_name, '|', '?'); +                LLStringUtil::stripNonprintable(asset_name); +                LLStringUtil::trim(asset_name); + +                NewResourceUploadInfo::ptr_t uploadInfo(new NewFileResourceUploadInfo( +                    filename, +                    asset_name, +                    asset_name, 0, +                    LLFolderType::FT_NONE, LLInventoryType::IT_NONE, +                    LLFloaterPerms::getNextOwnerPerms("Uploads"), +                    LLFloaterPerms::getGroupPerms("Uploads"), +                    LLFloaterPerms::getEveryonePerms("Uploads"), +                    expected_upload_cost)); + +                upload_new_resource(uploadInfo, NULL, NULL); + +                filename = picker.getNextFile(); +            } +#if 0  			const std::string& filename = picker.getFirstFile();  			std::string name = gDirUtilp->getBaseFileName(filename, true); @@ -453,6 +483,7 @@ class LLFileUploadBulk : public view_listener_t  			// *NOTE: Ew, we don't iterate over the file list here,  			// we handle the next files in upload_done_callback() +#endif  		}  		else  		{ @@ -621,6 +652,7 @@ void handle_compress_image(void*)  	}  } +  LLUUID upload_new_resource(  	const std::string& src_filename,  	std::string name, @@ -636,6 +668,18 @@ LLUUID upload_new_resource(  	S32 expected_upload_cost,  	void *userdata)  {	 + +    NewResourceUploadInfo::ptr_t uploadInfo(new NewFileResourceUploadInfo( +        src_filename, +        name, desc, compression_info, +        destination_folder_type, inv_type, +        next_owner_perms, group_perms, everyone_perms, +        expected_upload_cost)); +    upload_new_resource(uploadInfo, callback, userdata); + +    return LLUUID::null; + +#if 0  	// Generate the temporary UUID.  	std::string filename = gDirUtilp->getTempFilename();  	LLTransactionID tid; @@ -704,123 +748,6 @@ LLUUID upload_new_resource(  			return LLUUID();  		}  	} -	else if(exten == "tmp")	 	 -	{	 	 -		// This is a generic .lin resource file	 	 -         asset_type = LLAssetType::AT_OBJECT;	 	 -         LLFILE* in = LLFile::fopen(src_filename, "rb");		/* Flawfinder: ignore */	 	 -         if (in)	 	 -         {	 	 -                 // read in the file header	 	 -                 char buf[16384];		/* Flawfinder: ignore */ 	 -                 size_t readbytes; -                 S32  version;	 	 -                 if (fscanf(in, "LindenResource\nversion %d\n", &version))	 	 -                 {	 	 -                         if (2 == version)	 	 -                         { -								// *NOTE: This buffer size is hard coded into scanf() below. -                                 char label[MAX_STRING];		/* Flawfinder: ignore */	 	 -                                 char value[MAX_STRING];		/* Flawfinder: ignore */	 	 -                                 S32  tokens_read;	 	 -                                 while (fgets(buf, 1024, in))	 	 -                                 {	 	 -                                         label[0] = '\0';	 	 -                                         value[0] = '\0';	 	 -                                         tokens_read = sscanf(	/* Flawfinder: ignore */ -											 buf, -											 "%254s %254s\n", -											 label, value);	 	 - -                                         LL_INFOS() << "got: " << label << " = " << value	 	 -                                                         << LL_ENDL;	 	 - -                                         if (EOF == tokens_read)	 	 -                                         {	 	 -                                                 fclose(in);	 	 -                                                 error_message = llformat("corrupt resource file: %s", src_filename.c_str()); -												 args["FILE"] = src_filename; -												 upload_error(error_message, "CorruptResourceFile", filename, args); -                                                 return LLUUID(); -                                         }	 	 - -                                         if (2 == tokens_read)	 	 -                                         {	 	 -                                                 if (! strcmp("type", label))	 	 -                                                 {	 	 -                                                         asset_type = (LLAssetType::EType)(atoi(value));	 	 -                                                 }	 	 -                                         }	 	 -                                         else	 	 -                                         {	 	 -                                                 if (! strcmp("_DATA_", label))	 	 -                                                 {	 	 -                                                         // below is the data section	 	 -                                                         break;	 	 -                                                 }	 	 -                                         }	 	 -                                         // other values are currently discarded	 	 -                                 }	 	 - -                         }	 	 -                         else	 	 -                         {	 	 -                                 fclose(in);	 	 -                                 error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); -								 args["FILE"] = src_filename; -								 upload_error(error_message, "UnknownResourceFileVersion", filename, args); -                                 return LLUUID(); -                         }	 	 -                 }	 	 -                 else	 	 -                 {	 	 -                         // this is an original binary formatted .lin file	 	 -                         // start over at the beginning of the file	 	 -                         fseek(in, 0, SEEK_SET);	 	 - -                         const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;	 	 -                         const S32 MAX_ASSET_NAME_LENGTH = 64;	 	 -                         S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;	 	 -                         S16     type_num;	 	 - -                         // read in and throw out most of the header except for the type	 	 -                         if (fread(buf, header_size, 1, in) != 1) -						 { -							 LL_WARNS() << "Short read" << LL_ENDL; -						 } -                         memcpy(&type_num, buf + 16, sizeof(S16));		/* Flawfinder: ignore */	 	 -                         asset_type = (LLAssetType::EType)type_num;	 	 -                 }	 	 - -                 // copy the file's data segment into another file for uploading	 	 -                 LLFILE* out = LLFile::fopen(filename, "wb");		/* Flawfinder: ignore */	 -                 if (out)	 	 -                 {	 	 -                         while((readbytes = fread(buf, 1, 16384, in)))		/* Flawfinder: ignore */	 	 -                         {	 	 -							 if (fwrite(buf, 1, readbytes, out) != readbytes) -							 { -								 LL_WARNS() << "Short write" << LL_ENDL; -							 } -                         }	 	 -                         fclose(out);	 	 -                 }	 	 -                 else	 	 -                 {	 	 -                         fclose(in);	 	 -                         error_message = llformat( "Unable to create output file: %s", filename.c_str()); -						 args["FILE"] = filename; -						 upload_error(error_message, "UnableToCreateOutputFile", filename, args); -                         return LLUUID(); -                 }	 	 - -                 fclose(in);	 	 -         }	 	 -         else	 	 -         {	 	 -                 LL_INFOS() << "Couldn't open .lin file " << src_filename << LL_ENDL;	 	 -         }	 	 -	}  	else if (exten == "bvh")  	{  		error_message = llformat("We do not currently support bulk upload of animation files\n"); @@ -871,26 +798,15 @@ LLUUID upload_new_resource(  	if (!error)  	{ -		std::string t_disp_name = display_name; -		if (t_disp_name.empty()) -		{ -			t_disp_name = src_filename; -		} -		upload_new_resource( -			tid, -			asset_type, -			name, -			desc, -			compression_info, // tid -			destination_folder_type, -			inv_type, -			next_owner_perms, -			group_perms, -			everyone_perms, -			display_name, -			callback, -			expected_upload_cost, -			userdata); +        NewResourceUploadInfo::ptr_t uploadInfo(new NewResourceUploadInfo( +            tid, asset_type, +            name, desc, compression_info, +            destination_folder_type, inv_type, +            next_owner_perms, group_perms, everyone_perms, +            expected_upload_cost)); + +        upload_new_resource(uploadInfo,  +                callback, userdata);  	}  	else  	{ @@ -906,6 +822,7 @@ LLUUID upload_new_resource(  	}  	return uuid; +#endif  }  void upload_done_callback( @@ -1035,189 +952,64 @@ void upload_done_callback(  	}  } -static LLAssetID upload_new_resource_prep( -	const LLTransactionID& tid, -	LLAssetType::EType asset_type, -	LLInventoryType::EType& inventory_type, -	std::string& name, -	const std::string& display_name, -	std::string& description) -{ -	LLAssetID uuid = generate_asset_id_for_new_upload(tid); - -	increase_new_upload_stats(asset_type); - -	assign_defaults_and_show_upload_message( -		asset_type, -		inventory_type, -		name, -		display_name, -		description); - -	return uuid; -} - -LLSD generate_new_resource_upload_capability_body( -	LLAssetType::EType asset_type, -	const std::string& name, -	const std::string& desc, -	LLFolderType::EType destination_folder_type, -	LLInventoryType::EType inv_type, -	U32 next_owner_perms, -	U32 group_perms, -	U32 everyone_perms) -{ -	LLSD body; - -	body["folder_id"] = gInventory.findCategoryUUIDForType( -		(destination_folder_type == LLFolderType::FT_NONE) ? -		(LLFolderType::EType) asset_type : -		destination_folder_type); - -	body["asset_type"] = LLAssetType::lookup(asset_type); -	body["inventory_type"] = LLInventoryType::lookup(inv_type); -	body["name"] = name; -	body["description"] = desc; -	body["next_owner_mask"] = LLSD::Integer(next_owner_perms); -	body["group_mask"] = LLSD::Integer(group_perms); -	body["everyone_mask"] = LLSD::Integer(everyone_perms); - -	return body; -} -  void upload_new_resource( -	const LLTransactionID &tid, -	LLAssetType::EType asset_type, -	std::string name, -	std::string desc, -	S32 compression_info, -	LLFolderType::EType destination_folder_type, -	LLInventoryType::EType inv_type, -	U32 next_owner_perms, -	U32 group_perms, -	U32 everyone_perms, -	const std::string& display_name, -	LLAssetStorage::LLStoreAssetCallback callback, -	S32 expected_upload_cost, -	void *userdata) +    NewResourceUploadInfo::ptr_t &uploadInfo, +    LLAssetStorage::LLStoreAssetCallback callback, +    void *userdata)  {  	if(gDisconnected)  	{  		return ;  	} -	 -	LLAssetID uuid =  -		upload_new_resource_prep( -			tid, -			asset_type, -			inv_type, -			name, -			display_name, -			desc); -	 -	if( LLAssetType::AT_SOUND == asset_type ) -	{ -		add(LLStatViewer::UPLOAD_SOUND, 1); -	} -	else -	if( LLAssetType::AT_TEXTURE == asset_type ) -	{ -		add(LLStatViewer::UPLOAD_TEXTURE, 1); -	} -	else -	if( LLAssetType::AT_ANIMATION == asset_type) -	{ -		add(LLStatViewer::ANIMATION_UPLOADS, 1); -	} -	if(LLInventoryType::IT_NONE == inv_type) -	{ -		inv_type = LLInventoryType::defaultForAssetType(asset_type); -	} -	LLStringUtil::stripNonprintable(name); -	LLStringUtil::stripNonprintable(desc); -	if(name.empty()) -	{ -		name = "(No Name)"; -	} -	if(desc.empty()) -	{ -		desc = "(No Description)"; -	} -	 -	// At this point, we're ready for the upload. -	std::string upload_message = "Uploading...\n\n"; -	upload_message.append(display_name); -	LLUploadDialog::modalUploadDialog(upload_message); - -	LL_INFOS() << "*** Uploading: " << LL_ENDL; -	LL_INFOS() << "Type: " << LLAssetType::lookup(asset_type) << LL_ENDL; -	LL_INFOS() << "UUID: " << uuid << LL_ENDL; -	LL_INFOS() << "Name: " << name << LL_ENDL; -	LL_INFOS() << "Desc: " << desc << LL_ENDL; -	LL_INFOS() << "Expected Upload Cost: " << expected_upload_cost << LL_ENDL; -	LL_DEBUGS() << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << LL_ENDL; -	LL_DEBUGS() << "Asset Type: " << LLAssetType::lookup(asset_type) << LL_ENDL; - -	std::string url = gAgent.getRegion()->getCapability( -		"NewFileAgentInventory"); +//     uploadInfo->setAssetType(assetType); +//     uploadInfo->setTransactionId(tid); + + +	std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");  	if ( !url.empty() )  	{ -		LL_INFOS() << "New Agent Inventory via capability" << LL_ENDL; - -		LLSD body; -		body = generate_new_resource_upload_capability_body( -			asset_type, -			name, -			desc, -			destination_folder_type, -			inv_type, -			next_owner_perms, -			group_perms, -			everyone_perms); - -		LLHTTPClient::post( -			url, -			body, -			new LLNewAgentInventoryResponder( -				body, -				uuid, -				asset_type)); +        LLCoprocedureManager::CoProcedure_t proc = boost::bind(&LLViewerAssetUpload::AssetInventoryUploadCoproc, _1, _2, url, uploadInfo); + +        LLCoprocedureManager::getInstance()->enqueueCoprocedure("LLViewerAssetUpload::AssetInventoryUploadCoproc", proc);  	}  	else  	{ +        uploadInfo->prepareUpload(); +        uploadInfo->logPreparedUpload(); +  		LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL;  		// check for adequate funds  		// TODO: do this check on the sim -		if (LLAssetType::AT_SOUND == asset_type || -			LLAssetType::AT_TEXTURE == asset_type || -			LLAssetType::AT_ANIMATION == asset_type) +		if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || +            LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() || +            LLAssetType::AT_ANIMATION == uploadInfo->getAssetType())  		{  			S32 balance = gStatusBar->getBalance(); -			if (balance < expected_upload_cost) +			if (balance < uploadInfo->getExpectedUploadCost())  			{  				// insufficient funds, bail on this upload  				LLStringUtil::format_map_t args; -				args["NAME"] = name; -				args["AMOUNT"] = llformat("%d", expected_upload_cost); -				LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); +				args["NAME"] = uploadInfo->getName(); +                args["AMOUNT"] = llformat("%d", uploadInfo->getExpectedUploadCost()); +                LLBuyCurrencyHTML::openCurrencyFloater(LLTrans::getString("UploadingCosts", args), uploadInfo->getExpectedUploadCost());  				return;  			}  		}  		LLResourceData* data = new LLResourceData; -		data->mAssetInfo.mTransactionID = tid; -		data->mAssetInfo.mUuid = uuid; -		data->mAssetInfo.mType = asset_type; +		data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); +		data->mAssetInfo.mUuid = uploadInfo->getAssetId(); +        data->mAssetInfo.mType = uploadInfo->getAssetType();  		data->mAssetInfo.mCreatorID = gAgentID; -		data->mInventoryType = inv_type; -		data->mNextOwnerPerm = next_owner_perms; -		data->mExpectedUploadCost = expected_upload_cost; +		data->mInventoryType = uploadInfo->getInventoryType(); +		data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); +		data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost();  		data->mUserData = userdata; -		data->mAssetInfo.setName(name); -		data->mAssetInfo.setDescription(desc); -		data->mPreferredLocation = destination_folder_type; +		data->mAssetInfo.setName(uploadInfo->getName()); +		data->mAssetInfo.setDescription(uploadInfo->getDescription()); +		data->mPreferredLocation = uploadInfo->getDestinationFolderType();  		LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;  		if (callback) @@ -1233,66 +1025,6 @@ void upload_new_resource(  	}  } -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) -{ -	if ( gDisconnected ) -	{	 -		LLAssetID rv; - -		rv.setNull(); -		return rv; -	} - -	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - -	return uuid; -} - -void increase_new_upload_stats(LLAssetType::EType asset_type) -{ -	if ( LLAssetType::AT_SOUND == asset_type ) -	{ -		add(LLStatViewer::UPLOAD_SOUND, 1); -	} -	else if ( LLAssetType::AT_TEXTURE == asset_type ) -	{ -		add(LLStatViewer::UPLOAD_TEXTURE, 1); -	} -	else if ( LLAssetType::AT_ANIMATION == asset_type ) -	{ -		add(LLStatViewer::ANIMATION_UPLOADS, 1); -	} -} - -void assign_defaults_and_show_upload_message( -	LLAssetType::EType asset_type, -	LLInventoryType::EType& inventory_type, -	std::string& name, -	const std::string& display_name, -	std::string& description) -{ -	if ( LLInventoryType::IT_NONE == inventory_type ) -	{ -		inventory_type = LLInventoryType::defaultForAssetType(asset_type); -	} -	LLStringUtil::stripNonprintable(name); -	LLStringUtil::stripNonprintable(description); - -	if ( name.empty() ) -	{ -		name = "(No Name)"; -	} -	if ( description.empty() ) -	{ -		description = "(No Description)"; -	} - -	// At this point, we're ready for the upload. -	std::string upload_message = "Uploading...\n\n"; -	upload_message.append(display_name); -	LLUploadDialog::modalUploadDialog(upload_message); -} -  void init_menu_file()  { @@ -1315,3 +1047,349 @@ void init_menu_file()  	// "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.  } + +LLSD NewResourceUploadInfo::prepareUpload() +{ +    if (mAssetId.isNull()) +        generateNewAssetId(); + +    incrementUploadStats(); +    assignDefaults(); + +    return LLSD().with("success", LLSD::Boolean(true)); +} + +std::string NewResourceUploadInfo::getAssetTypeString() const +{ +    return LLAssetType::lookup(mAssetType); +} + +std::string NewResourceUploadInfo::getInventoryTypeString() const +{ +    return LLInventoryType::lookup(mInventoryType); +} + +LLSD NewResourceUploadInfo::generatePostBody() +{ +    LLSD body; + +    body["folder_id"] = mFolderId; +    body["asset_type"] = getAssetTypeString(); +    body["inventory_type"] = getInventoryTypeString(); +    body["name"] = mName; +    body["description"] = mDescription; +    body["next_owner_mask"] = LLSD::Integer(mNextOwnerPerms); +    body["group_mask"] = LLSD::Integer(mGroupPerms); +    body["everyone_mask"] = LLSD::Integer(mEveryonePerms); + +    return body; + +} + +void NewResourceUploadInfo::logPreparedUpload() +{ +    LL_INFOS() << "*** Uploading: " << std::endl <<  +        "Type: " << LLAssetType::lookup(mAssetType) << std::endl << +        "UUID: " << mAssetId.asString() << std::endl <<  +        "Name: " << mName << std::endl <<  +        "Desc: " << mDescription << std::endl << +        "Expected Upload Cost: " << mExpectedUploadCost << std::endl << +        "Folder: " << mFolderId << std::endl << +        "Asset Type: " << LLAssetType::lookup(mAssetType) << LL_ENDL; +} + +LLUUID NewResourceUploadInfo::finishUpload(LLSD &result) +{ +    if (getFolderId().isNull()) +    { +        return LLUUID::null; +    } + +    U32 permsEveryone = PERM_NONE; +    U32 permsGroup = PERM_NONE; +    U32 permsNextOwner = PERM_ALL; + +    if (result.has("new_next_owner_mask")) +    { +        // The server provided creation perms so use them. +        // Do not assume we got the perms we asked for in +        // since the server may not have granted them all. +        permsEveryone = result["new_everyone_mask"].asInteger(); +        permsGroup = result["new_group_mask"].asInteger(); +        permsNextOwner = result["new_next_owner_mask"].asInteger(); +    } +    else +    { +        // The server doesn't provide creation perms +        // so use old assumption-based perms. +        if (getAssetTypeString() != "snapshot") +        { +            permsNextOwner = PERM_MOVE | PERM_TRANSFER; +        } +    } + +    LLPermissions new_perms; +    new_perms.init( +        gAgent.getID(), +        gAgent.getID(), +        LLUUID::null, +        LLUUID::null); + +    new_perms.initMasks( +        PERM_ALL, +        PERM_ALL, +        permsEveryone, +        permsGroup, +        permsNextOwner); + +    U32 flagsInventoryItem = 0; +    if (result.has("inventory_flags")) +    { +        flagsInventoryItem = static_cast<U32>(result["inventory_flags"].asInteger()); +        if (flagsInventoryItem != 0) +        { +            LL_INFOS() << "inventory_item_flags " << flagsInventoryItem << LL_ENDL; +        } +    } +    S32 creationDate = time_corrected(); + +    LLUUID serverInventoryItem = result["new_inventory_item"].asUUID(); +    LLUUID serverAssetId = result["new_asset"].asUUID(); + +    LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( +        serverInventoryItem, +        getFolderId(), +        new_perms, +        serverAssetId, +        getAssetType(), +        getInventoryType(), +        getName(), +        getDescription(), +        LLSaleInfo::DEFAULT, +        flagsInventoryItem, +        creationDate); + +    gInventory.updateItem(item); +    gInventory.notifyObservers(); + +    return serverInventoryItem; +} + + +LLAssetID NewResourceUploadInfo::generateNewAssetId() +{ +    if (gDisconnected) +    { +        LLAssetID rv; + +        rv.setNull(); +        return rv; +    } +    mAssetId = mTransactionId.makeAssetID(gAgent.getSecureSessionID()); + +    return mAssetId; +} + +void NewResourceUploadInfo::incrementUploadStats() const +{ +    if (LLAssetType::AT_SOUND == mAssetType) +    { +        add(LLStatViewer::UPLOAD_SOUND, 1); +    } +    else if (LLAssetType::AT_TEXTURE == mAssetType) +    { +        add(LLStatViewer::UPLOAD_TEXTURE, 1); +    } +    else if (LLAssetType::AT_ANIMATION == mAssetType) +    { +        add(LLStatViewer::ANIMATION_UPLOADS, 1); +    } +} + +void NewResourceUploadInfo::assignDefaults() +{ +    if (LLInventoryType::IT_NONE == mInventoryType) +    { +        mInventoryType = LLInventoryType::defaultForAssetType(mAssetType); +    } +    LLStringUtil::stripNonprintable(mName); +    LLStringUtil::stripNonprintable(mDescription); + +    if (mName.empty()) +    { +        mName = "(No Name)"; +    } +    if (mDescription.empty()) +    { +        mDescription = "(No Description)"; +    } + +    mFolderId = gInventory.findCategoryUUIDForType( +        (mDestinationFolderType == LLFolderType::FT_NONE) ? +        (LLFolderType::EType)mAssetType : mDestinationFolderType); + +} + +std::string NewResourceUploadInfo::getDisplayName() const +{  +    return (mName.empty()) ? mAssetId.asString() : mName;  +}; + + +NewFileResourceUploadInfo::NewFileResourceUploadInfo( +        std::string fileName, +        std::string name, +        std::string description, +        S32 compressionInfo, +        LLFolderType::EType destinationType, +        LLInventoryType::EType inventoryType, +        U32 nextOWnerPerms, +        U32 groupPerms, +        U32 everyonePerms, +        S32 expectedCost): +    NewResourceUploadInfo(name, description, compressionInfo, +        destinationType, inventoryType, +        nextOWnerPerms, groupPerms, everyonePerms, expectedCost), +    mFileName(fileName) +{ +    LLTransactionID tid; +    tid.generate(); +    setTransactionId(tid); +} + + + +LLSD NewFileResourceUploadInfo::prepareUpload() +{ +    generateNewAssetId(); + +    LLSD result = exportTempFile(); +    if (result.has("error")) +        return result; + +    return NewResourceUploadInfo::prepareUpload(); +} + +LLSD NewFileResourceUploadInfo::exportTempFile() +{ +    std::string filename = gDirUtilp->getTempFilename(); + +    std::string exten = gDirUtilp->getExtension(getFileName()); +    U32 codec = LLImageBase::getCodecFromExtension(exten); + +    LLAssetType::EType assetType = LLAssetType::AT_NONE; +    std::string errorMessage; +    std::string errorLabel; + +    bool error = false; + +    if (exten.empty()) +    { +        std::string shortName = gDirUtilp->getBaseFileName(filename); + +        // No extension +        errorMessage = llformat( +            "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", +            shortName.c_str()); +        errorLabel = "NoFileExtension"; +        error = true; +    } +    else if (codec != IMG_CODEC_INVALID) +    { +        // It's an image file, the upload procedure is the same for all +        assetType = LLAssetType::AT_TEXTURE; +        if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec)) +        { +            errorMessage = llformat("Problem with file %s:\n\n%s\n", +                getFileName().c_str(), LLImage::getLastError().c_str()); +            errorLabel = "ProblemWithFile"; +            error = true; +        } +    } +    else if (exten == "wav") +    { +        assetType = LLAssetType::AT_SOUND;  // tag it as audio +        S32 encodeResult = 0; + +        LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL; + +        encodeResult = encode_vorbis_file(getFileName(), filename); + +        if (LLVORBISENC_NOERR != encodeResult) +        { +            switch (encodeResult) +            { +            case LLVORBISENC_DEST_OPEN_ERR: +                errorMessage = llformat("Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); +                errorLabel = "CannotOpenTemporarySoundFile"; +                break; + +            default: +                errorMessage = llformat("Unknown vorbis encode failure on: %s\n", getFileName().c_str()); +                errorLabel = "UnknownVorbisEncodeFailure"; +                break; +            } +            error = true; +        } +    } +    else if (exten == "bvh") +    { +        errorMessage = llformat("We do not currently support bulk upload of animation files\n"); +        errorLabel = "DoNotSupportBulkAnimationUpload"; +        error = true; +    } +    else if (exten == "anim") +    { +        assetType = LLAssetType::AT_ANIMATION; +        filename = getFileName(); +    } +    else +    { +        // Unknown extension +        errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); +        errorLabel = "ErrorMessage"; +        error = TRUE;; +    } + +    if (error) +    { +        LLSD errorResult(LLSD::emptyMap()); + +        errorResult["error"] = LLSD::Binary(true); +        errorResult["message"] = errorMessage; +        errorResult["label"] = errorLabel; +        return errorResult; +    } + +    setAssetType(assetType); + +    // copy this file into the vfs for upload +    S32 file_size; +    LLAPRFile infile; +    infile.open(filename, LL_APR_RB, NULL, &file_size); +    if (infile.getFileHandle()) +    { +        LLVFile file(gVFS, getAssetId(), assetType, LLVFile::WRITE); + +        file.setMaxSize(file_size); + +        const S32 buf_size = 65536; +        U8 copy_buf[buf_size]; +        while ((file_size = infile.read(copy_buf, buf_size))) +        { +            file.write(copy_buf, file_size); +        } +    } +    else +    { +        errorMessage = llformat("Unable to access output file: %s", filename.c_str()); +        LLSD errorResult(LLSD::emptyMap()); + +        errorResult["error"] = LLSD::Binary(true); +        errorResult["message"] = errorMessage; +        return errorResult; +    } + +    return LLSD(); + +} diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 3034d00b22..7ee5043777 100755 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -39,40 +39,172 @@ class LLTransactionID;  void init_menu_file(); +class NewResourceUploadInfo +{ +public: +    typedef boost::shared_ptr<NewResourceUploadInfo> ptr_t; + +    NewResourceUploadInfo( +            LLTransactionID transactId, +            LLAssetType::EType assetType, +            std::string name,  +            std::string description,  +            S32 compressionInfo, +            LLFolderType::EType destinationType, +            LLInventoryType::EType inventoryType, +            U32 nextOWnerPerms,  +            U32 groupPerms,  +            U32 everyonePerms,  +            S32 expectedCost) : +        mTransactionId(transactId), +        mAssetType(assetType), +        mName(name), +        mDescription(description), +        mCompressionInfo(compressionInfo), +        mDestinationFolderType(destinationType), +        mInventoryType(inventoryType), +        mNextOwnerPerms(nextOWnerPerms), +        mGroupPerms(groupPerms), +        mEveryonePerms(everyonePerms), +        mExpectedUploadCost(expectedCost), +        mFolderId(LLUUID::null), +        mItemId(LLUUID::null), +        mAssetId(LLAssetID::null) +    { } + +    virtual ~NewResourceUploadInfo() +    { } + +    virtual LLSD        prepareUpload(); +    virtual LLSD        generatePostBody(); +    virtual void        logPreparedUpload(); +    virtual LLUUID      finishUpload(LLSD &result); + +    //void                setAssetType(LLAssetType::EType assetType) { mAssetType = assetType; } +    //void                setTransactionId(LLTransactionID transactionId) { mTransactionId = transactionId; } + +    LLTransactionID     getTransactionId() const { return mTransactionId; } +    LLAssetType::EType  getAssetType() const { return mAssetType; } +    std::string         getAssetTypeString() const; +    std::string         getName() const { return mName; }; +    std::string         getDescription() const { return mDescription; }; +    S32                 getCompressionInfo() const { return mCompressionInfo; }; +    LLFolderType::EType getDestinationFolderType() const { return mDestinationFolderType; }; +    LLInventoryType::EType  getInventoryType() const { return mInventoryType; }; +    std::string         getInventoryTypeString() const; +    U32                 getNextOwnerPerms() const { return mNextOwnerPerms; }; +    U32                 getGroupPerms() const { return mGroupPerms; }; +    U32                 getEveryonePerms() const { return mEveryonePerms; }; +    S32                 getExpectedUploadCost() const { return mExpectedUploadCost; }; + +    virtual std::string getDisplayName() const; + +    LLUUID              getFolderId() const { return mFolderId; } +    LLUUID              getItemId() const { return mItemId; } +    LLAssetID           getAssetId() const { return mAssetId; } + +protected: +    NewResourceUploadInfo( +            std::string name, +            std::string description, +            S32 compressionInfo, +            LLFolderType::EType destinationType, +            LLInventoryType::EType inventoryType, +            U32 nextOWnerPerms, +            U32 groupPerms, +            U32 everyonePerms, +            S32 expectedCost) : +        mName(name), +        mDescription(description), +        mCompressionInfo(compressionInfo), +        mDestinationFolderType(destinationType), +        mInventoryType(inventoryType), +        mNextOwnerPerms(nextOWnerPerms), +        mGroupPerms(groupPerms), +        mEveryonePerms(everyonePerms), +        mExpectedUploadCost(expectedCost), +        mTransactionId(), +        mAssetType(LLAssetType::AT_NONE), +        mFolderId(LLUUID::null), +        mItemId(LLUUID::null), +        mAssetId(LLAssetID::null) +    { } + +    void                setTransactionId(LLTransactionID tid) { mTransactionId = tid; } +    void                setAssetType(LLAssetType::EType assetType) { mAssetType = assetType; } + +    LLAssetID           generateNewAssetId(); +    void                incrementUploadStats() const; +    virtual void        assignDefaults(); + +private: +    LLTransactionID     mTransactionId; +    LLAssetType::EType  mAssetType; +    std::string         mName; +    std::string         mDescription; +    S32                 mCompressionInfo; +    LLFolderType::EType mDestinationFolderType; +    LLInventoryType::EType mInventoryType; +    U32                 mNextOwnerPerms; +    U32                 mGroupPerms; +    U32                 mEveryonePerms; +    S32                 mExpectedUploadCost; + +    LLUUID              mFolderId; +    LLUUID              mItemId; +    LLAssetID           mAssetId; +}; + +class NewFileResourceUploadInfo : public NewResourceUploadInfo +{ +public: +    NewFileResourceUploadInfo( +        std::string fileName, +        std::string name, +        std::string description, +        S32 compressionInfo, +        LLFolderType::EType destinationType, +        LLInventoryType::EType inventoryType, +        U32 nextOWnerPerms, +        U32 groupPerms, +        U32 everyonePerms, +        S32 expectedCost); + +    virtual LLSD        prepareUpload(); + +    std::string         getFileName() const { return mFileName; }; + +protected: + +    virtual LLSD        exportTempFile(); + +private: +    std::string         mFileName; + +}; + +  LLUUID upload_new_resource( -	const std::string& src_filename,  -	std::string name, -	std::string desc,  -	S32 compression_info, -	LLFolderType::EType destination_folder_type, -	LLInventoryType::EType inv_type, -	U32 next_owner_perms, -	U32 group_perms, -	U32 everyone_perms, -	const std::string& display_name, -	LLAssetStorage::LLStoreAssetCallback callback, -	S32 expected_upload_cost, -	void *userdata); +    const std::string& src_filename, +    std::string name, +    std::string desc, +    S32 compression_info, +    LLFolderType::EType destination_folder_type, +    LLInventoryType::EType inv_type, +    U32 next_owner_perms, +    U32 group_perms, +    U32 everyone_perms, +    const std::string& display_name, +    LLAssetStorage::LLStoreAssetCallback callback, +    S32 expected_upload_cost, +    void *userdata);  void upload_new_resource( -	const LLTransactionID &tid,  -	LLAssetType::EType type, -	std::string name, -	std::string desc,  -	S32 compression_info, -	LLFolderType::EType destination_folder_type, -	LLInventoryType::EType inv_type, -	U32 next_owner_perms, -	U32 group_perms, -	U32 everyone_perms, -	const std::string& display_name, -	LLAssetStorage::LLStoreAssetCallback callback, -	S32 expected_upload_cost, -	void *userdata); +    NewResourceUploadInfo::ptr_t &uploadInfo, +    LLAssetStorage::LLStoreAssetCallback callback = NULL, +    void *userdata = NULL); -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid); -void increase_new_upload_stats(LLAssetType::EType asset_type);  void assign_defaults_and_show_upload_message(  	LLAssetType::EType asset_type,  	LLInventoryType::EType& inventory_type, @@ -80,16 +212,6 @@ void assign_defaults_and_show_upload_message(  	const std::string& display_name,  	std::string& description); -LLSD generate_new_resource_upload_capability_body( -	LLAssetType::EType asset_type, -	const std::string& name, -	const std::string& desc, -	LLFolderType::EType destination_folder_type, -	LLInventoryType::EType inv_type, -	U32 next_owner_perms, -	U32 group_perms, -	U32 everyone_perms); -  void on_new_single_inventory_upload_complete(  	LLAssetType::EType asset_type,  	LLInventoryType::EType inventory_type, diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 7c36b30dd1..2a009499d3 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -78,6 +78,7 @@  #include "llappviewer.h"  #include "llfloaterperms.h"  #include "llvocache.h" +#include "llcorehttputil.h"  extern F32 gMinObjectDistance;  extern BOOL gAnimateTextures; @@ -795,190 +796,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  	LLVOAvatar::cullAvatarsByPixelArea();  } -class LLObjectCostResponder : public LLCurl::Responder -{ -	LOG_CLASS(LLObjectCostResponder); -public: -	LLObjectCostResponder(const LLSD& object_ids) -		: mObjectIDs(object_ids) -	{ -	} - -	// Clear's the global object list's pending -	// request list for all objects requested -	void clear_object_list_pending_requests() -	{ -		// TODO*: No more hard coding -		for ( -			LLSD::array_iterator iter = mObjectIDs.beginArray(); -			iter != mObjectIDs.endArray(); -			++iter) -		{ -			gObjectList.onObjectCostFetchFailure(iter->asUUID()); -		} -	} - -private: -	/* virtual */ void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; - -		// TODO*: Error message to user -		// For now just clear the request from the pending list -		clear_object_list_pending_requests(); -	} - -	/* virtual */ void httpSuccess() -	{ -		const LLSD& content = getContent(); -		if ( !content.isMap() || content.has("error") ) -		{ -			// Improper response or the request had an error, -			// show an error to the user? -			LL_WARNS() -				<< "Application level error when fetching object " -				<< "cost.  Message: " << content["error"]["message"].asString() -				<< ", identifier: " << content["error"]["identifier"].asString() -				<< LL_ENDL; - -			// TODO*: Adaptively adjust request size if the -			// service says we've requested too many and retry - -			// TODO*: Error message if not retrying -			clear_object_list_pending_requests(); -			return; -		} - -		// Success, grab the resource cost and linked set costs -		// for an object if one was returned -		for ( -			LLSD::array_iterator iter = mObjectIDs.beginArray(); -			iter != mObjectIDs.endArray(); -			++iter) -		{ -			LLUUID object_id = iter->asUUID(); - -			// Check to see if the request contains data for the object -			if ( content.has(iter->asString()) ) -			{ -				F32 link_cost = -					content[iter->asString()]["linked_set_resource_cost"].asReal(); -				F32 object_cost = -					content[iter->asString()]["resource_cost"].asReal(); - -				F32 physics_cost = content[iter->asString()]["physics_cost"].asReal(); -				F32 link_physics_cost = content[iter->asString()]["linked_set_physics_cost"].asReal(); - -				gObjectList.updateObjectCost(object_id, object_cost, link_cost, physics_cost, link_physics_cost); -			} -			else -			{ -				// TODO*: Give user feedback about the missing data? -				gObjectList.onObjectCostFetchFailure(object_id); -			} -		} -	} - -private: -	LLSD mObjectIDs; -}; - - -class LLPhysicsFlagsResponder : public LLCurl::Responder -{ -	LOG_CLASS(LLPhysicsFlagsResponder); -public: -	LLPhysicsFlagsResponder(const LLSD& object_ids) -		: mObjectIDs(object_ids) -	{ -	} - -	// Clear's the global object list's pending -	// request list for all objects requested -	void clear_object_list_pending_requests() -	{ -		// TODO*: No more hard coding -		for ( -			LLSD::array_iterator iter = mObjectIDs.beginArray(); -			iter != mObjectIDs.endArray(); -			++iter) -		{ -			gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID()); -		} -	} - -private: -	/* virtual */ void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; - -		// TODO*: Error message to user -		// For now just clear the request from the pending list -		clear_object_list_pending_requests(); -	} - -	/* virtual void */ void httpSuccess() -	{ -		const LLSD& content = getContent(); -		if ( !content.isMap() || content.has("error") ) -		{ -			// Improper response or the request had an error, -			// show an error to the user? -			LL_WARNS() -				<< "Application level error when fetching object " -				<< "physics flags.  Message: " << content["error"]["message"].asString() -				<< ", identifier: " << content["error"]["identifier"].asString() -				<< LL_ENDL; - -			// TODO*: Adaptively adjust request size if the -			// service says we've requested too many and retry - -			// TODO*: Error message if not retrying -			clear_object_list_pending_requests(); -			return; -		} - -		// Success, grab the resource cost and linked set costs -		// for an object if one was returned -		for ( -			LLSD::array_iterator iter = mObjectIDs.beginArray(); -			iter != mObjectIDs.endArray(); -			++iter) -		{ -			LLUUID object_id = iter->asUUID(); - -			// Check to see if the request contains data for the object -			if ( content.has(iter->asString()) ) -			{ -				const LLSD& data = content[iter->asString()]; - -				S32 shape_type = data["PhysicsShapeType"].asInteger(); - -				gObjectList.updatePhysicsShapeType(object_id, shape_type); - -				if (data.has("Density")) -				{ -					F32 density = data["Density"].asReal(); -					F32 friction = data["Friction"].asReal(); -					F32 restitution = data["Restitution"].asReal(); -					F32 gravity_multiplier = data["GravityMultiplier"].asReal(); -					 -					gObjectList.updatePhysicsProperties(object_id,  -						density, friction, restitution, gravity_multiplier); -				} -			} -			else -			{ -				// TODO*: Give user feedback about the missing data? -				gObjectList.onPhysicsFlagsFetchFailure(object_id); -			} -		} -	} - -private: -	LLSD mObjectIDs; -}; -  static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy");  void LLViewerObjectList::update(LLAgent &agent) @@ -1174,41 +991,8 @@ void LLViewerObjectList::fetchObjectCosts()  			if (!url.empty())  			{ -				LLSD id_list; -				U32 object_index = 0; - -				for ( -					std::set<LLUUID>::iterator iter = mStaleObjectCost.begin(); -					iter != mStaleObjectCost.end(); -					) -				{ -					// Check to see if a request for this object -					// has already been made. -					if ( mPendingObjectCost.find(*iter) == -						 mPendingObjectCost.end() ) -					{ -						mPendingObjectCost.insert(*iter); -						id_list[object_index++] = *iter; -					} - -					mStaleObjectCost.erase(iter++); - -					if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS) -					{ -						break; -					} -				} -									 -				if ( id_list.size() > 0 ) -				{ -					LLSD post_data = LLSD::emptyMap(); - -					post_data["object_ids"] = id_list; -					LLHTTPClient::post( -						url, -						post_data, -						new LLObjectCostResponder(id_list)); -				} +                LLCoros::instance().launch("LLViewerObjectList::fetchObjectCostsCoro", +                    boost::bind(&LLViewerObjectList::fetchObjectCostsCoro, this, url));  			}  			else  			{ @@ -1219,6 +1003,111 @@ void LLViewerObjectList::fetchObjectCosts()  	}  } +/*static*/ +void LLViewerObjectList::reportObjectCostFailure(LLSD &objectList) +{ +    // TODO*: No more hard coding +    for (LLSD::array_iterator it = objectList.beginArray(); it != objectList.endArray(); ++it) +    { +        gObjectList.onObjectCostFetchFailure(it->asUUID()); +    } +} + + +void LLViewerObjectList::fetchObjectCostsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD idList; +    U32 objectIndex = 0; + +    for (std::set<LLUUID>::iterator it = mStaleObjectCost.begin(); it != mStaleObjectCost.end(); ) +    { +        // Check to see if a request for this object +        // has already been made. +        if (mPendingObjectCost.find(*it) == mPendingObjectCost.end()) +        { +            mPendingObjectCost.insert(*it); +            idList[objectIndex++] = *it; +        } + +        mStaleObjectCost.erase(it++); + +        if (objectIndex >= MAX_CONCURRENT_PHYSICS_REQUESTS) +        { +            break; +        } +    } + +    if (idList.size() < 1) +    { +        LL_INFOS() << "No outstanding object IDs to request." << LL_ENDL; +        return; +    } +      +    LLSD postData = LLSD::emptyMap(); + +    postData["object_ids"] = idList; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status || result.has("error")) +    { +        if (result.has("error")) +        { +            LL_WARNS() << "Application level error when fetching object " +                << "cost.  Message: " << result["error"]["message"].asString() +                << ", identifier: " << result["error"]["identifier"].asString() +                << LL_ENDL; + +            // TODO*: Adaptively adjust request size if the +            // service says we've requested too many and retry +        } +        reportObjectCostFailure(idList); + +        return; +    } + +    // Success, grab the resource cost and linked set costs +    // for an object if one was returned +    for (LLSD::array_iterator it = idList.beginArray(); it != idList.endArray(); ++it) +    { +        LLUUID objectId = it->asUUID(); + +        // Check to see if the request contains data for the object +        if (result.has(it->asString())) +        { +            const LLSD& data = result[it->asString()]; + +            S32 shapeType = data["PhysicsShapeType"].asInteger(); + +            gObjectList.updatePhysicsShapeType(objectId, shapeType); + +            if (data.has("Density")) +            { +                F32 density = data["Density"].asReal(); +                F32 friction = data["Friction"].asReal(); +                F32 restitution = data["Restitution"].asReal(); +                F32 gravityMult = data["GravityMultiplier"].asReal(); + +                gObjectList.updatePhysicsProperties(objectId, density, friction, restitution, gravityMult); +            } +        } +        else +        { +            // TODO*: Give user feedback about the missing data? +            gObjectList.onPhysicsFlagsFetchFailure(objectId); +        } +    } + +} +  void LLViewerObjectList::fetchPhysicsFlags()  {  	// issue http request for stale object physics flags @@ -1232,41 +1121,8 @@ void LLViewerObjectList::fetchPhysicsFlags()  			if (!url.empty())  			{ -				LLSD id_list; -				U32 object_index = 0; - -				for ( -					std::set<LLUUID>::iterator iter = mStalePhysicsFlags.begin(); -					iter != mStalePhysicsFlags.end(); -					) -				{ -					// Check to see if a request for this object -					// has already been made. -					if ( mPendingPhysicsFlags.find(*iter) == -						 mPendingPhysicsFlags.end() ) -					{ -						mPendingPhysicsFlags.insert(*iter); -						id_list[object_index++] = *iter; -					} - -					mStalePhysicsFlags.erase(iter++); -					 -					if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS) -					{ -						break; -					} -				} - -				if ( id_list.size() > 0 ) -				{ -					LLSD post_data = LLSD::emptyMap(); - -					post_data["object_ids"] = id_list; -					LLHTTPClient::post( -						url, -						post_data, -						new LLPhysicsFlagsResponder(id_list)); -				} +                LLCoros::instance().launch("LLViewerObjectList::fetchPhisicsFlagsCoro", +                    boost::bind(&LLViewerObjectList::fetchPhisicsFlagsCoro, this, url));  			}  			else  			{ @@ -1277,6 +1133,109 @@ void LLViewerObjectList::fetchPhysicsFlags()  	}  } +/*static*/ +void LLViewerObjectList::reportPhysicsFlagFailure(LLSD &objectList) +{ +    // TODO*: No more hard coding +    for (LLSD::array_iterator it = objectList.beginArray(); it != objectList.endArray(); ++it) +    { +        gObjectList.onPhysicsFlagsFetchFailure(it->asUUID()); +    } +} + +void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD idList; +    U32 objectIndex = 0; + +    for (std::set<LLUUID>::iterator it = mStalePhysicsFlags.begin(); it != mStalePhysicsFlags.end(); ) +    { +        // Check to see if a request for this object +        // has already been made. +        if (mPendingPhysicsFlags.find(*it) == mPendingPhysicsFlags.end()) +        { +            mPendingPhysicsFlags.insert(*it); +            idList[objectIndex++] = *it; +        } + +        mStalePhysicsFlags.erase(it++); + +        if (objectIndex >= MAX_CONCURRENT_PHYSICS_REQUESTS) +        { +            break; +        } +    } + +    if (idList.size() < 1) +    { +        LL_INFOS() << "No outstanding object physics flags to request." << LL_ENDL; +        return; +    } + +    LLSD postData = LLSD::emptyMap(); + +    postData["object_ids"] = idList; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status || result.has("error")) +    { +        if (result.has("error")) +        { +            LL_WARNS() << "Application level error when fetching object " +                << "physics flags.  Message: " << result["error"]["message"].asString() +                << ", identifier: " << result["error"]["identifier"].asString() +                << LL_ENDL; + +            // TODO*: Adaptively adjust request size if the +            // service says we've requested too many and retry +        } +        reportPhysicsFlagFailure(idList); + +        return; +    } + +    // Success, grab the resource cost and linked set costs +    // for an object if one was returned +    for (LLSD::array_iterator it = idList.beginArray(); it != idList.endArray(); ++it) +    { +        LLUUID objectId = it->asUUID(); + +        // Check to see if the request contains data for the object +        if (result.has(it->asString())) +        { +            const LLSD& data = result[it->asString()]; + +            S32 shapeType = data["PhysicsShapeType"].asInteger(); + +            gObjectList.updatePhysicsShapeType(objectId, shapeType); + +            if (data.has("Density")) +            { +                F32 density = data["Density"].asReal(); +                F32 friction = data["Friction"].asReal(); +                F32 restitution = data["Restitution"].asReal(); +                F32 gravityMult = data["GravityMultiplier"].asReal(); + +                gObjectList.updatePhysicsProperties(objectId, density,  +                    friction, restitution, gravityMult); +            } +        } +        else +        { +            // TODO*: Give user feedback about the missing data? +            gObjectList.onPhysicsFlagsFetchFailure(objectId); +        } +    } +}  void LLViewerObjectList::clearDebugText()  { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 594317cd9f..9ec7c4bc22 100755 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -36,6 +36,8 @@  // project includes  #include "llviewerobject.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLCamera;  class LLNetMap; @@ -227,6 +229,14 @@ protected:  	std::set<LLViewerObject *> mSelectPickList;  	friend class LLViewerObject; + +private: +    static void reportObjectCostFailure(LLSD &objectList); +    void fetchObjectCostsCoro(std::string url); + +    static void reportPhysicsFlagFailure(LLSD &obejectList); +    void fetchPhisicsFlagsCoro(std::string url); +  }; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 37b249dddd..828271da7a 100755 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -43,6 +43,7 @@  //#include "llfirstuse.h"  #include "llpluginclassmedia.h"  #include "llviewertexture.h" +#include "llcorehttputil.h"  // Static Variables @@ -457,6 +458,7 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void *  }  // Static  ///////////////////////////////////////////////////////////////////////////////////////// +// *TODO: I can not find any active code where this method is called...  void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url)  {  	std::string region_url = gAgent.getRegion()->getCapability("ParcelNavigateMedia"); @@ -467,7 +469,9 @@ void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url)  		body["agent-id"] = gAgent.getID();  		body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID();  		body["url"] = url; -		LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder); + +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(region_url, body, +            "Media Navigation sent to sim.", "Media Navigation failed to send to sim.");  	}  	else  	{ diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 59f57c218e..0fa6c432db 100755 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -67,6 +67,7 @@  #include "roles_constants.h"  #include "llweb.h"  #include "llvieweraudio.h" +#include "llcorehttputil.h"  const F32 PARCEL_COLLISION_DRAW_SECS = 1.f; @@ -1286,10 +1287,13 @@ const std::string& LLViewerParcelMgr::getAgentParcelName() const  void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region)  { -	if(!parcel) return; +	if(!parcel)  +        return;  	LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) return; +	if (!region)  +        return; +  	//LL_INFOS() << "found region: " << region->getName() << LL_ENDL;  	LLSD body; @@ -1302,7 +1306,9 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag  		parcel->packMessage(body);  		LL_INFOS() << "Sending parcel properties update via capability to: "  			<< url << LL_ENDL; -		LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); + +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, +            "Parcel Properties sent to sim.", "Parcel Properties failed to send to sim.");  	}  	else  	{ diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index ec28461201..b256482289 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -48,7 +48,6 @@  #include "llavatarrenderinfoaccountant.h"  #include "llcallingcard.h"  #include "llcaphttpsender.h" -#include "llcapabilitylistener.h"  #include "llcommandhandler.h"  #include "lldir.h"  #include "lleventpoll.h" @@ -78,6 +77,9 @@  #include "llviewerdisplay.h"  #include "llviewerwindow.h"  #include "llprogressview.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h"  #ifdef LL_WINDOWS  	#pragma warning(disable:4355) @@ -92,7 +94,6 @@  // We want to allow for seed cap retry, but its not useful after that 60 seconds.  // Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up.  const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; -const F32 CAP_REQUEST_TIMEOUT = 18;  // Even though we gave up on login, keep trying for caps after we are logged in:  const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;  const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000; @@ -105,31 +106,62 @@ typedef std::map<std::string, std::string> CapabilityMap;  static void log_capabilities(const CapabilityMap &capmap); -class LLViewerRegionImpl { +// support for secondlife:///app/region/{REGION} SLapps +// N.B. this is defined to work exactly like the classic secondlife://{REGION} +// However, the later syntax cannot support spaces in the region name because +// spaces (and %20 chars) are illegal in the hostname of an http URL. Some +// browsers let you get away with this, but some do not (such as Qt's Webkit). +// Hence we introduced the newer secondlife:///app/region alternative. +class LLRegionHandler : public LLCommandHandler +{ +public: +    // requests will be throttled from a non-trusted browser +    LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {} +        +    bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) +    { +        // make sure that we at least have a region name +        int num_params = params.size(); +        if (num_params < 1) +        { +            return false; +        } +            +        // build a secondlife://{PLACE} SLurl from this SLapp +        std::string url = "secondlife://"; +        for (int i = 0; i < num_params; i++) +        { +            if (i > 0) +            { +                url += "/"; +            } +            url += params[i].asString(); +        } +            +        // Process the SLapp as if it was a secondlife://{PLACE} SLurl +        LLURLDispatcher::dispatch(url, "clicked", web, true); +        return true; +    } +        +}; +LLRegionHandler gRegionHandler; + + +class LLViewerRegionImpl  +{  public: -	LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) -		:	mHost(host), -			mCompositionp(NULL), -			mEventPoll(NULL), -			mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), -			mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), -			mSeedCapAttempts(0), -			mHttpResponderID(0), -		mLastCameraUpdate(0), -		mLastCameraOrigin(), -		mVOCachePartition(NULL), -		mLandp(NULL), -		    // I'd prefer to set the LLCapabilityListener name to match the region -		    // name -- it's disappointing that's not available at construction time. -		    // We could instead store an LLCapabilityListener*, making -		    // setRegionNameAndZone() replace the instance. Would that pose -		    // consistency problems? Can we even request a capability before calling -		    // setRegionNameAndZone()? -		    // For testability -- the new Michael Feathers paradigm -- -		    // LLCapabilityListener binds all the globals it expects to need at -		    // construction time. -		    mCapabilityListener(host.getString(), gMessageSystem, *region, -		                        gAgent.getID(), gAgent.getSessionID()) +	LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host):    +        mHost(host), +        mCompositionp(NULL), +        mEventPoll(NULL), +        mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), +        mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), +        mSeedCapAttempts(0), +        mHttpResponderID(0), +        mLastCameraUpdate(0), +        mLastCameraOrigin(), +        mVOCachePartition(NULL), +        mLandp(NULL)  	{}  	void buildCapabilityNames(LLSD& capabilityNames); @@ -181,220 +213,284 @@ public:  	S32 mHttpResponderID; -	/// Post an event to this LLCapabilityListener to invoke a capability message on -	/// this LLViewerRegion's server -	/// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) -	LLCapabilityListener mCapabilityListener; -  	//spatial partitions for objects in this region  	std::vector<LLViewerOctreePartition*> mObjectPartition; -	LLVector3 mLastCameraOrigin; -	U32       mLastCameraUpdate; -}; - -// support for secondlife:///app/region/{REGION} SLapps -// N.B. this is defined to work exactly like the classic secondlife://{REGION} -// However, the later syntax cannot support spaces in the region name because -// spaces (and %20 chars) are illegal in the hostname of an http URL. Some -// browsers let you get away with this, but some do not (such as Qt's Webkit). -// Hence we introduced the newer secondlife:///app/region alternative. -class LLRegionHandler : public LLCommandHandler -{ -public: -	// requests will be throttled from a non-trusted browser -	LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {} - -	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) -	{ -		// make sure that we at least have a region name -		int num_params = params.size(); -		if (num_params < 1) -		{ -			return false; -		} - -		// build a secondlife://{PLACE} SLurl from this SLapp -		std::string url = "secondlife://"; -		for (int i = 0; i < num_params; i++) -		{ -			if (i > 0) -			{ -				url += "/"; -			} -			url += params[i].asString(); -		} +	LLVector3   mLastCameraOrigin; +	U32         mLastCameraUpdate; -		// Process the SLapp as if it was a secondlife://{PLACE} SLurl -		LLURLDispatcher::dispatch(url, "clicked", web, true); -		return true; -	} +    void        requestBaseCapabilitiesCoro(U64 regionHandle); +    void        requestBaseCapabilitiesCompleteCoro(U64 regionHandle); +    void        requestSimulatorFeatureCoro(std::string url, U64 regionHandle);  }; -LLRegionHandler gRegionHandler; -class BaseCapabilitiesComplete : public LLHTTPClient::Responder +void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)  { -	LOG_CLASS(BaseCapabilitiesComplete); -public: -	BaseCapabilitiesComplete(U64 region_handle, S32 id) -		: mRegionHandle(region_handle), mID(id) -	{ } -	virtual ~BaseCapabilitiesComplete() -	{ } - -	static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) -	{ -		return new BaseCapabilitiesComplete(region_handle, id); -	} - -private: -	/* virtual */void httpFailure() -	{ -		LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL; -		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if (regionp) -		{ -			regionp->failedSeedCapability(); -		} -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t  +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -	/* virtual */ void httpSuccess() -	{ -		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if(!regionp) //region was removed -		{ -			LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; -			return ; -		} -		if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder -		{ -			LL_WARNS("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; -			regionp->failedSeedCapability(); -			return ; -		} - -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		LLSD::map_const_iterator iter; -		for(iter = content.beginMap(); iter != content.endMap(); ++iter) -		{ -			regionp->setCapability(iter->first, iter->second); +    LLSD result; +    LLViewerRegion *regionp = NULL; -			LL_DEBUGS("AppInit", "Capabilities") -				<< "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; - -			/* HACK we're waiting for the ServerReleaseNotes */ -			if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) -			{ -				regionp->showReleaseNotes(); -			} -		} - -		regionp->setCapabilitiesReceived(true); +    // This loop is used for retrying a capabilities request. +    do +    { +        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +        if (!regionp) //region was removed +        { +            LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; +            return; // this error condition is not recoverable. +        } + +        std::string url = regionp->getCapability("Seed"); +        if (url.empty()) +        { +            LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL; +            return; // this error condition is not recoverable. +        } + +        // After a few attempts, continue login.  But keep trying to get the caps: +        if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin && +            STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) +        { +            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); +        } + +        if (mSeedCapAttempts > mSeedCapMaxAttempts) +        { +            // *TODO: Give a user pop-up about this error? +            LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mSeedCapAttempts << " attempts.  Giving up!" << LL_ENDL; +            return;  // this error condition is not recoverable. +        } + +        S32 id = ++mHttpResponderID; +        ++mSeedCapAttempts; + +        LLSD capabilityNames = LLSD::emptyArray(); +        buildCapabilityNames(capabilityNames); + +        LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url  +            << " (attempt #" << mSeedCapAttempts << ")" << LL_ENDL; + +        regionp = NULL; +        result = httpAdapter->postAndYield(httpRequest, url, capabilityNames); + +        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +        if (!regionp) //region was removed +        { +            LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; +            return; // this error condition is not recoverable. +        } + +        if (id != mHttpResponderID) // region is no longer referring to this request +        { +            LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL; +            // setup for retry. +            continue; +        } + +        LLSD httpResults = result["http_result"]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +        if (!status) +        { +            LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; +            // setup for retry. +            continue; +        } + +        // remove the http_result from the llsd +        result.erase("http_result"); + +        LLSD::map_const_iterator iter; +        for (iter = result.beginMap(); iter != result.endMap(); ++iter) +        { +            regionp->setCapability(iter->first, iter->second); + +            LL_DEBUGS("AppInit", "Capabilities") +                << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; +        } + +        regionp->setCapabilitiesReceived(true); + +        if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) +        { +            LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); +        } + +        break; +    }  +    while (true); + +    if (regionp && regionp->isCapabilityAvailable("ServerReleaseNotes") && +            regionp->getReleaseNotesRequested()) +    {   // *HACK: we're waiting for the ServerReleaseNotes +        regionp->showReleaseNotes(); +    } -		if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) -		{ -			LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); -		} -	} +} -private: -	U64 mRegionHandle; -	S32 mID; -}; -class BaseCapabilitiesCompleteTracker :  public LLHTTPClient::Responder +void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle)  { -	LOG_CLASS(BaseCapabilitiesCompleteTracker); -public: -	BaseCapabilitiesCompleteTracker( U64 region_handle) -	: mRegionHandle(region_handle) -	{ } -	 -	virtual ~BaseCapabilitiesCompleteTracker() -	{ } - -	static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) -	{ -		return new BaseCapabilitiesCompleteTracker( region_handle ); -	} - -private: -	/* virtual */ void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -	} +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -	/* virtual */ void httpSuccess() -	{ -		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if( !regionp )  -		{ -			LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; -			return ; -		} +    LLSD result; +    LLViewerRegion *regionp = NULL; -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		LLSD::map_const_iterator iter; -		for(iter = content.beginMap(); iter != content.endMap(); ++iter) -		{ -			regionp->setCapabilityDebug(iter->first, iter->second);	 -			//LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL; -		} -		 -		if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() ) -		{ -			LL_WARNS("AppInit", "Capabilities")  -				<< "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " -				<< "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() -				<< " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() -				<< LL_ENDL; +    // This loop is used for retrying a capabilities request. +    do +    { +        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +        if (!regionp) //region was removed +        { +            LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; +            break; // this error condition is not recoverable. +        } + +        std::string url = regionp->getCapabilityDebug("Seed"); +        if (url.empty()) +        { +            LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL; +            break; // this error condition is not recoverable. +        } + +        LLSD capabilityNames = LLSD::emptyArray(); +        buildCapabilityNames(capabilityNames); + +        LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << LL_ENDL; + +        regionp = NULL; +        result = httpAdapter->postAndYield(httpRequest, url, capabilityNames); + +        LLSD httpResults = result["http_result"]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +        if (!status) +        { +            LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; +            break;  // no retry +        } + +        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +        if (!regionp) //region was removed +        { +            LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; +            break; // this error condition is not recoverable. +        } + +        // remove the http_result from the llsd +        result.erase("http_result"); + +        LLSD::map_const_iterator iter; +        for (iter = result.beginMap(); iter != result.endMap(); ++iter) +        { +            regionp->setCapabilityDebug(iter->first, iter->second); +            //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL; +        } + +        if (mCapabilities.size() != mSecondCapabilitiesTracker.size()) +        { +            LL_WARNS("AppInit", "Capabilities") +                << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " +                << "mCapabilities == " << mCapabilities.size() +                << " mSecondCapabilitiesTracker == " << mSecondCapabilitiesTracker.size() +                << LL_ENDL;  #ifdef DEBUG_CAPS_GRANTS -			LL_WARNS("AppInit", "Capabilities") -				<< "Initial Base capabilities: " << LL_ENDL; +            LL_WARNS("AppInit", "Capabilities") +                << "Initial Base capabilities: " << LL_ENDL; -			log_capabilities(regionp->getRegionImpl()->mCapabilities); +            log_capabilities(mCapabilities); -			LL_WARNS("AppInit", "Capabilities") -							<< "Latest base capabilities: " << LL_ENDL; +            LL_WARNS("AppInit", "Capabilities") +                << "Latest base capabilities: " << LL_ENDL; -			log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); +            log_capabilities(mSecondCapabilitiesTracker);  #endif -			if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() ) -			{ -				// *HACK Since we were granted more base capabilities in this grant request than the initial, replace -				// the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a -				// sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the -				// inventory api capability grants. - -				// Need to clear a std::map before copying into it because old keys take precedence. -				regionp->getRegionImplNC()->mCapabilities.clear(); -				regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker; -			} -		} -		else -		{ -			LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; -		} -		regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); -	} +            if (mSecondCapabilitiesTracker.size() > mCapabilities.size()) +            { +                // *HACK Since we were granted more base capabilities in this grant request than the initial, replace +                // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a +                // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the +                // inventory api capability grants. +                // Need to clear a std::map before copying into it because old keys take precedence. +                mCapabilities.clear(); +                mCapabilities = mSecondCapabilitiesTracker; +            } +        } +        else +        { +            LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; +        } +        mSecondCapabilitiesTracker.clear(); +    }  +    while (false); -private: -	U64 mRegionHandle; -}; +} + +void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 regionHandle) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLViewerRegion *regionp = NULL; +    S32 attemptNumber = 0; +    // This loop is used for retrying a capabilities request. +    do +    { +        ++attemptNumber; + +        if (attemptNumber > MAX_CAP_REQUEST_ATTEMPTS) +        { +            LL_WARNS("AppInit", "SimulatorFeatures") << "Retries count exceeded attempting to get Simulator feature from "  +                << url << LL_ENDL; +            break; +        } + +        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +        if (!regionp) //region was removed +        { +            LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL; +            break; // this error condition is not recoverable. +        } + +        regionp = NULL; +        LLSD result = httpAdapter->getAndYield(httpRequest, url); + +        LLSD httpResults = result["http_result"]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +        if (!status) +        { +            LL_WARNS("AppInit", "SimulatorFeatures") << "HttpStatus error retrying" << LL_ENDL; +            continue;   +        } + +        // remove the http_result from the llsd +        result.erase("http_result"); + +        regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); +        if (!regionp) //region was removed +        { +            LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL; +            break; // this error condition is not recoverable. +        } + +        regionp->setSimulatorFeatures(result); + +        break; +    } +    while (true); + +}  LLViewerRegion::LLViewerRegion(const U64 &handle,  							   const LLHost &host, @@ -525,11 +621,6 @@ LLViewerRegion::~LLViewerRegion()  	mImpl = NULL;  } -LLEventPump& LLViewerRegion::getCapAPI() const -{ -	return mImpl->mCapabilityListener.getCapAPI(); -} -  /*virtual*/   const LLHost&	LLViewerRegion::getHost() const				  {  @@ -2810,15 +2901,14 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	if (getCapability("Seed") == url)      {	  		setCapabilityDebug("Seed", url); -		LL_DEBUGS("CrossingCaps") <<  "Received duplicate seed capability, posting to seed " << +		LL_WARNS("CrossingCaps") <<  "Received duplicate seed capability, posting to seed " <<  				url	<< LL_ENDL;  		//Instead of just returning we build up a second set of seed caps and compare them   		//to the "original" seed cap received and determine why there is problem! -		LLSD capabilityNames = LLSD::emptyArray(); -		mImpl->buildCapabilityNames( capabilityNames ); -		LLHTTPClient::post( url, capabilityNames, BaseCapabilitiesCompleteTracker::build(getHandle() ), -							LLSD(), CAP_REQUEST_TIMEOUT ); +        std::string coroname = +            LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro", +            boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, mImpl, getHandle()));  		return;      } @@ -2828,15 +2918,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)  	mImpl->mCapabilities.clear();  	setCapability("Seed", url); -	LLSD capabilityNames = LLSD::emptyArray(); -	mImpl->buildCapabilityNames(capabilityNames); - -	LL_INFOS() << "posting to seed " << url << LL_ENDL; +    std::string coroname = +        LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro", +        boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, mImpl, getHandle())); -	S32 id = ++mImpl->mHttpResponderID; -	LLHTTPClient::post(url, capabilityNames,  -						BaseCapabilitiesComplete::build(getHandle(), id), -						LLSD(), CAP_REQUEST_TIMEOUT); +    LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << LL_ENDL;  }  S32 LLViewerRegion::getNumSeedCapRetries() @@ -2844,94 +2930,6 @@ S32 LLViewerRegion::getNumSeedCapRetries()  	return mImpl->mSeedCapAttempts;  } -void LLViewerRegion::failedSeedCapability() -{ -	// Should we retry asking for caps? -	mImpl->mSeedCapAttempts++; -	std::string url = getCapability("Seed"); -	if ( url.empty() ) -	{ -		LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; -		return; -	} -	// After a few attempts, continue login.  We will keep trying once in-world: -	if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && -		 STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) -	{ -		LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); -	} - -	if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) -	{ -		LLSD capabilityNames = LLSD::emptyArray(); -		mImpl->buildCapabilityNames(capabilityNames); - -		LL_INFOS() << "posting to seed " << url << " (retry "  -				<< mImpl->mSeedCapAttempts << ")" << LL_ENDL; - -		S32 id = ++mImpl->mHttpResponderID; -		LLHTTPClient::post(url, capabilityNames,  -						BaseCapabilitiesComplete::build(getHandle(), id), -						LLSD(), CAP_REQUEST_TIMEOUT); -	} -	else -	{ -		// *TODO: Give a user pop-up about this error? -		LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts.  Giving up!" << LL_ENDL; -	} -} - -class SimulatorFeaturesReceived : public LLHTTPClient::Responder -{ -	LOG_CLASS(SimulatorFeaturesReceived); -public: -	SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle,  -							  S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) -		: mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) -	{ } - -	/* virtual */ void httpFailure() -	{ -		LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL; -		retry(); -	} - -	/* virtual */ void httpSuccess() -	{ -		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); -		if(!regionp) //region is removed or responder is not created. -		{ -			LL_WARNS("AppInit", "SimulatorFeatures")  -				<< "Received results for region that no longer exists!" << LL_ENDL; -			return ; -		} - -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		regionp->setSimulatorFeatures(content); -	} - -	void retry() -	{ -		if (mAttempt < mMaxAttempts) -		{ -			mAttempt++; -			LL_WARNS("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'.  Retry #" << mAttempt << LL_ENDL; -			LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); -		} -	} - -	std::string mRetryURL; -	U64 mRegionHandle; -	S32 mAttempt; -	S32 mMaxAttempts; -}; - -  void LLViewerRegion::setCapability(const std::string& name, const std::string& url)  {  	if(name == "EventQueueGet") @@ -2947,7 +2945,11 @@ 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); +        std::string coroname = +            LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", +            boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle())); + +        LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL;  	}  	else  	{ @@ -2970,9 +2972,20 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri  			mHttpUrl = url ;  		}  	} +} +std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const +{ +    CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name); +    if (iter == mImpl->mSecondCapabilitiesTracker.end()) +    { +        return ""; +    } + +    return iter->second;  } +  bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)  {  	return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index c14fa5aee8..8c4966369c 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -40,7 +40,6 @@  #include "llweb.h"  #include "llcapabilityprovider.h"  #include "m4math.h"					// LLMatrix4 -#include "llhttpclient.h"  #include "llframetimer.h"  // Surface id's @@ -62,7 +61,6 @@ class LLVOCache;  class LLVOCacheEntry;  class LLSpatialPartition;  class LLEventPump; -class LLCapabilityListener;  class LLDataPacker;  class LLDataPackerBinaryBuffer;  class LLHost; @@ -253,13 +251,14 @@ public:  	// Get/set named capability URLs for this region.  	void setSeedCapability(const std::string& url); -	void failedSeedCapability();  	S32 getNumSeedCapRetries();  	void setCapability(const std::string& name, const std::string& url);  	void setCapabilityDebug(const std::string& name, const std::string& url);  	bool isCapabilityAvailable(const std::string& name) const;  	// implements LLCapabilityProvider      virtual std::string getCapability(const std::string& name) const; +    std::string getCapabilityDebug(const std::string& name) const; +  	// has region received its final (not seed) capability list?  	bool capabilitiesReceived() const; @@ -269,10 +268,6 @@ public:  	static bool isSpecialCapabilityName(const std::string &name);  	void logActiveCapabilities() const; -    /// Get LLEventPump on which we listen for capability requests -    /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) -    LLEventPump& getCapAPI() const; -      /// implements LLCapabilityProvider  	/*virtual*/ const LLHost& getHost() const;  	const U64 		&getHandle() const 			{ return mHandle; } diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index f60829e9e8..2c3067cd3a 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -60,6 +60,7 @@  #include "llfeaturemanager.h"  #include "llviewernetwork.h"  #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived +#include "llcorehttputil.h"  namespace LLStatViewer  { @@ -410,24 +411,6 @@ void update_statistics()  	}  } -class ViewerStatsResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(ViewerStatsResponder); -public: -	ViewerStatsResponder() { } - -private: -	/* virtual */ void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -	} - -	/* virtual */ void httpSuccess() -	{ -		LL_INFOS() << "OK" << LL_ENDL; -	} -}; -  /*   * The sim-side LLSD is in newsim/llagentinfo.cpp:forwardViewerStats.   * @@ -618,8 +601,8 @@ void send_stats()  	body["MinimalSkin"] = false;  	LLViewerStats::getInstance()->addToMessage(body); -	LLHTTPClient::post(url, body, new ViewerStatsResponder()); - +    LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, +        "Statistics posted to sim", "Failed to post statistics to sim");  	LLViewerStats::instance().getRecording().resume();  } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 56997c928a..7c460ce097 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -64,6 +64,7 @@  #include "llsdutil.h"  #include "llstartup.h"  #include "llsdserialize.h" +#include "llcorehttputil.h"  #if LL_MSVC  // disable boost::lexical_cast warning @@ -105,6 +106,9 @@ void selfClearPhases()  using namespace LLAvatarAppearanceDefines; + +LLSD summarize_by_buckets(std::vector<LLSD> in_records, std::vector<std::string> by_fields, std::string val_field); +  /*********************************************************************************   **                                                                             **   ** Begin private LLVOAvatarSelf Support classes @@ -127,25 +131,6 @@ struct LocalTextureData  	LLTextureEntry *mTexEntry;  }; -// TODO - this class doesn't really do anything, could just use a base -// class responder if nothing else gets added. -class LLHoverHeightResponder: public LLHTTPClient::Responder -{ -public: -	LLHoverHeightResponder(): LLHTTPClient::Responder() {} - -private: -	void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -	} - -	void httpSuccess() -	{ -		LL_INFOS() << dumpResponse() << LL_ENDL; -	} -}; -  //-----------------------------------------------------------------------------  // Callback data  //----------------------------------------------------------------------------- @@ -180,7 +165,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,  	mRegionCrossingCount(0),  	// Value outside legal range, so will always be a mismatch the  	// first time through. -	mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)) +	mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)), +    mInitialMetric(true), +    mMetricSequence(0)  {  	mMotionController.mIsSelf = TRUE; @@ -2203,43 +2190,76 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const  	return text;  } -class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder -{ -	LOG_CLASS(ViewerAppearanceChangeMetricsResponder); -public: -	ViewerAppearanceChangeMetricsResponder( S32 expected_sequence, -											volatile const S32 & live_sequence, -											volatile bool & reporting_started): -		mExpectedSequence(expected_sequence), -		mLiveSequence(live_sequence), -		mReportingStarted(reporting_started) -	{ -	} - -private: -	/* virtual */ void httpSuccess() -	{ -		LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - -		gPendingMetricsUploads--; -		if (mLiveSequence == mExpectedSequence) -		{ -			mReportingStarted = true; -		} -	} - -	/* virtual */ void httpFailure() -	{ -		// if we add retry, this should be removed from the httpFailure case -		LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; -		gPendingMetricsUploads--; -	} - -private: -	S32 mExpectedSequence; -	volatile const S32 & mLiveSequence; -	volatile bool & mReportingStarted; -}; +void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("appearanceChangeMetrics", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + +    S32 currentSequence = mMetricSequence; +    if (S32_MAX == ++mMetricSequence) +        mMetricSequence = 0; + +    LLSD msg; +    msg["message"] = "ViewerAppearanceChangeMetrics"; +    msg["session_id"] = gAgentSessionID; +    msg["agent_id"] = gAgentID; +    msg["sequence"] = currentSequence; +    msg["initial"] = mInitialMetric; +    msg["break"] = false; +    msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32(); + +    // Status of our own rezzing. +    msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); + +    // Status of all nearby avs including ourself. +    msg["nearby"] = LLSD::emptyArray(); +    std::vector<S32> rez_counts; +    LLVOAvatar::getNearbyRezzedStats(rez_counts); +    for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat) +    { +        std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat); +        msg["nearby"][rez_status_name] = rez_counts[rez_stat]; +    } + +    //	std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake"); +    std::vector<std::string> by_fields; +    by_fields.push_back("timer_name"); +    by_fields.push_back("completed"); +    by_fields.push_back("grid_x"); +    by_fields.push_back("grid_y"); +    by_fields.push_back("is_using_server_bakes"); +    by_fields.push_back("is_self"); +    by_fields.push_back("central_bake_version"); +    LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed")); +    msg["timers"] = summary; + +    mPendingTimerRecords.clear(); + +    LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL; + +    gPendingMetricsUploads++; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, msg); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    gPendingMetricsUploads--; + +    if (!status) +    { +        LL_WARNS("Avatar") << "Unable to upload statistics" << LL_ENDL; +        return; +    } +    else +    { +        LL_INFOS("Avatar") << "Statistics upload OK" << LL_ENDL; +        mInitialMetric = false; +    } +}  bool LLVOAvatarSelf::updateAvatarRezMetrics(bool force_send)  { @@ -2317,51 +2337,7 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,  void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  { -	static volatile bool reporting_started(false); -	static volatile S32 report_sequence(0); - -	LLSD msg; -	msg["message"] = "ViewerAppearanceChangeMetrics"; -	msg["session_id"] = gAgentSessionID; -	msg["agent_id"] = gAgentID; -	msg["sequence"] = report_sequence; -	msg["initial"] = !reporting_started; -	msg["break"] = false; -	msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32(); - -	// Status of our own rezzing. -	msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); - -	// Status of all nearby avs including ourself. -	msg["nearby"] = LLSD::emptyArray(); -	std::vector<S32> rez_counts; -	LLVOAvatar::getNearbyRezzedStats(rez_counts); -	for (S32 rez_stat=0; rez_stat < rez_counts.size(); ++rez_stat) -	{ -		std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat); -		msg["nearby"][rez_status_name] = rez_counts[rez_stat]; -	} - -	//	std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake"); -	std::vector<std::string> by_fields; -	by_fields.push_back("timer_name"); -	by_fields.push_back("completed"); -	by_fields.push_back("grid_x"); -	by_fields.push_back("grid_y"); -	by_fields.push_back("is_using_server_bakes"); -	by_fields.push_back("is_self"); -	by_fields.push_back("central_bake_version"); -	LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed")); -	msg["timers"] = summary; - -	mPendingTimerRecords.clear(); - -	// Update sequence number -	if (S32_MAX == ++report_sequence) -		report_sequence = 0; - -	LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL; -	std::string	caps_url; +    std::string	caps_url;  	if (getRegion())  	{  		// runway - change here to activate. @@ -2369,13 +2345,9 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  	}  	if (!caps_url.empty())  	{ -		gPendingMetricsUploads++; -		LLCurlRequest::headers_t headers; -		LLHTTPClient::post(caps_url, -						   msg, -						   new ViewerAppearanceChangeMetricsResponder(report_sequence, -																	  report_sequence, -																	  reporting_started)); + +        LLCoros::instance().launch("LLVOAvatarSelf::appearanceChangeMetricsCoro", +            boost::bind(&LLVOAvatarSelf::appearanceChangeMetricsCoro, this, caps_url));  		mTimeSinceLastRezMessage.reset();  	}  } @@ -2798,8 +2770,12 @@ void LLVOAvatarSelf::sendHoverHeight() const  		update["hover_height"] = hover_offset[2];  		LL_DEBUGS("Avatar") << avString() << "sending hover height value " << hover_offset[2] << LL_ENDL; -		LLHTTPClient::post(url, update, new LLHoverHeightResponder); +        // *TODO: - this class doesn't really do anything, could just use a base +        // class responder if nothing else gets added.  +        // (comment from removed Responder) +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, update,  +            "Hover hight sent to sim", "Hover hight not sent to sim");  		mLastHoverOffsetSent = hover_offset;  	}  } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index dc5e64d547..d32c959fb5 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -31,6 +31,8 @@  #include "llviewertexture.h"  #include "llvoavatar.h"  #include <map> +#include "lleventcoro.h" +#include "llcoros.h"  struct LocalTextureData;  class LLInventoryCallback; @@ -400,6 +402,9 @@ private:  	F32 					mDebugBakedTextureTimes[LLAvatarAppearanceDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture  	void					debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); +    void                    appearanceChangeMetricsCoro(std::string url); +    bool                    mInitialMetric; +    S32                     mMetricSequence;  /**                    Diagnostics   **                                                                            **   *******************************************************************************/ diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 426ca332e4..192d50ae9b 100755 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -28,7 +28,6 @@  #include "llagent.h"  #include "llfloaterreg.h" -#include "llhttpclient.h"  #include "llimview.h"  #include "llnotifications.h"  #include "llnotificationsutil.h" @@ -37,7 +36,7 @@  #include "llviewercontrol.h"  #include "llviewerregion.h"  #include "llvoicechannel.h" - +#include "llcorehttputil.h"  LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;  LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; @@ -52,71 +51,6 @@ BOOL LLVoiceChannel::sSuspended = FALSE;  //  const U32 DEFAULT_RETRIES_COUNT = 3; - -class LLVoiceCallCapResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLVoiceCallCapResponder); -public: -	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; - -protected: -	// called with bad status codes -	virtual void httpFailure(); -	virtual void httpSuccess(); - -private: -	LLUUID mSessionID; -}; - - -void LLVoiceCallCapResponder::httpFailure() -{ -	LL_WARNS("Voice") << dumpResponse() << LL_ENDL; -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if ( channelp ) -	{ -		if ( HTTP_FORBIDDEN == getStatus() ) -		{ -			//403 == no ability -			LLNotificationsUtil::add( -				"VoiceNotAllowed", -				channelp->getNotifyArgs()); -		} -		else -		{ -			LLNotificationsUtil::add( -				"VoiceCallGenericError", -				channelp->getNotifyArgs()); -		} -		channelp->deactivate(); -	} -} - -void LLVoiceCallCapResponder::httpSuccess() -{ -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if (channelp) -	{ -		//*TODO: DEBUG SPAM -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		LLSD::map_const_iterator iter; -		for(iter = content.beginMap(); iter != content.endMap(); ++iter) -		{ -			LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got "  -				<< iter->first << LL_ENDL; -		} - -		channelp->setChannelInfo( -			content["voice_credentials"]["channel_uri"].asString(), -			content["voice_credentials"]["channel_credentials"].asString()); -	} -} -  //  // LLVoiceChannel  // @@ -545,12 +479,9 @@ void LLVoiceChannelGroup::getChannelInfo()  	if (region)  	{  		std::string url = region->getCapability("ChatSessionRequest"); -		LLSD data; -		data["method"] = "call"; -		data["session-id"] = mSessionID; -		LLHTTPClient::post(url, -						   data, -						   new LLVoiceCallCapResponder(mSessionID)); + +        LLCoros::instance().launch("LLVoiceChannelGroup::voiceCallCapCoro", +            boost::bind(&LLVoiceChannelGroup::voiceCallCapCoro, this, url));  	}  } @@ -673,6 +604,66 @@ void LLVoiceChannelGroup::setState(EState state)  	}  } +void LLVoiceChannelGroup::voiceCallCapCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceCallCapCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD postData; +    postData["method"] = "call"; +    postData["session-id"] = mSessionID; + +    LL_INFOS("Voice", "voiceCallCapCoro") << "Generic POST for " << url << LL_ENDL; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +    if (!channelp) +    { +        LL_WARNS("Voice") << "Unable to retrieve channel with Id = " << mSessionID << LL_ENDL; +        return; +    } + +    if (!status) +    { +        if (status == LLCore::HttpStatus(HTTP_FORBIDDEN)) +        { +            //403 == no ability +            LLNotificationsUtil::add( +                "VoiceNotAllowed", +                channelp->getNotifyArgs()); +        } +        else +        { +            LLNotificationsUtil::add( +                "VoiceCallGenericError", +                channelp->getNotifyArgs()); +        } +        channelp->deactivate(); +        return; +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + +    LLSD::map_const_iterator iter; +    for (iter = result.beginMap(); iter != result.endMap(); ++iter) +    { +        LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " +            << iter->first << LL_ENDL; +    } + +    channelp->setChannelInfo( +        result["voice_credentials"]["channel_uri"].asString(), +        result["voice_credentials"]["channel_credentials"].asString()); + +} + +  //  // LLVoiceChannelProximal  // diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index fed44974fd..ef15b2c79e 100755 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -29,6 +29,8 @@  #include "llhandle.h"  #include "llvoiceclient.h" +#include "lleventcoro.h" +#include "llcoros.h"  class LLPanel; @@ -157,6 +159,8 @@ protected:  	virtual void setState(EState state);  private: +    void voiceCallCapCoro(std::string url); +  	U32 mRetries;  	BOOL mIsRetrying;  }; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a6a7a35b03..f50ffdeae7 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -64,6 +64,8 @@  #include "llviewernetwork.h"  #include "llnotificationsutil.h" +#include "llcorehttputil.h" +  #include "stringize.h"  // for base64 decoding @@ -122,66 +124,6 @@ static int scale_speaker_volume(float volume)  } -class LLVivoxVoiceAccountProvisionResponder : -	public LLHTTPClient::Responder -{ -	LOG_CLASS(LLVivoxVoiceAccountProvisionResponder); -public: -	LLVivoxVoiceAccountProvisionResponder(int retries) -	{ -		mRetries = retries; -	} - -private: -	/* virtual */ void httpFailure() -	{ -		LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, " -			<<  ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) -			<< " " << dumpResponse() << LL_ENDL; - -		if ( mRetries > 0 ) -		{ -			LLVivoxVoiceClient::getInstance()->requestVoiceAccountProvision(mRetries - 1); -		} -		else -		{ -			LLVivoxVoiceClient::getInstance()->giveUp(); -		} -	} - -	/* virtual */ void httpSuccess() -	{ -		std::string voice_sip_uri_hostname; -		std::string voice_account_server_uri; -		 -		LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; -		 -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		if(content.has("voice_sip_uri_hostname")) -			voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); -		 -		// this key is actually misnamed -- it will be an entire URI, not just a hostname. -		if(content.has("voice_account_server_name")) -			voice_account_server_uri = content["voice_account_server_name"].asString(); -		 -		LLVivoxVoiceClient::getInstance()->login( -			content["username"].asString(), -			content["password"].asString(), -			voice_sip_uri_hostname, -			voice_account_server_uri); -	} - -private: -	int mRetries; -}; - - -  ///////////////////////////////////////////////////////////////////////////////////////////////  class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver @@ -194,59 +136,6 @@ static LLVivoxVoiceClientMuteListObserver mutelist_listener;  static bool sMuteListListener_listening = false;  /////////////////////////////////////////////////////////////////////////////////////////////// - -class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLVivoxVoiceClientCapResponder); -public: -	LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; - -private: -	// called with bad status codes -	/* virtual */ void httpFailure(); -	/* virtual */ void httpSuccess(); - -	LLVivoxVoiceClient::state mRequestingState;  // state  -}; - -void LLVivoxVoiceClientCapResponder::httpFailure() -{ -	LL_WARNS("Voice") << dumpResponse() << LL_ENDL; -	LLVivoxVoiceClient::getInstance()->sessionTerminate(); -} - -void LLVivoxVoiceClientCapResponder::httpSuccess() -{ -	LLSD::map_const_iterator iter; -	 -	LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL; - -	std::string uri; -	std::string credentials; -	 -	const LLSD& content = getContent(); -	if ( content.has("voice_credentials") ) -	{ -		LLSD voice_credentials = content["voice_credentials"]; -		if ( voice_credentials.has("channel_uri") ) -		{ -			uri = voice_credentials["channel_uri"].asString(); -		} -		if ( voice_credentials.has("channel_credentials") ) -		{ -			credentials = -				voice_credentials["channel_credentials"].asString(); -		} -	} -	 -	// set the spatial channel.  If no voice credentials or uri are  -	// available, then we simply drop out of voice spatially. -	if(LLVivoxVoiceClient::getInstance()->parcelVoiceInfoReceived(mRequestingState)) -	{ -		LLVivoxVoiceClient::getInstance()->setSpatialChannel(uri, credentials); -	} -} -  static LLProcessPtr sGatewayPtr;  static bool isGatewayRunning() @@ -556,16 +445,51 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries)  		if ( !url.empty() )   		{ -			LLHTTPClient::post( -							   url, -							   LLSD(), -							   new LLVivoxVoiceAccountProvisionResponder(retries)); -		 +            LLCoros::instance().launch("LLVivoxVoiceClient::voiceAccountProvisionCoro", +                boost::bind(&LLVivoxVoiceClient::voiceAccountProvisionCoro, this, url, retries));  			setState(stateConnectorStart);		  		}  	}  } +void LLVivoxVoiceClient::voiceAccountProvisionCoro(std::string url, S32 retries) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + +    httpOpts->setRetries(retries); + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, LLSD(), httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL; +        giveUp(); +        return; +    } + +    std::string voice_sip_uri_hostname; +    std::string voice_account_server_uri; + +    //LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; + +    if (result.has("voice_sip_uri_hostname")) +        voice_sip_uri_hostname = result["voice_sip_uri_hostname"].asString(); + +    // this key is actually misnamed -- it will be an entire URI, not just a hostname. +    if (result.has("voice_account_server_name")) +        voice_account_server_uri = result["voice_account_server_name"].asString(); + +    login(result["username"].asString(), result["password"].asString(), +        voice_sip_uri_hostname, voice_account_server_uri); +} +  void LLVivoxVoiceClient::login(  	const std::string& account_name,  	const std::string& password, @@ -4003,14 +3927,60 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo()  		LLSD data;  		LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL; -		LLHTTPClient::post( -						url, -						data, -						new LLVivoxVoiceClientCapResponder(getState())); +        LLCoros::instance().launch("LLVivoxVoiceClient::parcelVoiceInfoRequestCoro", +            boost::bind(&LLVivoxVoiceClient::parcelVoiceInfoRequestCoro, this, url));  		return true;  	}  } +void LLVivoxVoiceClient::parcelVoiceInfoRequestCoro(std::string url) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("parcelVoiceInfoRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    state requestingState = getState(); + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, LLSD()); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("Voice") << "No voice on parcel" << LL_ENDL; +        sessionTerminate(); +        return; +    } + +    std::string uri; +    std::string credentials; + +    if (result.has("voice_credentials")) +    { +        LLSD voice_credentials = result["voice_credentials"]; +        if (voice_credentials.has("channel_uri")) +        { +            uri = voice_credentials["channel_uri"].asString(); +        } +        if (voice_credentials.has("channel_credentials")) +        { +            credentials = +                voice_credentials["channel_credentials"].asString(); +        } +    } + +    LL_INFOS("Voice") << "Voice URI is " << uri << LL_ENDL; + +    // set the spatial channel.  If no voice credentials or uri are  +    // available, then we simply drop out of voice spatially. +    if (parcelVoiceInfoReceived(requestingState)) +    { +        setSpatialChannel(uri, credentials); +    } + +} +  void LLVivoxVoiceClient::switchChannel(  	std::string uri,  	bool spatial, diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index a4ec9f2a69..b12ed80e41 100755 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -37,6 +37,9 @@ class LLVivoxProtocolParser;  #include "llframetimer.h"  #include "llviewerregion.h"  #include "llcallingcard.h"   // for LLFriendObserver +#include "lleventcoro.h" +#include "llcoros.h" +#include <queue>  #ifdef LL_USESYSTEMLIBS  # include "expat.h" @@ -46,7 +49,6 @@ class LLVivoxProtocolParser;  #include "llvoiceclient.h"  class LLAvatarName; -class LLVivoxVoiceAccountProvisionResponder;  class LLVivoxVoiceClientMuteListObserver; @@ -251,7 +253,6 @@ protected:  	//////////////////////  	// Vivox Specific definitions	 -	friend class LLVivoxVoiceAccountProvisionResponder;  	friend class LLVivoxVoiceClientMuteListObserver;  	friend class LLVivoxVoiceClientFriendsObserver;	 @@ -635,6 +636,10 @@ protected:  	void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString);   private: +     +    void voiceAccountProvisionCoro(std::string url, S32 retries); +    void parcelVoiceInfoRequestCoro(std::string url); +  	LLVoiceVersionInfo mVoiceVersion;  	/// Clean up objects created during a voice session. diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index ddb7f7bfce..2033a5f36a 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -30,14 +30,17 @@  // libs  #include "llbufferstream.h" -#include "llhttpclient.h"  #include "llimagepng.h"  #include "llplugincookiestore.h" +#include "llsdserialize.h" +  // newview  #include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions  #include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals +#include "llcorehttputil.h" +  // third-party  #include "reader.h" // JSON @@ -55,139 +58,6 @@   */  /////////////////////////////////////////////////////////////////////////////// -// LLWebProfileResponders::ConfigResponder - -class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLWebProfileResponders::ConfigResponder); - -public: -	ConfigResponder(LLPointer<LLImageFormatted> imagep) -	:	mImagep(imagep) -	{ -	} - -	// *TODO: Check for 'application/json' content type, and parse json at the base class. -	/*virtual*/ void completedRaw( -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer) -	{ -		LLBufferStream istr(channels, buffer.get()); -		std::stringstream strstrm; -		strstrm << istr.rdbuf(); -		const std::string body = strstrm.str(); - -		if (getStatus() != HTTP_OK) -		{ -			LL_WARNS() << "Failed to get upload config " << dumpResponse() << LL_ENDL; -			LLWebProfile::reportImageUploadStatus(false); -			return; -		} - -		Json::Value root; -		Json::Reader reader; -		if (!reader.parse(body, root)) -		{ -			LL_WARNS() << "Failed to parse upload config: " << reader.getFormatedErrorMessages() << LL_ENDL; -			LLWebProfile::reportImageUploadStatus(false); -			return; -		} - -		// *TODO: 404 = not supported by the grid -		// *TODO: increase timeout or handle 499 Expired - -		// Convert config to LLSD. -		const Json::Value data = root["data"]; -		const std::string upload_url = root["url"].asString(); -		LLSD config; -		config["acl"]						= data["acl"].asString(); -		config["AWSAccessKeyId"]			= data["AWSAccessKeyId"].asString(); -		config["Content-Type"]				= data["Content-Type"].asString(); -		config["key"]						= data["key"].asString(); -		config["policy"]					= data["policy"].asString(); -		config["success_action_redirect"]	= data["success_action_redirect"].asString(); -		config["signature"]					= data["signature"].asString(); -		config["add_loc"]					= data.get("add_loc", "0").asString(); -		config["caption"]					= data.get("caption", "").asString(); - -		// Do the actual image upload using the configuration. -		LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL; -		LLWebProfile::post(mImagep, config, upload_url); -	} - -private: -	LLPointer<LLImageFormatted> mImagep; -}; - -/////////////////////////////////////////////////////////////////////////////// -// LLWebProfilePostImageRedirectResponder -class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLWebProfileResponders::PostImageRedirectResponder); - -public: -	/*virtual*/ void completedRaw( -		const LLChannelDescriptors& channels, -		const LLIOPipe::buffer_ptr_t& buffer) -	{ -		if (getStatus() != HTTP_OK) -		{ -			LL_WARNS() << "Failed to upload image " << dumpResponse() << LL_ENDL; -			LLWebProfile::reportImageUploadStatus(false); -			return; -		} - -		LLBufferStream istr(channels, buffer.get()); -		std::stringstream strstrm; -		strstrm << istr.rdbuf(); -		const std::string body = strstrm.str(); -		LL_INFOS() << "Image uploaded." << LL_ENDL; -		LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL; -		LLWebProfile::reportImageUploadStatus(true); -	} -}; - - -/////////////////////////////////////////////////////////////////////////////// -// LLWebProfileResponders::PostImageResponder -class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLWebProfileResponders::PostImageResponder); - -public: -	/*virtual*/ void completedRaw(const LLChannelDescriptors& channels, -								  const LLIOPipe::buffer_ptr_t& buffer) -	{ -		// Viewer seems to fail to follow a 303 redirect on POST request -		// (URLRequest Error: 65, Send failed since rewinding of the data stream failed). -		// Handle it manually. -		if (getStatus() == HTTP_SEE_OTHER) -		{ -			LLSD headers = LLViewerMedia::getHeaders(); -			headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie(); -			const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION); -			if (redir_url.empty()) -			{ -				LL_WARNS() << "Received empty redirection URL " << dumpResponse() << LL_ENDL; -				LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -				LLWebProfile::reportImageUploadStatus(false); -			} -			else -			{ -				LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; -				LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); -			} -		} -		else -		{ -			LL_WARNS() << "Unexpected POST response " << dumpResponse() << LL_ENDL; -			LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; -			LLWebProfile::reportImageUploadStatus(false); -		} -	} -}; - -///////////////////////////////////////////////////////////////////////////////  // LLWebProfile  std::string LLWebProfile::sAuthCookie; @@ -196,15 +66,9 @@ LLWebProfile::status_callback_t LLWebProfile::mStatusCallback;  // static  void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::string& caption, bool add_location)  { -	// Get upload configuration data. -	std::string config_url(getProfileURL(LLStringUtil::null) + "snapshots/s3_upload_config"); -	config_url += "?caption=" + LLURI::escape(caption); -	config_url += "&add_loc=" + std::string(add_location ? "1" : "0"); - -	LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL; -	LLSD headers = LLViewerMedia::getHeaders(); -	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); -	LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers); +    LLCoros::instance().launch("LLWebProfile::uploadImageCoro", +        boost::bind(&LLWebProfile::uploadImageCoro, image, caption, add_location)); +  }  // static @@ -214,74 +78,178 @@ void LLWebProfile::setAuthCookie(const std::string& cookie)  	sAuthCookie = cookie;  } -// static -void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url) + +/*static*/ +LLCore::HttpHeaders::ptr_t LLWebProfile::buildDefaultHeaders()  { -	if (dynamic_cast<LLImagePNG*>(image.get()) == 0) -	{ -		LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL; -		llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0); -		return; -	} +    LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); +    LLSD headers = LLViewerMedia::getHeaders(); -	const std::string boundary = "----------------------------0123abcdefab"; +    for (LLSD::map_iterator it = headers.beginMap(); it != headers.endMap(); ++it) +    { +        httpHeaders->append((*it).first, (*it).second.asStringRef()); +    } -	LLSD headers = LLViewerMedia::getHeaders(); -	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); -	headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary; +    return httpHeaders; +} -	std::ostringstream body; -	// *NOTE: The order seems to matter. -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"key\"\r\n\r\n" -			<< config["key"].asString() << "\r\n"; +/*static*/ +void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::string caption, bool addLocation) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); +    LLCore::HttpHeaders::ptr_t httpHeaders; -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n" -			<< config["AWSAccessKeyId"].asString() << "\r\n"; +    if (dynamic_cast<LLImagePNG*>(image.get()) == 0) +    { +        LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL; +        llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0); +        return; +    } -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"acl\"\r\n\r\n" -			<< config["acl"].asString() << "\r\n"; +    httpOpts->setWantHeaders(true); +    httpOpts->setFollowRedirects(false); -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n" -			<< config["Content-Type"].asString() << "\r\n"; +    // Get upload configuration data. +    std::string configUrl(getProfileURL(std::string()) + "snapshots/s3_upload_config"); +    configUrl += "?caption=" + LLURI::escape(caption); +    configUrl += "&add_loc=" + std::string(addLocation ? "1" : "0"); -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"policy\"\r\n\r\n" -			<< config["policy"].asString() << "\r\n"; +    LL_DEBUGS("Snapshots") << "Requesting " << configUrl << LL_ENDL; -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"signature\"\r\n\r\n" -			<< config["signature"].asString() << "\r\n"; +    httpHeaders = buildDefaultHeaders(); +    httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie()); -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n" -			<< config["success_action_redirect"].asString() << "\r\n"; +    LLSD result = httpAdapter->getJsonAndYield(httpRequest, configUrl, httpOpts, httpHeaders); -	body	<< "--" << boundary << "\r\n" -			<< "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" -			<< "Content-Type: image/png\r\n\r\n"; +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); -	// Insert the image data. -	// *FIX: Treating this as a string will probably screw it up ... -	U8* image_data = image->getData(); -	for (S32 i = 0; i < image->getDataSize(); ++i) -	{ -		body << image_data[i]; -	} +    if (!status) +    { +        LL_WARNS("Snapshots") << "Failed to get image upload config" << LL_ENDL; +        LLWebProfile::reportImageUploadStatus(false); +        return; +    } + +    // Ready to build our image post body. + +    const LLSD &data = result["data"]; +    const std::string &uploadUrl = result["url"].asStringRef(); +    const std::string boundary = "----------------------------0123abcdefab"; + +    // a new set of headers. +    httpHeaders = LLWebProfile::buildDefaultHeaders(); +    httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie()); +    httpHeaders->remove(HTTP_OUT_HEADER_CONTENT_TYPE); +    httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary); +     +    LLCore::BufferArray::ptr_t body = LLWebProfile::buildPostData(data, image, boundary); + +    result = httpAdapter->postAndYield(httpRequest, uploadUrl, body, httpOpts, httpHeaders); + +    body.reset(); +    httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); -	body <<	"\r\n--" << boundary << "--\r\n"; +    if (!status && (status != LLCore::HttpStatus(HTTP_SEE_OTHER))) +    { +        LL_WARNS("Snapshots") << "Failed to upload image data." << LL_ENDL; +        LLWebProfile::reportImageUploadStatus(false); +        return; +    } -	// postRaw() takes ownership of the buffer and releases it later. -	size_t size = body.str().size(); -	U8 *data = new U8[size]; -	memcpy(data, body.str().data(), size); +    LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; -	// Send request, successful upload will trigger posting metadata. -	LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers); +    httpHeaders = LLWebProfile::buildDefaultHeaders(); +    httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie()); + +    const std::string& redirUrl = resultHeaders[HTTP_IN_HEADER_LOCATION].asStringRef(); + +    if (redirUrl.empty()) +    { +        LL_WARNS("Snapshots") << "Received empty redirection URL in post image." << LL_ENDL; +        LLWebProfile::reportImageUploadStatus(false); +    } + +    LL_DEBUGS("Snapshots") << "Got redirection URL: " << redirUrl << LL_ENDL; + +    result = httpAdapter->getRawAndYield(httpRequest, redirUrl, httpOpts, httpHeaders); + +    httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (status != LLCore::HttpStatus(HTTP_OK)) +    { +        LL_WARNS("Snapshots") << "Failed to upload image." << LL_ENDL; +        LLWebProfile::reportImageUploadStatus(false); +        return; +    } + +    //LLSD raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW]; + +    LL_INFOS("Snapshots") << "Image uploaded." << LL_ENDL; +    //LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << raw.asString() << "]" << LL_ENDL; +    LLWebProfile::reportImageUploadStatus(true); + + +} + +/*static*/ +LLCore::BufferArray::ptr_t LLWebProfile::buildPostData(const LLSD &data, LLPointer<LLImageFormatted> &image, const std::string &boundary) +{ +    LLCore::BufferArray::ptr_t body(new LLCore::BufferArray); +    LLCore::BufferArrayStream bas(body.get()); + +    // *NOTE: The order seems to matter. +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"key\"\r\n\r\n" +        << data["key"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n" +        << data["AWSAccessKeyId"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"acl\"\r\n\r\n" +        << data["acl"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n" +        << data["Content-Type"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"policy\"\r\n\r\n" +        << data["policy"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"signature\"\r\n\r\n" +        << data["signature"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n" +        << data["success_action_redirect"].asString() << "\r\n"; + +    bas << "--" << boundary << "\r\n" +        << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" +        << "Content-Type: image/png\r\n\r\n"; + +    // Insert the image data. +    //char *datap = (char *)(image->getData()); +    //bas.write(datap, image->getDataSize()); +    U8* image_data = image->getData(); +    for (S32 i = 0; i < image->getDataSize(); ++i) +    { +        bas << image_data[i]; +    } + +    bas << "\r\n--" << boundary << "--\r\n"; + +    return body;  }  // static diff --git a/indra/newview/llwebprofile.h b/indra/newview/llwebprofile.h index 10279bffac..6227e00afe 100755 --- a/indra/newview/llwebprofile.h +++ b/indra/newview/llwebprofile.h @@ -28,6 +28,10 @@  #define LL_LLWEBPROFILE_H  #include "llimage.h" +#include "lleventcoro.h" +#include "llcoros.h" +#include "httpheaders.h" +#include "bufferarray.h"  namespace LLWebProfileResponders  { @@ -54,11 +58,11 @@ public:  	static void setImageUploadResultCallback(status_callback_t cb) { mStatusCallback = cb; }  private: -	friend class LLWebProfileResponders::ConfigResponder; -	friend class LLWebProfileResponders::PostImageResponder; -	friend class LLWebProfileResponders::PostImageRedirectResponder; +    static LLCore::HttpHeaders::ptr_t buildDefaultHeaders(); + +    static void uploadImageCoro(LLPointer<LLImageFormatted> image, std::string caption, bool add_location); +    static LLCore::BufferArray::ptr_t buildPostData(const LLSD &data, LLPointer<LLImageFormatted> &image, const std::string &boundary); -	static void post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url);  	static void reportImageUploadStatus(bool ok);  	static std::string getAuthCookie(); diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 3bedfbe502..ff15afa598 100755 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -32,6 +32,7 @@  #include "llviewerregion.h"  #include "llenvmanager.h"  #include "llnotificationsutil.h" +#include "llcorehttputil.h"  /****   * LLEnvironmentRequest @@ -81,55 +82,62 @@ bool LLEnvironmentRequest::doRequest()  		return false;  	} -	LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; -	LLHTTPClient::get(url, new LLEnvironmentRequestResponder()); -	return true; -} - -/**** - * LLEnvironmentRequestResponder - ****/ -int LLEnvironmentRequestResponder::sCount = 0; // init to 0 +    std::string coroname = +        LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro", +        boost::bind(&LLEnvironmentRequest::environmentRequestCoro, url)); -LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() -{ -	mID = ++sCount; +    LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; +    return true;  } -/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess() -{ -	const LLSD& unvalidated_content = getContent(); -	LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; -	if (mID != sCount) -	{ -		LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL; -		return; -	} - -	LLUUID regionId; -	if( gAgent.getRegion() ) -	{ -		regionId = gAgent.getRegion()->getRegionID(); -	} -	 -	if (unvalidated_content[0]["regionID"].asUUID() != regionId ) -	{ -		LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting " -			<< regionId << " but got " << unvalidated_content[0]["regionID"].asUUID() -			<< ") - ignoring..." << LL_ENDL; -		return; -	} +S32 LLEnvironmentRequest::sLastRequest = 0; -	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content); -} -/*virtual*/ -void LLEnvironmentRequestResponder::httpFailure() +//static  +void LLEnvironmentRequest::environmentRequestCoro(std::string url)  { -	LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " -			<< dumpResponse() << LL_ENDL; -	LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    S32 requestId = ++LLEnvironmentRequest::sLastRequest; +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t  +            httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    if (requestId != LLEnvironmentRequest::sLastRequest) +    { +        LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL; +        return; +    } + +    LLSD httpResults = result["http_result"]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +    if (!status) +    { +        LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " << LL_ENDL; +        LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); +        return; +    } +    result = result["content"]; +    LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; + +    LLUUID regionId; +    if (gAgent.getRegion()) +    { +        regionId = gAgent.getRegion()->getRegionID(); +    } + +    if (result[0]["regionID"].asUUID() != regionId) +    { +        LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting " +            << regionId << " but got " << result[0]["regionID"].asUUID() +            << ") - ignoring..." << LL_ENDL; +        return; +    } + +    LLEnvManagerNew::getInstance()->onRegionSettingsResponse(result);  } +  /****   * LLEnvironmentApply   ****/ @@ -161,53 +169,86 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content)  		return false;  	} -	LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL; -	LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL; -	LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder()); +    LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL; +    LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL; + +    std::string coroname = +        LLCoros::instance().launch("LLEnvironmentApply::environmentApplyCoro", +        boost::bind(&LLEnvironmentApply::environmentApplyCoro, url, content));  	return true;  } -/**** - * LLEnvironmentApplyResponder - ****/ -/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap() || !content.has("regionID")) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) -	{ -		LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " -			<< gAgent.getRegion()->getRegionID() << ", reply is from " << content["regionID"].asUUID() -			<< "); ignoring..." << LL_ENDL; -		return; -	} -	else if (content["success"].asBoolean()) -	{ -		LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << content["regionID"].asUUID() << LL_ENDL; -		LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true); -	} -	else -	{ -		LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  " << dumpResponse() << LL_ENDL; -		LLSD args(LLSD::emptyMap()); -		args["FAIL_REASON"] = content["fail_reason"].asString(); -		LLNotificationsUtil::add("WLRegionApplyFail", args); -		LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); -	} -} -/*virtual*/ -void LLEnvironmentApplyResponder::httpFailure() +void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content)  { -	LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " -		<< dumpResponse() << LL_ENDL; - -	LLSD args(LLSD::emptyMap()); -	std::stringstream msg; -	msg << getReason() << " (Code " << getStatus() << ")"; -	args["FAIL_REASON"] = msg.str(); -	LLNotificationsUtil::add("WLRegionApplyFail", args); +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentApply", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, content); + +    LLSD notify; // for error reporting.  If there is something to report to user this will be defined. +    /* +     * Expecting reply from sim in form of: +     * { +     *   regionID : uuid, +     *   messageID: uuid, +     *   success : true +     * } +     * or +     * { +     *   regionID : uuid, +     *   success : false, +     *   fail_reason : string +     * } +     */ + +    do // while false.   +    {  // Breaks from loop in the case of an error. + +        LLSD httpResults = result["http_result"]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +        if (!status) +        { +            LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " << LL_ENDL; + +            std::stringstream msg; +            msg << status.toString() << " (Code " << status.toTerseString() << ")"; +            notify = LLSD::emptyMap(); +            notify["FAIL_REASON"] = msg.str(); +            break; +        } + +        if (!result.has("regionID")) +        { +            notify = LLSD::emptyMap(); +            notify["FAIL_REASON"] = "Missing regionID, malformed response"; +            break; +        }  +        else if (result["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) +        { +            // note that there is no report to the user in this failure case. +            LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " +                << gAgent.getRegion()->getRegionID() << ", reply is from " << result["regionID"].asUUID() +                << "); ignoring..." << LL_ENDL; +            break; +        } +        else if (!result["success"].asBoolean()) +        { +            LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings!  " << LL_ENDL; +            notify = LLSD::emptyMap(); +            notify["FAIL_REASON"] = result["fail_reason"].asString(); +            break; +        } + +        LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << result["regionID"].asUUID() << LL_ENDL; +        LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true); + +    } while (false); + +    if (!notify.isUndefined()) +    { +        LLNotificationsUtil::add("WLRegionApplyFail", notify); +        LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); +    }  } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 089c799da7..eb2bbf9553 100755 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -28,7 +28,7 @@  #define LL_LLWLHANDLERS_H  #include "llviewerprecompiledheaders.h" -#include "llhttpclient.h" +#include "llcoros.h"  class LLEnvironmentRequest  { @@ -40,21 +40,10 @@ public:  private:  	static void onRegionCapsReceived(const LLUUID& region_id);  	static bool doRequest(); -}; - -class LLEnvironmentRequestResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(LLEnvironmentRequestResponder); -private: -	/* virtual */ void httpSuccess(); -	/* virtual */ void httpFailure(); -private: -	friend class LLEnvironmentRequest; +    static void environmentRequestCoro(std::string url); -	LLEnvironmentRequestResponder(); -	static int sCount; -	int mID; +    static S32 sLastRequest;  };  class LLEnvironmentApply @@ -67,35 +56,8 @@ public:  private:  	static clock_t sLastUpdate;  	static clock_t UPDATE_WAIT_SECONDS; -}; -class LLEnvironmentApplyResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(LLEnvironmentApplyResponder); -private: -	/* -	 * Expecting reply from sim in form of: -	 * { -	 *   regionID : uuid, -	 *   messageID: uuid, -	 *   success : true -	 * } -	 * or -	 * { -	 *   regionID : uuid, -	 *   success : false, -	 *   fail_reason : string -	 * } -	 */ -	/* virtual */ void httpSuccess(); - -	// non-2xx errors only -	/* virtual */ void httpFailure(); - -private: -	friend class LLEnvironmentApply; -	 -	LLEnvironmentApplyResponder() {} +    static void environmentApplyCoro(std::string url, LLSD content);  };  #endif // LL_LLWLHANDLERS_H diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index c12c2cc24c..066970614a 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -35,6 +35,11 @@  #include "llxmlrpclistener.h"  #include "llcurl.h" +#include "httpcommon.h" +#include "httprequest.h" +#include "httpoptions.h" +#include "httpheaders.h" +#include "bufferarray.h"  #include "llviewercontrol.h"  // Have to include these last to avoid queue redefinition! @@ -43,6 +48,13 @@  #include "llappviewer.h"  #include "lltrans.h" +#include "boost/move/unique_ptr.hpp" + +namespace boost +{ +	using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace. +} +  // Static instance of LLXMLRPCListener declared here so that every time we  // bring in this code, we instantiate a listener. If we put the static  // instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would @@ -155,55 +167,158 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const  } +class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler +{ +public:  +	Handler(LLCore::HttpRequest::ptr_t &request, LLXMLRPCTransaction::Impl *impl); +	virtual ~Handler(); + +	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +	typedef boost::unique_ptr<LLXMLRPCTransaction::Handler> ptr_t; + +private: + +	LLXMLRPCTransaction::Impl *mImpl; +	LLCore::HttpRequest::ptr_t mRequest; +}; +  class LLXMLRPCTransaction::Impl  {  public:  	typedef LLXMLRPCTransaction::EStatus	EStatus; -	LLCurlEasyRequest* mCurlRequest; +	LLCore::HttpRequest::ptr_t	mHttpRequest; + + +	EStatus				mStatus; +	CURLcode			mCurlCode; +	std::string			mStatusMessage; +	std::string			mStatusURI; +	LLCore::HttpResponse::TransferStats::ptr_t	mTransferStats; +	Handler::ptr_t		mHandler; +	LLCore::HttpHandle	mPostH; -	EStatus		mStatus; -	CURLcode	mCurlCode; -	std::string	mStatusMessage; -	std::string	mStatusURI; -	LLCurl::TransferInfo mTransferInfo; -	  	std::string			mURI; -	char*				mRequestText; -	int					mRequestTextSize; -	 +  	std::string			mProxyAddress;  	std::string			mResponseText;  	XMLRPC_REQUEST		mResponse;  	std::string         mCertStore;  	LLPointer<LLCertificate> mErrorCert; -	 +  	Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);  	Impl(const std::string& uri, -		 const std::string& method, LLXMLRPCValue params, bool useGzip); +		const std::string& method, LLXMLRPCValue params, bool useGzip);  	~Impl(); -	 +  	bool process(); -	 -	void setStatus(EStatus code, -				   const std::string& message = "", const std::string& uri = ""); -	void setCurlStatus(CURLcode); + +	void setStatus(EStatus code, const std::string& message = "", const std::string& uri = ""); +	void setHttpStatus(const LLCore::HttpStatus &status);  private:  	void init(XMLRPC_REQUEST request, bool useGzip); -	static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param); -	static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param); -	static size_t curlDownloadCallback( -		char* data, size_t size, size_t nmemb, void* user_data);  }; +LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,  +		LLXMLRPCTransaction::Impl *impl) : +	mImpl(impl), +	mRequest(request) +{ +} + +LLXMLRPCTransaction::Handler::~Handler() +{ +} + +void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,  +	LLCore::HttpResponse * response) +{ +	LLCore::HttpStatus status = response->getStatus(); + +	if (!status) +	{ +		if ((status.toULong() != CURLE_SSL_PEER_CERTIFICATE) && +			(status.toULong() != CURLE_SSL_CACERT)) +		{ +			// if we have a curl error that's not already been handled +			// (a non cert error), then generate the error message as +			// appropriate +			mImpl->setHttpStatus(status); +			LLCertificate *errordata = static_cast<LLCertificate *>(status.getErrorData()); + +			if (errordata) +			{ +				mImpl->mErrorCert = LLPointer<LLCertificate>(errordata); +				status.setErrorData(NULL); +				errordata->unref(); +			} + +			LL_WARNS() << "LLXMLRPCTransaction error " +				<< status.toHex() << ": " << status.toString() << LL_ENDL; +			LL_WARNS() << "LLXMLRPCTransaction request URI: " +				<< mImpl->mURI << LL_ENDL; +		} + +		return; +	} + +	mImpl->setStatus(LLXMLRPCTransaction::StatusComplete); +	mImpl->mTransferStats = response->getTransferStats(); + +	// the contents of a buffer array are potentially noncontiguous, so we +	// will need to copy them into an contiguous block of memory for XMLRPC. +	LLCore::BufferArray *body = response->getBody(); +	char * bodydata = new char[body->size()]; + +	body->read(0, bodydata, body->size()); + +	mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, body->size(), 0); + +	delete[] bodydata; + +	bool		hasError = false; +	bool		hasFault = false; +	int			faultCode = 0; +	std::string	faultString; + +	LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse)); +	if (error.isValid()) +	{ +		hasError = true; +		faultCode = error["faultCode"].asInt(); +		faultString = error["faultString"].asString(); +	} +	else if (XMLRPC_ResponseIsFault(mImpl->mResponse)) +	{ +		hasFault = true; +		faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse); +		faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse); +	} + +	if (hasError || hasFault) +	{ +		mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError); + +		LL_WARNS() << "LLXMLRPCTransaction XMLRPC " +			<< (hasError ? "error " : "fault ") +			<< faultCode << ": " +			<< faultString << LL_ENDL; +		LL_WARNS() << "LLXMLRPCTransaction request URI: " +			<< mImpl->mURI << LL_ENDL; +	} + +} + +//========================================================================= +  LLXMLRPCTransaction::Impl::Impl(const std::string& uri,  		XMLRPC_REQUEST request, bool useGzip) -	: mCurlRequest(0), +	: mHttpRequest(),  	  mStatus(LLXMLRPCTransaction::StatusNotStarted),  	  mURI(uri), -	  mRequestText(0),   	  mResponse(0)  {  	init(request, useGzip); @@ -212,10 +327,9 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,  LLXMLRPCTransaction::Impl::Impl(const std::string& uri,  		const std::string& method, LLXMLRPCValue params, bool useGzip) -	: mCurlRequest(0), +	: mHttpRequest(),  	  mStatus(LLXMLRPCTransaction::StatusNotStarted),  	  mURI(uri), -	  mRequestText(0),   	  mResponse(0)  {  	XMLRPC_REQUEST request = XMLRPC_RequestNew(); @@ -231,127 +345,53 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,      XMLRPC_RequestFree(request, 1);  } -// _sslCertVerifyCallback -// callback called when a cert verification is requested. -// calls SECAPI to validate the context -int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) +void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)  { -	LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param; -	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore); -	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); -	LLSD validation_params = LLSD::emptyMap(); -	LLURI uri(transaction->mURI); -	validation_params[CERT_HOSTNAME] = uri.hostName(); -	try -	{ -		// don't validate hostname.  Let libcurl do it instead.  That way, it'll handle redirects -		store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); -	} -	catch (LLCertValidationTrustException& cert_exception) -	{ -		// this exception is is handled differently than the general cert -		// exceptions, as we allow the user to actually add the certificate -		// for trust. -		// therefore we pass back a different error code -		// NOTE: We're currently 'wired' to pass around CURL error codes.  This is -		// somewhat clumsy, as we may run into errors that do not map directly to curl -		// error codes.  Should be refactored with login refactoring, perhaps. -		transaction->mCurlCode = CURLE_SSL_CACERT; -		// set the status directly.  set curl status generates error messages and we want -		// to use the fixed ones from the exceptions -		transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string()); -		// We should probably have a more generic way of passing information -		// back to the error handlers. -		transaction->mErrorCert = cert_exception.getCert(); -		return 0;		 -	} -	catch (LLCertException& cert_exception) -	{ -		transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE; -		// set the status directly.  set curl status generates error messages and we want -		// to use the fixed ones from the exceptions -		transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string()); -		transaction->mErrorCert = cert_exception.getCert(); -		return 0; -	} -	catch (...) -	{ -		// any other odd error, we just handle as a connect error. -		transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR; -		transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR); -		return 0; -	} -	return 1; -} +	LLCore::HttpOptions::ptr_t httpOpts; +	LLCore::HttpHeaders::ptr_t httpHeaders; -// _sslCtxFunction -// Callback function called when an SSL Context is created via CURL -// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion -// based on SECAPI - -CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param) -{ -	SSL_CTX * ctx = (SSL_CTX *) sslctx; -	// disable any default verification for server certs -	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); -	// set the verification callback. -	SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param); -	// the calls are void -	return CURLE_OK; -	 -} -void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) -{ -	if (!mCurlRequest) +	if (!mHttpRequest)  	{ -		mCurlRequest = new LLCurlEasyRequest(); +		mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);  	} -	if(!mCurlRequest->isValid()) -	{ -		LL_WARNS() << "mCurlRequest is invalid." << LL_ENDL ; -		delete mCurlRequest ; -		mCurlRequest = NULL ; -		return ; -	} +	// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer +	httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());  -	mErrorCert = NULL; +	httpOpts->setTimeout(40L); -//	mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging -	mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); -	mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); -	BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); +	bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");  	mCertStore = gSavedSettings.getString("CertStore"); -	mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); -	mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); -	// Be a little impatient about establishing connections. -	mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); -	mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this); -	/* Setting the DNS cache timeout to -1 disables it completely. -	   This might help with bug #503 */ -	mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); +	httpOpts->setSSLVerifyPeer( vefifySSLCert ); +	httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0); -    mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); +	// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer +	httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); -	if (useGzip) -	{ -		mCurlRequest->setoptString(CURLOPT_ENCODING, ""); -	} +	httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); + +	///* Setting the DNS cache timeout to -1 disables it completely. +	//This might help with bug #503 */ +	//httpOpts->setDNSCacheTimeout(-1); + +	LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); + +	// TODO: See if there is a way to serialize to a preallocated buffer I'm  +	// not fond of the copy here. +	int	requestSize(0); +	char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize); + +	body->append(requestText, requestSize); -	mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); -	if (mRequestText) -	{ -		mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText); -		mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize); -	} -	else -	{ -		setStatus(StatusOtherError); -	} +	XMLRPC_Free(requestText); + +	mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this )); + +	mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, 0,  +		mURI, body.get(), httpOpts.get(), httpHeaders.get(), mHandler.get()); -	mCurlRequest->sendRequest(mURI);  } @@ -361,28 +401,17 @@ LLXMLRPCTransaction::Impl::~Impl()  	{  		XMLRPC_RequestFree(mResponse, 1);  	} -	 -	if (mRequestText) -	{ -		XMLRPC_Free(mRequestText); -	} -	 -	delete mCurlRequest; -	mCurlRequest = NULL ;  }  bool LLXMLRPCTransaction::Impl::process()  { -	if(!mCurlRequest || !mCurlRequest->isValid()) +	if (!mPostH || !mHttpRequest)  	{ -		LL_WARNS() << "transaction failed." << LL_ENDL ; - -		delete mCurlRequest ; -		mCurlRequest = NULL ; -		return true ; //failed, quit. +		LL_WARNS() << "transaction failed." << LL_ENDL; +		return true; //failed, quit.  	} -	switch(mStatus) +	switch (mStatus)  	{  		case LLXMLRPCTransaction::StatusComplete:  		case LLXMLRPCTransaction::StatusCURLError: @@ -391,93 +420,25 @@ bool LLXMLRPCTransaction::Impl::process()  		{  			return true;  		} -		 +  		case LLXMLRPCTransaction::StatusNotStarted:  		{  			setStatus(LLXMLRPCTransaction::StatusStarted);  			break;  		} -		 +  		default: -		{ -			// continue onward -		} -	} -		 -	if(!mCurlRequest->wait()) -	{ -		return false ; +			break;  	} -	while(1) -	{ -		CURLcode result; -		bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo); -		if (newmsg) -		{ -			if (result != CURLE_OK) -			{ -				if ((result != CURLE_SSL_PEER_CERTIFICATE) && -					(result != CURLE_SSL_CACERT)) -				{ -					// if we have a curl error that's not already been handled -					// (a non cert error), then generate the error message as -					// appropriate -					setCurlStatus(result); -				 -					LL_WARNS() << "LLXMLRPCTransaction CURL error " -					<< mCurlCode << ": " << mCurlRequest->getErrorString() << LL_ENDL; -					LL_WARNS() << "LLXMLRPCTransaction request URI: " -					<< mURI << LL_ENDL; -				} -					 -				return true; -			} -			 -			setStatus(LLXMLRPCTransaction::StatusComplete); +	LLCore::HttpStatus status = mHttpRequest->update(0); -			mResponse = XMLRPC_REQUEST_FromXML( -					mResponseText.data(), mResponseText.size(), NULL); - -			bool		hasError = false; -			bool		hasFault = false; -			int			faultCode = 0; -			std::string	faultString; - -			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse)); -			if (error.isValid()) -			{ -				hasError = true; -				faultCode = error["faultCode"].asInt(); -				faultString = error["faultString"].asString(); -			} -			else if (XMLRPC_ResponseIsFault(mResponse)) -			{ -				hasFault = true; -				faultCode = XMLRPC_GetResponseFaultCode(mResponse); -				faultString = XMLRPC_GetResponseFaultString(mResponse); -			} - -			if (hasError || hasFault) -			{ -				setStatus(LLXMLRPCTransaction::StatusXMLRPCError); -				 -				LL_WARNS() << "LLXMLRPCTransaction XMLRPC " -						<< (hasError ? "error " : "fault ") -						<< faultCode << ": " -						<< faultString << LL_ENDL; -				LL_WARNS() << "LLXMLRPCTransaction request URI: " -						<< mURI << LL_ENDL; -			} -			 -			return true; -		} -		else -		{ -			break; // done -		} +	status = mHttpRequest->getStatus(); +	if (!status)  +	{ +		return false;  	} -	 +  	return false;  } @@ -516,64 +477,51 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status,  	}  } -void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) +void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)  { +	CURLcode code = static_cast<CURLcode>(status.toULong());  	std::string message;  	std::string uri = "http://secondlife.com/community/support.php"; -	 +	LLURI failuri(mURI); + +  	switch (code)  	{ -		case CURLE_COULDNT_RESOLVE_HOST: -			message = -				"DNS could not resolve the host name.\n" -				"Please verify that you can connect to the www.secondlife.com\n" -				"web site.  If you can, but continue to receive this error,\n" -				"please go to the support section and report this problem."; -			break; -			 -		case CURLE_SSL_PEER_CERTIFICATE: -			message = -				"The login server couldn't verify itself via SSL.\n" -				"If you continue to receive this error, please go\n" -				"to the Support section of the SecondLife.com web site\n" -				"and report the problem."; -			break; -			 -		case CURLE_SSL_CACERT: -		case CURLE_SSL_CONNECT_ERROR: -			message = -				"Often this means that your computer\'s clock is set incorrectly.\n" -				"Please go to Control Panels and make sure the time and date\n" -				"are set correctly.\n" -				"Also check that your network and firewall are set up correctly.\n" -				"If you continue to receive this error, please go\n" -				"to the Support section of the SecondLife.com web site\n" -				"and report the problem."; -			break; -			 -		default: -				break; +	case CURLE_COULDNT_RESOLVE_HOST: +		message = +			std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\n" +			"Please verify that you can connect to the www.secondlife.com\n" +			"web site.  If you can, but continue to receive this error,\n" +			"please go to the support section and report this problem."; +		break; + +	case CURLE_SSL_PEER_CERTIFICATE: +		message = +			"The login server couldn't verify itself via SSL.\n" +			"If you continue to receive this error, please go\n" +			"to the Support section of the SecondLife.com web site\n" +			"and report the problem."; +		break; + +	case CURLE_SSL_CACERT: +	case CURLE_SSL_CONNECT_ERROR: +		message = +			"Often this means that your computer\'s clock is set incorrectly.\n" +			"Please go to Control Panels and make sure the time and date\n" +			"are set correctly.\n" +			"Also check that your network and firewall are set up correctly.\n" +			"If you continue to receive this error, please go\n" +			"to the Support section of the SecondLife.com web site\n" +			"and report the problem."; +		break; + +	default: +		break;  	} -	 +  	mCurlCode = code;  	setStatus(StatusCURLError, message, uri); -} - -size_t LLXMLRPCTransaction::Impl::curlDownloadCallback( -		char* data, size_t size, size_t nmemb, void* user_data) -{ -	Impl& impl(*(Impl*)user_data); -	 -	size_t n = size * nmemb; -	impl.mResponseText.append(data, n); -	 -	if (impl.mStatus == LLXMLRPCTransaction::StatusStarted) -	{ -		impl.setStatus(LLXMLRPCTransaction::StatusDownloading); -	} -	 -	return n;  } @@ -645,11 +593,11 @@ F64 LLXMLRPCTransaction::transferRate()  		return 0.0L;  	} -	double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0; +	double rate_bits_per_sec = impl.mTransferStats->mSpeedDownload * 8.0;  	LL_INFOS("AppInit") << "Buffer size:   " << impl.mResponseText.size() << " B" << LL_ENDL; -	LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL; -	LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL; +	LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferStats->mSizeDownload << " B" << LL_ENDL; +	LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferStats->mTotalTime << " s" << LL_ENDL;  	LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL;  	return rate_bits_per_sec; diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h index f2589c7f41..3a1c9c82b7 100755 --- a/indra/newview/llxmlrpctransaction.h +++ b/indra/newview/llxmlrpctransaction.h @@ -81,7 +81,7 @@ private:  class LLXMLRPCTransaction -	// an asynchronous request and respones via XML-RPC +	// an asynchronous request and responses via XML-RPC  {  public:  	LLXMLRPCTransaction(const std::string& uri, @@ -127,7 +127,9 @@ public:  		// only valid if StsatusComplete, otherwise 0.0  private: +	class Handler;  	class Impl; +  	Impl& impl;  }; diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp deleted file mode 100755 index bde991a01e..0000000000 --- a/indra/newview/tests/llcapabilitylistener_test.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/** - * @file   llcapabilitylistener_test.cpp - * @author Nat Goodspeed - * @date   2008-12-31 - * @brief  Test for llcapabilitylistener.cpp. - *  - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -// Precompiled header -#include "../llviewerprecompiledheaders.h" -// Own header -#include "../llcapabilitylistener.h" -// STL headers -#include <stdexcept> -#include <map> -#include <vector> -// std headers -// external library headers -#include "boost/bind.hpp" -// other Linden headers -#include "../test/lltut.h" -#include "../llcapabilityprovider.h" -#include "lluuid.h" -#include "tests/networkio.h" -#include "tests/commtest.h" -#include "tests/wrapllerrs.h" -#include "message.h" -#include "stringize.h" - -#if defined(LL_WINDOWS) -#pragma warning(disable: 4355)      // using 'this' in base-class ctor initializer expr -#endif - -/***************************************************************************** -*   TestCapabilityProvider -*****************************************************************************/ -struct TestCapabilityProvider: public LLCapabilityProvider -{ -    TestCapabilityProvider(const LLHost& host): -        mHost(host) -    {} - -    std::string getCapability(const std::string& cap) const -    { -        CapMap::const_iterator found = mCaps.find(cap); -        if (found != mCaps.end()) -            return found->second; -        // normal LLViewerRegion lookup failure mode -        return ""; -    } -    void setCapability(const std::string& cap, const std::string& url) -    { -        mCaps[cap] = url; -    } -    const LLHost& getHost() const { return mHost; } -    std::string getDescription() const { return "TestCapabilityProvider"; } - -    LLHost mHost; -    typedef std::map<std::string, std::string> CapMap; -    CapMap mCaps; -}; - -/***************************************************************************** -*   Dummy LLMessageSystem methods -*****************************************************************************/ -/*==========================================================================*| -// This doesn't work because we're already linking in llmessage.a, and we get -// duplicate-symbol errors from the linker. Perhaps if I wanted to go through -// the exercise of providing dummy versions of every single symbol defined in -// message.o -- maybe some day. -typedef std::vector< std::pair<std::string, std::string> > StringPairVector; -StringPairVector call_history; - -S32 LLMessageSystem::sendReliable(const LLHost& host) -{ -    call_history.push_back(StringPairVector::value_type("sendReliable", stringize(host))); -    return 0; -} -|*==========================================================================*/ - -/***************************************************************************** -*   TUT -*****************************************************************************/ -namespace tut -{ -    struct llcapears_data: public commtest_data -    { -        TestCapabilityProvider provider; -        LLCapabilityListener regionListener; -        LLEventPump& regionPump; - -        llcapears_data(): -            provider(host), -            regionListener("testCapabilityListener", NULL, provider, LLUUID(), LLUUID()), -            regionPump(regionListener.getCapAPI()) -        { -            LLCurl::initClass(); -            provider.setCapability("good", server + "capability-test"); -            provider.setCapability("fail", server + "fail"); -        } -    }; -    typedef test_group<llcapears_data> llcapears_group; -    typedef llcapears_group::object llcapears_object; -    llcapears_group llsdmgr("llcapabilitylistener"); - -    template<> template<> -    void llcapears_object::test<1>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        std::string threw; -        try -        { -            WrapLLErrs capture; -            regionPump.post(request); -        } -        catch (const WrapLLErrs::FatalException& e) -        { -            threw = e.what(); -        } -        ensure_contains("missing capability name", threw, "without 'message' key"); -    } - -    template<> template<> -    void llcapears_object::test<2>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["message"] = "good"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        regionPump.post(request); -        ensure("got response", netio.pump()); -        ensure("success response", success); -        ensure_equals(result["reply"].asString(), "success"); - -        body["status"] = 499; -        body["reason"] = "custom error message"; -        request["message"] = "fail"; -        request["payload"] = body; -        regionPump.post(request); -        ensure("got response", netio.pump()); -        ensure("failure response", ! success); -        ensure_equals(result["status"].asInteger(), body["status"].asInteger()); -        ensure_equals(result["reason"].asString(),  body["reason"].asString()); -    } - -    template<> template<> -    void llcapears_object::test<3>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["message"] = "unknown"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        std::string threw; -        try -        { -            WrapLLErrs capture; -            regionPump.post(request); -        } -        catch (const WrapLLErrs::FatalException& e) -        { -            threw = e.what(); -        } -        ensure_contains("bad capability name", threw, "unsupported capability"); -    } - -    struct TestMapper: public LLCapabilityListener::CapabilityMapper -    { -        // Instantiator gets to specify whether mapper expects a reply. -        // I'd really like to be able to test CapabilityMapper::buildMessage() -        // functionality, too, but -- even though LLCapabilityListener accepts -        // the LLMessageSystem* that it passes to CapabilityMapper -- -        // LLMessageSystem::sendReliable(const LLHost&) isn't virtual, so it's -        // not helpful to pass a subclass instance. I suspect that making any -        // LLMessageSystem methods virtual would provoke howls of outrage, -        // given how heavily it's used. Nor can I just provide a local -        // definition of LLMessageSystem::sendReliable(const LLHost&) because -        // we're already linking in the rest of message.o via llmessage.a, and -        // that produces duplicate-symbol link errors. -        TestMapper(const std::string& replyMessage = std::string()): -            LLCapabilityListener::CapabilityMapper("test", replyMessage) -        {} -        virtual void buildMessage(LLMessageSystem* msg, -                                  const LLUUID& agentID, -                                  const LLUUID& sessionID, -                                  const std::string& capabilityName, -                                  const LLSD& payload) const -        { -            msg->newMessageFast(_PREHASH_SetStartLocationRequest); -            msg->nextBlockFast( _PREHASH_AgentData); -            msg->addUUIDFast(_PREHASH_AgentID, agentID); -            msg->addUUIDFast(_PREHASH_SessionID, sessionID); -            msg->nextBlockFast( _PREHASH_StartLocationData); -            // corrected by sim -            msg->addStringFast(_PREHASH_SimName, ""); -            msg->addU32Fast(_PREHASH_LocationID, payload["HomeLocation"]["LocationId"].asInteger()); -/*==========================================================================*| -            msg->addVector3Fast(_PREHASH_LocationPos, -                                ll_vector3_from_sdmap(payload["HomeLocation"]["LocationPos"])); -            msg->addVector3Fast(_PREHASH_LocationLookAt, -                                ll_vector3_from_sdmap(payload["HomeLocation"]["LocationLookAt"])); -|*==========================================================================*/ -        } -    }; - -    template<> template<> -    void llcapears_object::test<4>() -    { -        TestMapper testMapper("WantReply"); -        LLSD request, body; -        body["data"] = "yes"; -        request["message"] = "test"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        std::string threw; -        try -        { -            WrapLLErrs capture; -            regionPump.post(request); -        } -        catch (const WrapLLErrs::FatalException& e) -        { -            threw = e.what(); -        } -        ensure_contains("capability mapper wants reply", threw, "unimplemented support for reply message"); -    } - -    template<> template<> -    void llcapears_object::test<5>() -    { -        TestMapper testMapper; -        std::string threw; -        try -        { -            TestMapper testMapper2; -        } -        catch (const std::runtime_error& e) -        { -            threw = e.what(); -        } -        ensure_contains("no dup cap mapper", threw, "DupCapMapper"); -    } -} diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp index 6f57daf151..61120686e4 100755 --- a/indra/newview/tests/llmediadataclient_test.cpp +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -106,7 +106,7 @@ const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","true");  LLSD *gPostRecords = NULL;  F64   gMinimumInterestLevel = (F64)0.0; - +#if 0  // stubs:  void LLHTTPClient::post(  		const std::string& url, @@ -140,6 +140,7 @@ void LLHTTPClient::post(  	}  	responder->successResult(result);  } +#endif  const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index c49b0350e9..ea5014a59c 100755 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -27,6 +27,7 @@  #include "linden_common.h"  #include "../test/lltut.h" +#if 0  #include "../llremoteparcelrequest.h" @@ -134,3 +135,4 @@ namespace tut  		processor.processParcelInfoReply(gMessageSystem, NULL);  	}  } +#endif diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index b8408a6fb4..88415ff11a 100755 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -107,9 +107,8 @@ private:      }      // In a coroutine's top-level function args, do NOT NOT NOT accept -    // references (const or otherwise) to anything but the self argument! Pass -    // by value only! -    void login_(LLCoros::self& self, std::string uri, LLSD credentials); +    // references (const or otherwise) to anything! Pass by value only! +    void login_(std::string uri, LLSD credentials);      LLEventStream mPump;  	LLSD mAuthResponse, mValidAuthResponse; @@ -123,11 +122,11 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)      // its first wait; at that point, return here.      std::string coroname =           LLCoros::instance().launch("LLLogin::Impl::login_", -                                   boost::bind(&Impl::login_, this, _1, uri, login_params)); +                                   boost::bind(&Impl::login_, this, uri, login_params));      LL_DEBUGS("LLLogin") << " connected with  uri '" << uri << "', login_params " << login_params << LL_ENDL;	  } -void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_params) +void LLLogin::Impl::login_(std::string uri, LLSD login_params)  {  	try  	{ @@ -137,7 +136,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para  	//{  	//	printable_params["params"]["passwd"] = "*******";  	//} -	LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self) +	LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName()                          << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;  	// Arriving in SRVRequest state @@ -176,7 +175,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para  		request["op"] = "rewriteURI";  		request["uri"] = uri;  		request["reply"] = replyPump.getName(); -		rewrittenURIs = postAndWait(self, request, srv_pump_name, filter); +		rewrittenURIs = llcoro::postAndWait(request, srv_pump_name, filter);  		// EXP-772: If rewrittenURIs fail, try original URI as a fallback.  		rewrittenURIs.append(uri);      } // we no longer need the filter @@ -222,10 +221,10 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para              // returns. Subsequent responses, of course, must be awaited              // without posting again.              for (mAuthResponse = validateResponse(loginReplyPump.getName(), -                                 postAndWait(self, request, xmlrpcPump, loginReplyPump, "reply")); +                     llcoro::postAndWait(request, xmlrpcPump, loginReplyPump, "reply"));                   mAuthResponse["status"].asString() == "Downloading";                   mAuthResponse = validateResponse(loginReplyPump.getName(), -                                     waitForEventOn(self, loginReplyPump))) +                                                  llcoro::waitForEventOn(loginReplyPump)))              {                  // Still Downloading -- send progress update.                  sendProgressEvent("offline", "downloading"); diff --git a/indra/viewer_components/updater/CMakeLists.txt b/indra/viewer_components/updater/CMakeLists.txt index 61fd4220e0..53e309290f 100755 --- a/indra/viewer_components/updater/CMakeLists.txt +++ b/indra/viewer_components/updater/CMakeLists.txt @@ -9,12 +9,14 @@ endif(LL_TESTS)  include(CMakeCopyIfDifferent)  include(CURL)  include(LLCommon) +include(LLCoreHttp)  include(LLMessage)  include(LLPlugin)  include(LLVFS)  include_directories(      ${LLCOMMON_INCLUDE_DIRS} +    ${LLCOREHTTP_INCLUDE_DIRS}      ${LLMESSAGE_INCLUDE_DIRS}      ${LLPLUGIN_INCLUDE_DIRS}      ${LLVFS_INCLUDE_DIRS} @@ -59,6 +61,7 @@ add_library(llupdaterservice  target_link_libraries(llupdaterservice      ${LLCOMMON_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${LLMESSAGE_LIBRARIES}      ${LLPLUGIN_LIBRARIES}      ${LLVFS_LIBRARIES} diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp index 8da4f88905..e889f83aa9 100755 --- a/indra/viewer_components/updater/llupdatechecker.cpp +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -26,10 +26,10 @@  #include "linden_common.h"  #include <stdexcept>  #include <boost/format.hpp> -#include "llhttpclient.h"  #include "llsd.h"  #include "llupdatechecker.h"  #include "lluri.h" +#include "llcorehttputil.h"  #if LL_DARWIN  #include <CoreServices/CoreServices.h>  #endif @@ -53,15 +53,12 @@ public:  // LLUpdateChecker  //----------------------------------------------------------------------------- - -  LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client):  	mImplementation(new LLUpdateChecker::Implementation(client))  {  	; // No op.  } -  void LLUpdateChecker::checkVersion(std::string const & urlBase,   								   std::string const & channel,  								   std::string const & version, @@ -74,11 +71,8 @@ void LLUpdateChecker::checkVersion(std::string const & urlBase,  } -  // LLUpdateChecker::Implementation  //----------------------------------------------------------------------------- - -  const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.1"; @@ -121,57 +115,58 @@ void LLUpdateChecker::Implementation::checkVersion(std::string const & urlBase,  		std::string checkUrl = buildUrl(urlBase, channel, version, platform, platform_version, uniqueid, willing_to_test);  		LL_INFOS("UpdaterService") << "checking for updates at " << checkUrl << LL_ENDL; -	 -		mHttpClient.get(checkUrl, this); -	} -	else -	{ -		LL_WARNS("UpdaterService") << "attempting to restart a check when one is in progress; ignored" << LL_ENDL; -	} -} -void LLUpdateChecker::Implementation::httpCompleted() -{ -	mInProgress = false;	 +        LLCoros::instance().launch("LLUpdateChecker::Implementation::checkVersionCoro", +            boost::bind(&Implementation::checkVersionCoro, this, checkUrl)); -	S32 status = getStatus(); -	const LLSD& content = getContent(); -	const std::string& reason = getReason(); -	if(status != 200) -	{ -		std::string server_error; -		if ( content.has("error_code") ) -		{ -			server_error += content["error_code"].asString(); -		} -		if ( content.has("error_text") ) -		{ -			server_error += server_error.empty() ? "" : ": "; -			server_error += content["error_text"].asString(); -		} - -		LL_WARNS("UpdaterService") << "response error " << status -								   << " " << reason -								   << " (" << server_error << ")" -								   << LL_ENDL; -		mClient.error(reason);  	}  	else  	{ -		mClient.response(content); +		LL_WARNS("UpdaterService") << "attempting to restart a check when one is in progress; ignored" << LL_ENDL;  	}  } - -void LLUpdateChecker::Implementation::httpFailure() +void LLUpdateChecker::Implementation::checkVersionCoro(std::string url)  { -	const std::string& reason = getReason(); -	mInProgress = false; -	LL_WARNS("UpdaterService") << "update check failed; " << reason << LL_ENDL; -	mClient.error(reason); +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("checkVersionCoro", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LL_INFOS("checkVersionCoro") << "Getting update information from " << url << LL_ENDL; + +    LLSD result = httpAdapter->getAndYield(httpRequest, url); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    mInProgress = false; + +    if (status != LLCore::HttpStatus(HTTP_OK)) +    { +        std::string server_error; +        if (result.has("error_code")) +        { +            server_error += result["error_code"].asString(); +        } +        if (result.has("error_text")) +        { +            server_error += server_error.empty() ? "" : ": "; +            server_error += result["error_text"].asString(); +        } + +        LL_WARNS("UpdaterService") << "response error " << status.getStatus() +            << " " << status.toString() +            << " (" << server_error << ")" +            << LL_ENDL; +        mClient.error(status.toString()); +        return; +    } + +    result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    mClient.response(result);  } -  std::string LLUpdateChecker::Implementation::buildUrl(std::string const & urlBase,   													  std::string const & channel,  													  std::string const & version, diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h index 3163a6d53c..d10ea4cf42 100755 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -30,61 +30,27 @@  #include <boost/shared_ptr.hpp>  #include "llmd5.h" -#include "llhttpclient.h" +#include "lleventcoro.h" +#include "llcoros.h"  //  // Implements asynchronous checking for updates.  //  class LLUpdateChecker {  public: -	class Client; -	class Implementation: public LLHTTPClient::Responder -	{ -	public: -		Implementation(Client & client); -		~Implementation(); -		void checkVersion(std::string const & urlBase,  -						  std::string const & channel, -						  std::string const & version, -						  std::string const & platform, -						  std::string const & platform_version, -						  unsigned char       uniqueid[MD5HEX_STR_SIZE], -						  bool                willing_to_test -						  ); -	 -    protected: -		// Responder: -		virtual void httpCompleted(); -		virtual void httpFailure(); -	 -	private:	 -		static const char * sLegacyProtocolVersion; -		static const char * sProtocolVersion; -		const char* mProtocol; -		 -		Client & mClient; -		LLHTTPClient mHttpClient; -		bool         mInProgress; -		std::string   mVersion; -		std::string   mUrlBase; -		std::string   mChannel; -		std::string   mPlatform; -		std::string   mPlatformVersion; -		unsigned char mUniqueId[MD5HEX_STR_SIZE]; -		bool          mWillingToTest; -		 -		std::string buildUrl(std::string const & urlBase,  -							 std::string const & channel, -							 std::string const & version, -							 std::string const & platform, -							 std::string const & platform_version, -							 unsigned char       uniqueid[MD5HEX_STR_SIZE], -							 bool                willing_to_test); - -		LOG_CLASS(LLUpdateChecker::Implementation); -	}; +    // +    // The client interface implemented by a requestor checking for an update. +    // +    class Client +    { +    public: +        // An error occurred while checking for an update. +        virtual void error(std::string const & message) = 0; + +        // A successful response was received from the viewer version manager +        virtual void response(LLSD const & content) = 0; +    }; -	  	// An exception that may be raised on check errors.  	class CheckError; @@ -100,25 +66,54 @@ public:  					  bool                willing_to_test);  private: -	LLPointer<Implementation> mImplementation; -}; +    class Implementation +    { +    public: +        typedef boost::shared_ptr<Implementation> ptr_t; +        Implementation(Client & client); +        ~Implementation(); +        void checkVersion(std::string const & urlBase, +            std::string const & channel, +            std::string const & version, +            std::string const & platform, +            std::string const & platform_version, +            unsigned char       uniqueid[MD5HEX_STR_SIZE], +            bool                willing_to_test +            ); -class LLURI; // From lluri.h +    private: +        static const char * sLegacyProtocolVersion; +        static const char * sProtocolVersion; +        const char* mProtocol; -// -// The client interface implemented by a requestor checking for an update. -// -class LLUpdateChecker::Client -{ -public: -	// An error occurred while checking for an update. -	virtual void error(std::string const & message) = 0; -	 -	// A successful response was received from the viewer version manager -	virtual void response(LLSD const & content) = 0; -}; +        Client & mClient; +        bool         mInProgress; +        std::string   mVersion; +        std::string   mUrlBase; +        std::string   mChannel; +        std::string   mPlatform; +        std::string   mPlatformVersion; +        unsigned char mUniqueId[MD5HEX_STR_SIZE]; +        bool          mWillingToTest; + +        std::string buildUrl(std::string const & urlBase, +            std::string const & channel, +            std::string const & version, +            std::string const & platform, +            std::string const & platform_version, +            unsigned char       uniqueid[MD5HEX_STR_SIZE], +            bool                willing_to_test); + +        void checkVersionCoro(std::string url); +        LOG_CLASS(LLUpdateChecker::Implementation); +    }; + + +    Implementation::ptr_t       mImplementation; +	//LLPointer<Implementation> mImplementation; +};  #endif diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt index c6070020db..144d037a31 100755 --- a/indra/win_crash_logger/CMakeLists.txt +++ b/indra/win_crash_logger/CMakeLists.txt @@ -4,6 +4,7 @@ project(win_crash_logger)  include(00-Common)  include(LLCommon) +include(LLCoreHttp)  include(LLCrashLogger)  include(LLMath)  include(LLMessage) @@ -13,8 +14,10 @@ include(LLXML)  include(Linking)  include(LLSharedLibs)  include(GoogleBreakpad) +include(Boost)  include_directories( +    ${LLCOREHTTP_INCLUDE_DIRS}      ${LLCOMMON_INCLUDE_DIRS}      ${LLCRASHLOGGER_INCLUDE_DIRS}      ${LLMATH_INCLUDE_DIRS} @@ -77,7 +80,10 @@ target_link_libraries(windows-crash-logger      ${LLXML_LIBRARIES}      ${LLMESSAGE_LIBRARIES}      ${LLMATH_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${LLCOMMON_LIBRARIES} +    ${BOOST_CONTEXT_LIBRARY} +    ${BOOST_COROUTINE_LIBRARY}      ${WINDOWS_LIBRARIES}      ${DXGUID_LIBRARY}      ${GOOGLE_PERFTOOLS_LIBRARIES}  | 
