diff options
Diffstat (limited to 'indra/llmessage')
28 files changed, 2481 insertions, 1897 deletions
| diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 0a308fbf10..9739f7c607 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,10 +49,9 @@ set(llmessage_SOURCE_FILES      llhost.cpp      llhttpassetstorage.cpp      llhttpclient.cpp -    llhttpclientadapter.cpp      llhttpconstants.cpp      llhttpnode.cpp -    llhttpsender.cpp +    llhttpsdhandler.cpp      llinstantmessage.cpp      lliobuffer.cpp      lliohttpserver.cpp @@ -74,7 +75,6 @@ set(llmessage_SOURCE_FILES      llpumpio.cpp      llsdappservices.cpp      llsdhttpserver.cpp -    llsdmessage.cpp      llsdmessagebuilder.cpp      llsdmessagereader.cpp      llsdrpcclient.cpp @@ -142,11 +142,10 @@ set(llmessage_HEADER_FILES      llhttpassetstorage.h      llhttpclient.h      llhttpclientinterface.h -    llhttpclientadapter.h      llhttpconstants.h      llhttpnode.h      llhttpnodeadapter.h -    llhttpsender.h +    llhttpsdhandler.h      llinstantmessage.h      llinvite.h      lliobuffer.h @@ -176,7 +175,6 @@ set(llmessage_HEADER_FILES      llregionhandle.h      llsdappservices.h      llsdhttpserver.h -    llsdmessage.h      llsdmessagebuilder.h      llsdmessagereader.h      llsdrpcclient.h @@ -226,12 +224,17 @@ target_link_libraries(    llmessage    ${CURL_LIBRARIES}    ${LLCOMMON_LIBRARIES} -  ${LLVFS_LIBRARES} +  ${LLVFS_LIBRARIES}    ${LLMATH_LIBRARIES}    ${CARES_LIBRARIES} +  ${JSONCPP_LIBRARIES}    ${OPENSSL_LIBRARIES}    ${CRYPTO_LIBRARIES}    ${XMLRPCEPI_LIBRARIES} +  ${LLCOREHTTP_LIBRARIES} +  ${BOOST_COROUTINE_LIBRARY} +  ${BOOST_CONTEXT_LIBRARY} +  ${BOOST_SYSTEM_LIBRARY}    )  # tests @@ -243,36 +246,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/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 61663e1982..5740b8f7da 100755 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -290,7 +290,7 @@ LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS  LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,  							   LLVFS *vfs, LLVFS *static_vfs)  { -	_init(msg, xfer, vfs, static_vfs, LLHost::invalid); +	_init(msg, xfer, vfs, static_vfs, LLHost());  } 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/llcachename.cpp b/indra/llmessage/llcachename.cpp index daf3e0b4de..66bd85f4e6 100755 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -259,7 +259,7 @@ LLCacheName::~LLCacheName()  }  LLCacheName::Impl::Impl(LLMessageSystem* msg) -	: mMsg(msg), mUpstreamHost(LLHost::invalid) +	: mMsg(msg), mUpstreamHost(LLHost())  {  	mMsg->setHandlerFuncFast(  		_PREHASH_UUIDNameRequest, handleUUIDNameRequest, (void**)this); diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index ee80b0fd94..d342888255 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -28,112 +28,1111 @@  #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, +    const HttpOptions::ptr_t &options, +    const HttpHeaders::ptr_t &headers, +    HttpHandler * handler) +{ +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    BufferArray * ba = new BufferArray(); +    BufferArrayStream bas(ba); +    LLSDSerialize::toXML(body, bas); + +    handle = request->requestPost(policy_id, +        priority, +        url, +        ba, +        options, +        headers, +        handler); +    ba->release(); +    return handle; +} + + +HttpHandle requestPutWithLLSD(HttpRequest * request, +    HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    const HttpOptions::ptr_t &options, +    const HttpHeaders::ptr_t &headers, +    HttpHandler * handler) +{ +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +    BufferArray * ba = new BufferArray(); +    BufferArrayStream bas(ba); +    LLSDSerialize::toXML(body, bas); + +    handle = request->requestPut(policy_id, +        priority, +        url, +        ba, +        options, +        headers, +        handler); +    ba->release(); +    return handle; +} + +HttpHandle requestPatchWithLLSD(HttpRequest * request, +    HttpRequest::policy_t policy_id, +    HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    const HttpOptions::ptr_t &options, +    const HttpHeaders::ptr_t &headers, +    HttpHandler * handler)  { -	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); +    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); -	BufferArray * ba = new BufferArray(); -	BufferArrayStream bas(ba); -	LLSDSerialize::toXML(body, bas); +    BufferArray * ba = new BufferArray(); +    BufferArrayStream bas(ba); +    LLSDSerialize::toXML(body, bas); -	handle = request->requestPost(policy_id, -								  priority, -								  url, -								  ba, -								  options, -								  headers, -								  handler); -	ba->release(); -	return handle; +    handle = request->requestPatch(policy_id, +        priority, +        url, +        ba, +        options, +        headers, +        handler); +    ba->release(); +    return handle;  }  std::string responseToString(LLCore::HttpResponse * response)  { -	static const std::string empty("[Empty]"); - -	if (! response) -	{ -		return empty; -	} - -	BufferArray * body(response->getBody()); -	if (! body || ! body->size()) -	{ -		return empty; -	} - -	// Attempt to parse as LLSD regardless of content-type -	LLSD body_llsd; -	if (responseToLLSD(response, false, body_llsd)) -	{ -		std::ostringstream tmp; - -		LLSDSerialize::toPrettyNotation(body_llsd, tmp); -		std::size_t temp_len(tmp.tellp()); -		 -		if (temp_len) -		{ -			return tmp.str().substr(0, std::min(temp_len, std::size_t(1024))); -		} -	} -	else -	{ -		// *TODO:  More elaborate forms based on Content-Type as needed. -		char content[1024]; - -		size_t len(body->read(0, content, sizeof(content))); -		if (len) -		{ -			return std::string(content, 0, len); -		} -	} - -	// Default -	return empty; +    static const std::string empty("[Empty]"); + +    if (!response) +    { +        return empty; +    } + +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return empty; +    } + +    // Attempt to parse as LLSD regardless of content-type +    LLSD body_llsd; +    if (responseToLLSD(response, false, body_llsd)) +    { +        std::ostringstream tmp; + +        LLSDSerialize::toPrettyNotation(body_llsd, tmp); +        std::size_t temp_len(tmp.tellp()); + +        if (temp_len) +        { +            return tmp.str().substr(0, std::min(temp_len, std::size_t(1024))); +        } +    } +    else +    { +        // *TODO:  More elaborate forms based on Content-Type as needed. +        char content[1024]; + +        size_t len(body->read(0, content, sizeof(content))); +        if (len) +        { +            return std::string(content, 0, len); +        } +    } + +    // Default +    return empty; +} + +//======================================================================== + +HttpCoroHandler::HttpCoroHandler(LLEventStream &reply) : +    mReplyPump(reply) +{ +} + +void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +    LLSD result; + +    LLCore::HttpStatus status = response->getStatus(); + +    if (status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_HANDLE_NOT_FOUND)) +    {   // A response came in for a canceled request and we have not processed the  +        // cancel yet.  Patience! +        return; +    } + +    if (!status) +    { +        result = LLSD::emptyMap(); +        LL_WARNS() +            << "\n--------------------------------------------------------------------------\n" +            << " Error[" << status.getType() << "] cannot access url '" << response->getRequestURL() +            << "' because " << status.toString() +            << "\n--------------------------------------------------------------------------" +            << LL_ENDL; +    } +    else +    { +        result = this->handleSuccess(response, status); +    } + +    buildStatusEntry(response, status, result); + +#if 1 +    // commenting out, but keeping since this can be useful for debugging +    if (!status) +    { +        LLSD &httpStatus = result[HttpCoroutineAdapter::HTTP_RESULTS]; + +        LLCore::BufferArray *body = response->getBody(); +        LLCore::BufferArrayStream bas(body); +        LLSD::String bodyData; +        bodyData.reserve(response->getBodySize()); +        bas >> std::noskipws; +        bodyData.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); +        httpStatus["error_body"] = LLSD(bodyData); + +        LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL; +    } +#endif + +    mReplyPump.post(result); +} + +void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) +{ +    LLSD httpresults = LLSD::emptyMap(); + +    writeStatusCodes(status, response->getRequestURL(), httpresults); + +    LLSD httpHeaders = LLSD::emptyMap(); +    LLCore::HttpHeaders::ptr_t hdrs = response->getHeaders(); + +    if (hdrs) +    { +        for (LLCore::HttpHeaders::iterator it = hdrs->begin(); it != hdrs->end(); ++it) +        { +            if (!(*it).second.empty()) +            { +                httpHeaders[(*it).first] = (*it).second; +            } +            else +            { +                httpHeaders[(*it).first] = static_cast<LLSD::Boolean>(true); +            } +        } +    } + +    httpresults[HttpCoroutineAdapter::HTTP_RESULTS_HEADERS] = httpHeaders; +    result[HttpCoroutineAdapter::HTTP_RESULTS] = httpresults; +} + +void HttpCoroHandler::writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result) +{ +    result[HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS] = static_cast<LLSD::Boolean>(status); +    result[HttpCoroutineAdapter::HTTP_RESULTS_TYPE] = static_cast<LLSD::Integer>(status.getType()); +    result[HttpCoroutineAdapter::HTTP_RESULTS_STATUS] = static_cast<LLSD::Integer>(status.getStatus()); +    result[HttpCoroutineAdapter::HTTP_RESULTS_MESSAGE] = static_cast<LLSD::String>(status.getMessage()); +    result[HttpCoroutineAdapter::HTTP_RESULTS_URL] = static_cast<LLSD::String>(url); + +} + +//========================================================================= +/// The HttpCoroLLSDHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines. When the request is completed the response  +/// will be posted onto the supplied Event Pump. +///  +/// If the LLSD retrieved from through the HTTP connection is not in the form +/// of a LLSD::map it will be returned as in an llsd["content"] element. +///  +/// The LLSD posted back to the coroutine will have the following additions: +/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status +///                      +- ["status"]  - The status code associated with the HTTP call +///                      +- ["success"] - Success of failure of the HTTP call and LLSD parsing. +///                      +- ["type"]    - The LLCore::HttpStatus type associted with the HTTP call +///                      +- ["url"]     - The URL used to make the call. +///                      +- ["headers"] - A map of name name value pairs with the HTTP headers. +///                       +class HttpCoroLLSDHandler : public HttpCoroHandler +{ +public: +    HttpCoroLLSDHandler(LLEventStream &reply); + +protected: +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); +}; + +//------------------------------------------------------------------------- +HttpCoroLLSDHandler::HttpCoroLLSDHandler(LLEventStream &reply): +    HttpCoroHandler(reply) +{ +} +     + +LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +{ +    LLSD result; + +    const bool emit_parse_errors = false; + +    bool parsed = !((response->getBodySize() == 0) || +        !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result)); + +    if (!parsed) +    { +        // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' +        LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); +        const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; + +        if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) +        { +            std::string thebody = LLCoreHttpUtil::responseToString(response); +            LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " +                << " body: " << thebody << LL_ENDL; + +            // Replace the status with a new one indicating the failure. +            status = LLCore::HttpStatus(499, "Failed to deserialize LLSD."); +        } +    } + +    if (result.isUndefined()) +    {   // If we've gotten to this point and the result LLSD is still undefined  +        // either there was an issue deserializing the body or the response was +        // blank.  Create an empty map to hold the result either way. +        result = LLSD::emptyMap(); +    } +    else if (!result.isMap()) +    {   // The results are not themselves a map.  Move them down so that  +        // this method can return a map to the caller. +        // *TODO: Should it always do this? +        LLSD newResult = LLSD::emptyMap(); +        newResult[HttpCoroutineAdapter::HTTP_RESULTS_CONTENT] = result; +        result = newResult; +    } + +    return result; +} + +//======================================================================== +/// The HttpCoroRawHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines.  +///  +/// In addition to the normal "http_results" the returned LLSD will contain  +/// an entry keyed with "raw" containing the unprocessed results of the HTTP +/// call. +///                       +class HttpCoroRawHandler : public HttpCoroHandler +{ +public: +    HttpCoroRawHandler(LLEventStream &reply); + +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); +}; + +//------------------------------------------------------------------------- +HttpCoroRawHandler::HttpCoroRawHandler(LLEventStream &reply): +    HttpCoroHandler(reply) +{ +} + +LLSD HttpCoroRawHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +{ +    LLSD result = LLSD::emptyMap(); + +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return result; +    } + +    size_t size = body->size(); + +    LLCore::BufferArrayStream bas(body); + +#if 1 +    // This is the slower implementation.  It is safe vis-a-vi the const_cast<> and modification +    // of a LLSD managed array but contains an extra (potentially large) copy. +    //  +    // *TODO: https://jira.secondlife.com/browse/MAINT-5221 +     +    LLSD::Binary data; +    data.reserve(size); +    bas >> std::noskipws; +    data.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); + +    result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = data; + +#else +    // This is disabled because it's dangerous.  See the other case for an  +    // alternate implementation. +    // We create a new LLSD::Binary object and assign it to the result map. +    // The LLSD has created it's own copy so we retrieve it asBinary and const cast  +    // the reference so that we can modify it. +    // *TODO: This is potentially dangerous... but I am trying to avoid a potentially  +    // large copy. +    result[HttpCoroutineAdapter::HTTP_RESULTS_RAW] = LLSD::Binary(); +    LLSD::Binary &data = const_cast<LLSD::Binary &>( result[HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary() ); + +    data.reserve(size); +    bas >> std::noskipws; +    data.assign(std::istream_iterator<U8>(bas), std::istream_iterator<U8>()); +#endif + +    return result; +} + +//======================================================================== +/// The HttpCoroJSONHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines.  +///  +/// In addition to the normal "http_results" the returned LLSD will contain  +/// JSON entries will be converted into an LLSD map.  All results are considered  +/// strings +///                       +class HttpCoroJSONHandler : public HttpCoroHandler +{ +public: +    HttpCoroJSONHandler(LLEventStream &reply); + +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status); +}; + +//------------------------------------------------------------------------- +HttpCoroJSONHandler::HttpCoroJSONHandler(LLEventStream &reply) : +    HttpCoroHandler(reply) +{ +} + +LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) +{ +    LLSD result = LLSD::emptyMap(); + +    BufferArray * body(response->getBody()); +    if (!body || !body->size()) +    { +        return result; +    } + +    LLCore::BufferArrayStream bas(body); +    Json::Value jsonRoot; + +    try +    { +        bas >> jsonRoot; +    } +    catch (std::runtime_error e) +    {   // deserialization failed.  Record the reason and pass back an empty map for markup. +        status = LLCore::HttpStatus(499, std::string(e.what())); +        return result; +    } + +    // Convert the JSON structure to LLSD +    result = LlsdFromJson(jsonRoot); + +    return result; +} + + +//======================================================================== +HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) : +    mHttpRequest(request) +{ +    mBoundListener = LLEventPumps::instance().obtain("mainloop"). +        listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1)); +} + +HttpRequestPumper::~HttpRequestPumper() +{ +    if (mBoundListener.connected()) +    { +        mBoundListener.disconnect(); +    } +} + +bool HttpRequestPumper::pollRequest(const LLSD&) +{ +    if (mHttpRequest->getStatus() != HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED)) +    { +        mHttpRequest->update(0L); +    } +    return false; +} + +//======================================================================== +const std::string HttpCoroutineAdapter::HTTP_RESULTS("http_result"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_SUCCESS("success"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_TYPE("type"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_STATUS("status"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_MESSAGE("message"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_URL("url"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_HEADERS("headers"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_CONTENT("content"); +const std::string HttpCoroutineAdapter::HTTP_RESULTS_RAW("raw"); + +HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name, +    LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) : +    mAdapterName(name), +    mPolicyId(policyId), +    mPriority(priority), +    mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID), +    mWeakRequest(), +    mWeakHandler() +{ +} + +HttpCoroutineAdapter::~HttpCoroutineAdapter() +{ +    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, 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::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(); + +    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, 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::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, 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::patchAndYield(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 patchAndYield_(request, url, body, options, headers, httpHandler); +} + + +LLSD HttpCoroutineAdapter::patchAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, const LLSD & body, +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    LLCore::HttpHandle hhandle = requestPatchWithLLSD(request, +        mPolicyId, mPriority, url, body, options, headers, +        handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); + +    return results; +} + +LLSD HttpCoroutineAdapter::copyAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, const std::string dest, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    if (!headers) +        headers.reset(new LLCore::HttpHeaders); +    headers->append(HTTP_OUT_HEADER_DESTINATION, dest); + +    return copyAndYield_(request, url, options, headers, httpHandler); +} + + +LLSD HttpCoroutineAdapter::copyAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url,  +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    //  +    LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, mPriority, url, +        options, headers, handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); + +    return results; +} + +LLSD HttpCoroutineAdapter::moveAndYield(LLCore::HttpRequest::ptr_t request, +    const std::string & url, const std::string dest, +    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers) +{ +    LLEventStream  replyPump(mAdapterName + "Reply", true); +    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump)); + +    if (!headers) +        headers.reset(new LLCore::HttpHeaders); +    headers->append(HTTP_OUT_HEADER_DESTINATION, dest); + +    return moveAndYield_(request, url, options, headers, httpHandler); +} + + +LLSD HttpCoroutineAdapter::moveAndYield_(LLCore::HttpRequest::ptr_t &request, +    const std::string & url, +    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +    HttpCoroHandler::ptr_t &handler) +{ +    HttpRequestPumper pumper(request); + +    checkDefaultHeaders(headers); + +    // The HTTPCoroHandler does not self delete, so retrieval of a the contained  +    // pointer from the smart pointer is safe in this case. +    //  +    LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, mPriority, url, +        options, headers, handler.get()); + +    if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +    { +        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url); +    } + +    saveState(hhandle, request, handler); +    LLSD results = llcoro::waitForEventOn(handler->getReplyPump()); +    cleanState(); + +    return results; +} + + +void HttpCoroutineAdapter::checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers) +{ +    if (!headers) +        headers.reset(new LLCore::HttpHeaders); +    if (!headers->find(HTTP_OUT_HEADER_ACCEPT)) +    { +        headers->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); +    } +    if (!headers->find(HTTP_OUT_HEADER_CONTENT_TYPE)) +    { +        headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); +    } + +    if (!headers->find("X-SecondLife-UDP-Listen-Port") && gMessageSystem) +    { +        headers->append("X-SecondLife-UDP-Listen-Port", llformat("%d", gMessageSystem->mPort)); +    } +} + + +void HttpCoroutineAdapter::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..31a73bb900 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 @@ -101,15 +107,505 @@ std::string responseToString(LLCore::HttpResponse * response);  ///						a now-useless HttpHandler object.  ///  LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request, -									   LLCore::HttpRequest::policy_t policy_id, -									   LLCore::HttpRequest::priority_t priority, -									   const std::string & url, -									   const LLSD & body, -									   LLCore::HttpOptions * options, -									   LLCore::HttpHeaders * headers, -									   LLCore::HttpHandler * handler); +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    const LLCore::HttpOptions::ptr_t &options, +    const LLCore::HttpHeaders::ptr_t &headers, +    LLCore::HttpHandler * handler); -} // end namespace LLCoreHttpUtil +inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	const LLCore::HttpOptions::ptr_t & options, +	const LLCore::HttpHeaders::ptr_t & headers, +	LLCore::HttpHandler * handler) +{ +    return requestPostWithLLSD(request.get(), policy_id, priority, +        url, body, options, headers, handler); +} + +inline LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpHandler * handler) +{ +    LLCore::HttpOptions::ptr_t options; +    LLCore::HttpHeaders::ptr_t headers; + +    return requestPostWithLLSD(request.get(), policy_id, priority, +        url, body, options, headers, handler); +} + + +/// Issue a standard HttpRequest::requestPut() call but using +/// and LLSD object as the request body.  Conventions are the +/// same as with that method.  Caller is expected to provide +/// an HttpHeaders object with a correct 'Content-Type:' header. +/// One will not be provided by this call. +/// +/// @return				If request is successfully issued, the +///						HttpHandle representing the request. +///						On error, LLCORE_HTTP_HANDLE_INVALID +///						is returned and caller can fetch detailed +///						status with the getStatus() method on the +///						request object.  In case of error, no +///						request is queued and caller may need to +///						perform additional cleanup such as freeing +///						a now-useless HttpHandler object. +/// +LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	const LLCore::HttpOptions::ptr_t &options, +	const LLCore::HttpHeaders::ptr_t &headers, +	LLCore::HttpHandler * handler); + +inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	const LLCore::HttpOptions::ptr_t & options, +	const LLCore::HttpHeaders::ptr_t & headers, +	LLCore::HttpHandler * handler) +{ +    return requestPutWithLLSD(request.get(), policy_id, priority, +        url, body, options, headers, handler); +} + +inline LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpHandler * handler) +{ +    LLCore::HttpOptions::ptr_t options; +    LLCore::HttpHeaders::ptr_t headers; + +    return requestPutWithLLSD(request.get(), policy_id, priority, +        url, body, options, headers, handler); +} + +/// Issue a standard HttpRequest::requestPatch() call but using +/// and LLSD object as the request body.  Conventions are the +/// same as with that method.  Caller is expected to provide +/// an HttpHeaders object with a correct 'Content-Type:' header. +/// One will not be provided by this call. +/// +/// @return				If request is successfully issued, the +///						HttpHandle representing the request. +///						On error, LLCORE_HTTP_HANDLE_INVALID +///						is returned and caller can fetch detailed +///						status with the getStatus() method on the +///						request object.  In case of error, no +///						request is queued and caller may need to +///						perform additional cleanup such as freeing +///						a now-useless HttpHandler object. +/// +LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest * request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    const LLCore::HttpOptions::ptr_t &options, +    const LLCore::HttpHeaders::ptr_t &headers, +    LLCore::HttpHandler * handler); + +inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    const LLCore::HttpOptions::ptr_t & options, +    const LLCore::HttpHeaders::ptr_t & headers, +    LLCore::HttpHandler * handler) +{ +    return requestPatchWithLLSD(request.get(), policy_id, priority, +        url, body, options, headers, handler); +} + +inline LLCore::HttpHandle requestPatchWithLLSD(LLCore::HttpRequest::ptr_t & request, +    LLCore::HttpRequest::policy_t policy_id, +    LLCore::HttpRequest::priority_t priority, +    const std::string & url, +    const LLSD & body, +    LLCore::HttpHandler * handler) +{ +    LLCore::HttpOptions::ptr_t options; +    LLCore::HttpHeaders::ptr_t headers; + +    return requestPatchWithLLSD(request.get(), policy_id, priority, +        url, body, options, headers, handler); +} + +//========================================================================= +/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines. When the request is completed the response  +/// will be posted onto the supplied Event Pump. +///  +/// The LLSD posted back to the coroutine will have the following additions: +/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status +///                      +- ["status"]  - The status code associated with the HTTP call +///                      +- ["success"] - Success of failure of the HTTP call and LLSD parsing. +///                      +- ["type"]    - The LLCore::HttpStatus type associted with the HTTP call +///                      +- ["url"]     - The URL used to make the call. +///                      +- ["headers"] - A map of name name value pairs with the HTTP headers. +///                       +class HttpCoroHandler : public LLCore::HttpHandler +{ +public: + +    typedef boost::shared_ptr<HttpCoroHandler>  ptr_t; +    typedef boost::weak_ptr<HttpCoroHandler>    wptr_t; + +    HttpCoroHandler(LLEventStream &reply); + +    static void writeStatusCodes(LLCore::HttpStatus status, const std::string &url, LLSD &result); +    virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +    inline LLEventStream &getReplyPump() +    { +        return mReplyPump; +    } + +protected: +    /// this method may modify the status value +    virtual LLSD handleSuccess(LLCore::HttpResponse * response, LLCore::HttpStatus &status) = 0; + +private: +    void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result); + +    LLEventStream &mReplyPump; +}; + +//========================================================================= +/// An adapter to handle some of the boilerplate code surrounding HTTP and coroutine  +/// interaction. +///  +/// Construct an HttpCoroutineAdapter giving it a name and policy Id. After  +/// any application specific setup call the post, put or get method.  The request  +/// will be automatically pumped and the method will return with an LLSD describing +/// the result of the operation.  See HttpCoroHandler for a description of the  +/// decoration done to the returned LLSD. +///  +/// Posting through the adapter will automatically add the following headers to  +/// the request if they have not been previously specified in a supplied  +/// HttpHeaders object: +///     "Accept=application/llsd+xml" +///     "X-SecondLife-UDP-Listen-Port=###" +///      +class HttpCoroutineAdapter +{ +public: +    static const std::string HTTP_RESULTS; +    static const std::string HTTP_RESULTS_SUCCESS; +    static const std::string HTTP_RESULTS_TYPE; +    static const std::string HTTP_RESULTS_STATUS; +    static const std::string HTTP_RESULTS_MESSAGE; +    static const std::string HTTP_RESULTS_URL; +    static const std::string HTTP_RESULTS_HEADERS; +    static const std::string HTTP_RESULTS_CONTENT; +    static const std::string HTTP_RESULTS_RAW; + +    typedef boost::shared_ptr<HttpCoroutineAdapter> ptr_t; +    typedef boost::weak_ptr<HttpCoroutineAdapter>   wptr_t; + +    HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId, +        LLCore::HttpRequest::priority_t priority = 0L); +    ~HttpCoroutineAdapter(); + +    /// Execute a Post transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available.  +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD 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())); + + +    /// Execute a PATCH transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available.  +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD patchAndYield(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 patchAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, const LLSD & body, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return patchAndYield(request, url, body, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + +    /// Execute a COPY transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available.  +    ///  +    /// @Note: The destination is passed through the HTTP pipe as a header +    /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination"); +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD copyAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, const std::string dest, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD copyAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, const std::string & dest, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return copyAndYield(request, url, dest, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + +    /// Execute a MOVE transaction on the supplied URL and yield execution of  +    /// the coroutine until a result is available.  +    ///  +    /// @Note: The destination is passed through the HTTP pipe in the headers. +    /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination"); +    ///  +    /// @Note: the request's smart pointer is passed by value so that it will +    /// not be deallocated during the yield. +    LLSD moveAndYield(LLCore::HttpRequest::ptr_t request, +        const std::string & url, const std::string dest, +        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), +        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders())); +    LLSD moveAndYield(LLCore::HttpRequest::ptr_t &request, +        const std::string & url, const std::string & dest, +        LLCore::HttpHeaders::ptr_t &headers) +    { +        return moveAndYield(request, url, dest, +            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers); +    } + +    /// +    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); + +    LLSD patchAndYield_(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 copyAndYield_(LLCore::HttpRequest::ptr_t &request, +        const std::string & url,  +        LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers, +        HttpCoroHandler::ptr_t &handler); + +    LLSD moveAndYield_(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/llhost.cpp b/indra/llmessage/llhost.cpp index 63c15f0d5e..ae5c2ecf69 100755 --- a/indra/llmessage/llhost.cpp +++ b/indra/llmessage/llhost.cpp @@ -41,8 +41,6 @@  	#include <arpa/inet.h>  #endif -LLHost LLHost::invalid(INVALID_PORT,INVALID_HOST_IP_ADDRESS); -  LLHost::LLHost(const std::string& ip_and_port)  {  	std::string::size_type colon_index = ip_and_port.find(":"); diff --git a/indra/llmessage/llhost.h b/indra/llmessage/llhost.h index 0cf52a4151..79cad4b123 100755 --- a/indra/llmessage/llhost.h +++ b/indra/llmessage/llhost.h @@ -40,9 +40,8 @@ class LLHost {  protected:  	U32			mPort;  	U32         mIP; +    std::string mUntrustedSimCap;  public: -	 -	static LLHost invalid;  	// CREATORS  	LLHost() @@ -89,13 +88,17 @@ public:  	// READERS  	U32		getAddress() const							{ return mIP; }  	U32		getPort() const								{ return mPort; } -	BOOL	isOk() const								{ return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); } +	bool	isOk() const								{ return (mIP != INVALID_HOST_IP_ADDRESS) && (mPort != INVALID_PORT); } +    bool    isInvalid()                                 { return (mIP == INVALID_HOST_IP_ADDRESS) || (mPort == INVALID_PORT); }  	size_t	hash() const								{ return (mIP << 16) | (mPort & 0xffff); }  	std::string getString() const;  	std::string getIPString() const;  	std::string getHostName() const;  	std::string getIPandPort() const; +    std::string getUntrustedSimulatorCap() const        { return mUntrustedSimCap; } +    void setUntrustedSimulatorCap(const std::string &capurl) { mUntrustedSimCap = capurl; } +  	friend std::ostream& operator<< (std::ostream& os, const LLHost &hh);  	// This operator is not well defined. does it expect a diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 60f17e6870..b149d24c4b 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/llhttpsender.cpp b/indra/llmessage/llhttpsender.cpp deleted file mode 100755 index 5363088d79..0000000000 --- a/indra/llmessage/llhttpsender.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/**  - * @file llhttpsender.cpp - * @brief Abstracts details of sending messages via HTTP. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llhttpsender.h" - -#include <map> -#include <sstream> - -#include "llhost.h" -#include "llsd.h" - -namespace -{ -	typedef std::map<LLHost, LLHTTPSender*> SenderMap; -	static SenderMap senderMap; -	static LLPointer<LLHTTPSender> defaultSender(new LLHTTPSender()); -} - -//virtual  -LLHTTPSender::~LLHTTPSender() -{ -} - -//virtual  -void LLHTTPSender::send(const LLHost& host, const std::string& name,  -						const LLSD& body,  -						LLHTTPClient::ResponderPtr response) const -{ -	// Default implementation inserts sender, message and sends HTTP POST -	std::ostringstream stream; -	stream << "http://" << host << "/trusted-message/" << name; -	LL_INFOS() << "LLHTTPSender::send: POST to " << stream.str() << LL_ENDL; -	LLHTTPClient::post(stream.str(), body, response); -} - -//static  -void LLHTTPSender::setSender(const LLHost& host, LLHTTPSender* sender) -{ -	LL_INFOS() << "LLHTTPSender::setSender " << host << LL_ENDL; -	senderMap[host] = sender; -} - -//static -const LLHTTPSender& LLHTTPSender::getSender(const LLHost& host) -{ -	SenderMap::const_iterator iter = senderMap.find(host); -	if(iter == senderMap.end()) -	{ -		return *defaultSender; -	} -	return *(iter->second); -} - -//static  -void LLHTTPSender::clearSender(const LLHost& host) -{ -	SenderMap::iterator iter = senderMap.find(host); -	if(iter != senderMap.end()) -	{ -		delete iter->second; -		senderMap.erase(iter); -	} -} - -//static  -void LLHTTPSender::setDefaultSender(LLHTTPSender* sender) -{ -	defaultSender = sender; -} diff --git a/indra/llmessage/llhttpsender.h b/indra/llmessage/llhttpsender.h deleted file mode 100755 index ff8fa2f95b..0000000000 --- a/indra/llmessage/llhttpsender.h +++ /dev/null @@ -1,59 +0,0 @@ -/**  - * @file llhttpsender.h - * @brief Abstracts details of sending messages via HTTP. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_HTTP_SENDER_H -#define LL_HTTP_SENDER_H - -#include "llhttpclient.h" - -class LLHost; -class LLSD; - -class LLHTTPSender : public LLThreadSafeRefCount -{ - public: - -	virtual ~LLHTTPSender(); - -	/** @brief Send message to host with body, call response when done */  -	virtual void send(const LLHost& host,  -					  const std::string& message, const LLSD& body,  -					  LLHTTPClient::ResponderPtr response) const; - -	/** @brief Set sender for host, takes ownership of sender. */ -	static void setSender(const LLHost& host, LLHTTPSender* sender); - -	/** @brief Get sender for host, retains ownership of returned sender. */ -	static const LLHTTPSender& getSender(const LLHost& host); -	 -	/** @brief Clear sender for host. */ -	static void clearSender(const LLHost& host); - -	/** @brief Set default sender, takes ownership of sender. */ -	static void setDefaultSender(LLHTTPSender* sender); -}; - -#endif // LL_HTTP_SENDER_H diff --git a/indra/llmessage/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/message.cpp b/indra/llmessage/message.cpp index e9ce94ab3b..10dbbef046 100755 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -52,7 +52,6 @@  #include "llfasttimer.h"  #include "llhttpclient.h"  #include "llhttpnodeadapter.h" -#include "llhttpsender.h"  #include "llmd5.h"  #include "llmessagebuilder.h"  #include "llmessageconfig.h" @@ -77,6 +76,7 @@  #include "v3math.h"  #include "v4math.h"  #include "lltransfertargetvfile.h" +#include "llcorehttputil.h"  // Constants  //const char* MESSAGE_LOG_FILENAME = "message.log"; @@ -97,45 +97,6 @@ public:  	apr_pollfd_t mPollFD;  }; -namespace -{ -	class LLFnPtrResponder : public LLHTTPClient::Responder -	{ -		LOG_CLASS(LLFnPtrResponder); -	public: -		LLFnPtrResponder(void (*callback)(void **,S32), void **callbackData, const std::string& name) : -			mCallback(callback), -			mCallbackData(callbackData), -			mMessageName(name) -		{ -		} - -	protected: -		virtual void httpFailure() -		{ -			// don't spam when agent communication disconnected already -			if (HTTP_GONE != getStatus()) -			{ -				LL_WARNS("Messaging") << "error for message " << mMessageName -									  << " " << dumpResponse() << LL_ENDL; -			} -			// TODO: Map status in to useful error code. -			if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT); -		} -		 -		virtual void httpSuccess() -		{ -			if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR); -		} - -	private: - -		void (*mCallback)(void **,S32);     -		void **mCallbackData; -		std::string mMessageName; -	}; -} -  class LLMessageHandlerBridge : public LLHTTPNode  {  	virtual bool validate(const std::string& name, LLSD& context) const @@ -1129,29 +1090,6 @@ S32 LLMessageSystem::flushReliable(const LLHost &host)  	return send_bytes;  } -LLHTTPClient::ResponderPtr LLMessageSystem::createResponder(const std::string& name) -{ -	if(mSendReliable) -	{ -		return new LLFnPtrResponder( -			mReliablePacketParams.mCallback, -			mReliablePacketParams.mCallbackData, -			name); -	} -	else -	{ -		// These messages aren't really unreliable, they just weren't -		// explicitly sent as reliable, so they don't have a callback -//		LL_WARNS("Messaging") << "LLMessageSystem::sendMessage: Sending unreliable " -//				<< mMessageBuilder->getMessageName() << " message via HTTP" -//				<< LL_ENDL; -		return new LLFnPtrResponder( -			NULL, -			NULL, -			name); -	} -} -  // This can be called from signal handlers,  // so should should not use LL_INFOS().  S32 LLMessageSystem::sendMessage(const LLHost &host) @@ -1216,13 +1154,17 @@ S32 LLMessageSystem::sendMessage(const LLHost &host)  	if(mMessageBuilder == mLLSDMessageBuilder)  	{  		LLSD message = mLLSDMessageBuilder->getMessage(); -		 -		const LLHTTPSender& sender = LLHTTPSender::getSender(host); -		sender.send( -			host, -			mLLSDMessageBuilder->getMessageName(), -			message, -			createResponder(mLLSDMessageBuilder->getMessageName())); + +        UntrustedCallback_t cb = NULL; +        if ((mSendReliable) && (mReliablePacketParams.mCallback)) +        { +            cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1); +        } + +        LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro", +            boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this,  +            host.getUntrustedSimulatorCap(),  +            mLLSDMessageBuilder->getMessageName(), message, cb));  		mSendReliable = FALSE;  		mReliablePacketParams.clear(); @@ -1410,9 +1352,16 @@ S32 LLMessageSystem::sendMessage(  		return 0;  	} -	const LLHTTPSender& sender = LLHTTPSender::getSender(host); -	sender.send(host, name, message, createResponder(name)); -	return 1; +    UntrustedCallback_t cb = NULL; +    if ((mSendReliable) && (mReliablePacketParams.mCallback)) +    { +        cb = boost::bind(mReliablePacketParams.mCallback, mReliablePacketParams.mCallbackData, _1); +    } + +    LLCoros::instance().launch("LLMessageSystem::sendUntrustedSimulatorMessageCoro", +            boost::bind(&LLMessageSystem::sendUntrustedSimulatorMessageCoro, this, +            host.getUntrustedSimulatorCap(), name, message, cb)); +    return 1;  }  void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host ) @@ -1725,7 +1674,7 @@ LLHost LLMessageSystem::findHost(const U32 circuit_code)  	}  	else  	{ -		return LLHost::invalid; +		return LLHost();  	}  } @@ -4055,6 +4004,36 @@ const LLHost& LLMessageSystem::getSender() const  	return mLastSender;  } +void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback) +{ +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + +    if (url.empty()) +    { +        LL_WARNS() << "sendUntrustedSimulatorMessageCoro called with empty capability!" << LL_ENDL; +        return; +    } + +    LL_INFOS() << "sendUntrustedSimulatorMessageCoro: message " << message << " to cap " << url << LL_ENDL; +    LLSD postData; +    postData["message"] = message; +    postData["body"] = body; + +    LLSD result = httpAdapter->postAndYield(httpRequest, url, postData, httpOpts); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if ((callback) && (!callback.empty())) +        callback((status) ? LL_ERR_NOERR : LL_ERR_TCP_TIMEOUT); +} + +  LLHTTPRegistration<LLHTTPNodeAdapter<LLTrustedMessageService> >  	gHTTPRegistrationTrustedMessageWildcard("/trusted-message/<message-name>"); diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 348b09b992..fc391da633 100755 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -60,6 +60,7 @@  #include "llmessagesenderinterface.h"  #include "llstoredmessage.h" +#include "boost/function.hpp"  const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;  const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192; @@ -489,7 +490,6 @@ public:  		void (*callback)(void **,S32),   		void ** callback_data); -	LLCurl::ResponderPtr createResponder(const std::string& name);  	S32		sendMessage(const LLHost &host);  	S32		sendMessage(const U32 circuit);  private: @@ -740,6 +740,9 @@ public:  	void receivedMessageFromTrustedSender();  private: +    typedef boost::function<void(S32)>  UntrustedCallback_t; +    void sendUntrustedSimulatorMessageCoro(std::string url, std::string message, LLSD body, UntrustedCallback_t callback); +  	bool mLastMessageFromTrustedMessageService; diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp deleted file mode 100755 index e9ce116bb3..0000000000 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/**  - * @file llhttpclientadapter_test.cpp - * @brief Tests for LLHTTPClientAdapter - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llhttpclientadapter.h" - -#include "../test/lltut.h" -#include "llhttpclient.h" -#include "llcurl_stub.cpp" - -float const HTTP_REQUEST_EXPIRY_SECS = 1.0F; - -std::vector<std::string> get_urls; -std::vector< LLCurl::ResponderPtr > get_responders; -void LLHTTPClient::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout, bool follow_redirects) -{ -	get_urls.push_back(url); -	get_responders.push_back(responder); -} - -std::vector<std::string> put_urls; -std::vector<LLSD> put_body; -std::vector<LLSD> put_headers; -std::vector<LLCurl::ResponderPtr> put_responders; - -void LLHTTPClient::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout) -{ -	put_urls.push_back(url); -	put_responders.push_back(responder); -	put_body.push_back(body); -	put_headers.push_back(headers); - -} - -std::vector<std::string> delete_urls; -std::vector<LLCurl::ResponderPtr> delete_responders; - -void LLHTTPClient::del( -	const std::string& url, -	LLCurl::ResponderPtr responder, -	const LLSD& headers, -	const F32 timeout) -{ -	delete_urls.push_back(url); -	delete_responders.push_back(responder); -} - -namespace tut -{ -	struct LLHTTPClientAdapterData -	{ -		LLHTTPClientAdapterData() -		{ -			get_urls.clear(); -			get_responders.clear(); -			put_urls.clear(); -			put_responders.clear(); -			put_body.clear(); -			put_headers.clear(); -			delete_urls.clear(); -			delete_responders.clear(); -		} -	}; - -	typedef test_group<LLHTTPClientAdapterData> factory; -	typedef factory::object object; -} - -namespace -{ -	tut::factory tf("LLHTTPClientAdapterData"); -} - -namespace tut -{ -	// Ensure we can create the object -	template<> template<> -	void object::test<1>() -	{ -		LLHTTPClientAdapter adapter; -	} - -	// Does the get pass the appropriate arguments to the LLHTTPClient -	template<> template<> -	void object::test<2>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		adapter.get("Made up URL", responder); -		ensure_equals(get_urls.size(), 1); -		ensure_equals(get_urls[0], "Made up URL"); -	} - -	// Ensure the responder matches the one passed to get -	template<> template<> -	void object::test<3>() -	{ -		LLHTTPClientAdapter adapter; -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		adapter.get("Made up URL", responder); - -		ensure_equals(get_responders.size(), 1); -		ensure_equals(get_responders[0].get(), responder.get()); -	} -	 -	// Ensure the correct url is used in the put -	template<> template<> -	void object::test<4>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body; -		body["TestBody"] = "Foobar"; - -		adapter.put("Made up URL", body, responder); -		ensure_equals(put_urls.size(), 1); -		ensure_equals(put_urls[0], "Made up URL"); -	} - -	// Ensure the correct responder is used by put -	template<> template<> -	void object::test<5>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body; -		body["TestBody"] = "Foobar"; - -		adapter.put("Made up URL", body, responder); - -		ensure_equals(put_responders.size(), 1); -		ensure_equals(put_responders[0].get(), responder.get()); -	} - -	// Ensure the message body is passed through the put properly -	template<> template<> -	void object::test<6>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body; -		body["TestBody"] = "Foobar"; - -		adapter.put("Made up URL", body, responder); - -		ensure_equals(put_body.size(), 1); -		ensure_equals(put_body[0]["TestBody"].asString(), "Foobar"); -	} - -	// Ensure that headers are passed through put properly -	template<> template<> -	void object::test<7>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		LLSD body = LLSD::emptyMap(); -		body["TestBody"] = "Foobar"; - -		LLSD headers = LLSD::emptyMap(); -		headers["booger"] = "omg"; - -		adapter.put("Made up URL", body, responder, headers); - -		ensure_equals("Header count", put_headers.size(), 1); -		ensure_equals( -			"First header", -			put_headers[0]["booger"].asString(), -			"omg"); -	} - -	// Ensure that del() passes appropriate arguments to the LLHTTPClient -	template<> template<> -	void object::test<8>() -	{ -		LLHTTPClientAdapter adapter; - -		LLCurl::ResponderPtr responder = new LLCurl::Responder(); - -		adapter.del("Made up URL", responder); - -		ensure_equals("URL count", delete_urls.size(), 1); -		ensure_equals("Received URL", delete_urls[0], "Made up URL"); - -		ensure_equals("Responder count", delete_responders.size(), 1); -		//ensure_equals("Responder", delete_responders[0], responder); -	} -} - diff --git a/indra/llmessage/tests/llsdmessage_test.cpp b/indra/llmessage/tests/llsdmessage_test.cpp deleted file mode 100755 index 44b024a83f..0000000000 --- a/indra/llmessage/tests/llsdmessage_test.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file   llsdmessage_test.cpp - * @author Nat Goodspeed - * @date   2008-12-22 - * @brief  Test of llsdmessage.h - *  - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#if LL_WINDOWS -#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want! -#endif - -// Precompiled header -#include "linden_common.h" -// associated header -#include "llsdmessage.h" -// STL headers -#include <iostream> -// std headers -#include <stdexcept> -#include <typeinfo> -// external library headers -// other Linden headers -#include "../test/lltut.h" -#include "../test/catch_and_store_what_in.h" -#include "llsdserialize.h" -#include "llevents.h" -#include "stringize.h" -#include "llhost.h" -#include "tests/networkio.h" -#include "tests/commtest.h" - -/***************************************************************************** -*   TUT -*****************************************************************************/ -namespace tut -{ -    struct llsdmessage_data: public commtest_data -    { -        LLEventPump& httpPump; - -        llsdmessage_data(): -            httpPump(pumps.obtain("LLHTTPClient")) -        { -            LLCurl::initClass(); -            LLSDMessage::link(); -        } -    }; -    typedef test_group<llsdmessage_data> llsdmessage_group; -    typedef llsdmessage_group::object llsdmessage_object; -    llsdmessage_group llsdmgr("llsdmessage"); - -    template<> template<> -    void llsdmessage_object::test<1>() -    { -        std::string threw; -        // This should fail... -        try -        { -            LLSDMessage localListener; -        } -        CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupPumpName) -        ensure("second LLSDMessage should throw", ! threw.empty()); -    } - -    template<> template<> -    void llsdmessage_object::test<2>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        bool threw = false; -        try -        { -            httpPump.post(request); -        } -        catch (const LLSDMessage::ArgError&) -        { -            threw = true; -        } -        ensure("missing URL", threw); -    } - -    template<> template<> -    void llsdmessage_object::test<3>() -    { -        LLSD request, body; -        body["data"] = "yes"; -        request["url"] = server + "got-message"; -        request["payload"] = body; -        request["reply"] = replyPump.getName(); -        request["error"] = errorPump.getName(); -        httpPump.post(request); -        ensure("got response", netio.pump()); -        ensure("success response", success); -        ensure_equals(result["reply"].asString(), "success"); - -        body["status"] = 499; -        body["reason"] = "custom error message"; -        request["url"] = server + "fail"; -        request["payload"] = body; -        httpPump.post(request); -        ensure("got response", netio.pump()); -        ensure("failure response", ! success); -        ensure_equals(result["status"].asInteger(), body["status"].asInteger()); -        ensure_equals(result["reason"].asString(),  body["reason"].asString()); -    } -} // namespace tut diff --git a/indra/llmessage/tests/lltesthttpclientadapter.cpp b/indra/llmessage/tests/lltesthttpclientadapter.cpp deleted file mode 100755 index 4539e4a540..0000000000 --- a/indra/llmessage/tests/lltesthttpclientadapter.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**  - * @file  - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ -#include "lltesthttpclientadapter.h" - -LLTestHTTPClientAdapter::LLTestHTTPClientAdapter() -{ -} - -LLTestHTTPClientAdapter::~LLTestHTTPClientAdapter() -{ -} - -void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder) -{ -	mGetUrl.push_back(url); -	mGetResponder.push_back(responder); -} - -void LLTestHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) -{ -	mPutUrl.push_back(url); -	mPutBody.push_back(body); -	mPutResponder.push_back(responder); -} - -U32 LLTestHTTPClientAdapter::putCalls() const  -{  -	return mPutUrl.size();  -} - -void LLTestHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) -{ -	mGetUrl.push_back(url); -	mGetHeaders.push_back(headers); -	mGetResponder.push_back(responder); -} - - diff --git a/indra/llmessage/tests/lltesthttpclientadapter.h b/indra/llmessage/tests/lltesthttpclientadapter.h deleted file mode 100755 index c29cbb3a2a..0000000000 --- a/indra/llmessage/tests/lltesthttpclientadapter.h +++ /dev/null @@ -1,57 +0,0 @@ -/**  - * @file  - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLTESTHTTPCLIENTADAPTER_H -#define LL_LLTESTHTTPCLIENTADAPTER_H - - -#include "linden_common.h" -#include "llhttpclientinterface.h" - -class LLTestHTTPClientAdapter : public LLHTTPClientInterface -{ -public: -	LLTestHTTPClientAdapter(); -	virtual ~LLTestHTTPClientAdapter(); -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder); -	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers); - -	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder); -	U32 putCalls() const; - -	std::vector<LLSD> mPutBody; -	std::vector<LLSD> mGetHeaders; -	std::vector<std::string> mPutUrl; -	std::vector<std::string> mGetUrl; -	std::vector<LLCurl::ResponderPtr> mPutResponder; -	std::vector<LLCurl::ResponderPtr> mGetResponder; -}; - - - -#endif //LL_LLSIMULATORPRESENCESENDER_H - | 
