diff options
Diffstat (limited to 'indra/llmessage')
-rwxr-xr-x | indra/llmessage/CMakeLists.txt | 15 | ||||
-rwxr-xr-x | indra/llmessage/llavatarnamecache.cpp | 286 | ||||
-rwxr-xr-x | indra/llmessage/llavatarnamecache.h | 5 | ||||
-rw-r--r-- | indra/llmessage/llcorehttputil.cpp | 168 | ||||
-rw-r--r-- | indra/llmessage/llcorehttputil.h | 87 | ||||
-rwxr-xr-x | indra/llmessage/llcurl.cpp | 858 | ||||
-rwxr-xr-x | indra/llmessage/llcurl.h | 96 | ||||
-rwxr-xr-x | indra/llmessage/llhttpclient.cpp | 4 | ||||
-rwxr-xr-x | indra/llmessage/llhttpclientadapter.cpp | 90 | ||||
-rwxr-xr-x | indra/llmessage/llhttpclientadapter.h | 2 | ||||
-rwxr-xr-x | indra/llmessage/llhttpclientinterface.h | 16 | ||||
-rw-r--r-- | indra/llmessage/llhttpsdhandler.cpp | 103 | ||||
-rw-r--r-- | indra/llmessage/llhttpsdhandler.h | 67 | ||||
-rwxr-xr-x | indra/llmessage/llsdrpcclient.h | 8 | ||||
-rwxr-xr-x | indra/llmessage/tests/llhttpclientadapter_test.cpp | 3 |
15 files changed, 1136 insertions, 672 deletions
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 40eddcb0ab..f6ca6a3634 100755 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -49,6 +49,7 @@ set(llmessage_SOURCE_FILES llhttpclientadapter.cpp llhttpconstants.cpp llhttpnode.cpp + llhttpsdhandler.cpp llhttpsender.cpp llinstantmessage.cpp lliobuffer.cpp @@ -144,6 +145,7 @@ set(llmessage_HEADER_FILES llhttpconstants.h llhttpnode.h llhttpnodeadapter.h + llhttpsdhandler.h llhttpsender.h llinstantmessage.h llinvite.h @@ -224,7 +226,7 @@ target_link_libraries( llmessage ${CURL_LIBRARIES} ${LLCOMMON_LIBRARIES} - ${LLVFS_LIBRARES} + ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${CARES_LIBRARIES} ${OPENSSL_LIBRARIES} @@ -241,15 +243,20 @@ 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} + ${LLMESSAGE_LIBRARIES} + ${LLCOREHTTP_LIBRARIES} + ${BOOST_CONTEXT_LIBRARY} + ${BOOST_COROUTINE_LIBRARY} + ${GOOGLEMOCK_LIBRARIES} ) LL_ADD_INTEGRATION_TEST( diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index d02a60b7b2..88859819e0 100755 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -33,9 +33,18 @@ #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 +99,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 +136,13 @@ namespace LLAvatarNameCache // Erase expired names from cache void eraseUnrefreshed(); - bool expirationFromCacheControl(const LLSD& headers, F64 *expires); + //bool expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires); + bool expirationFromCacheControl(const LLSD& headers, F64 *expires); + + // This is a coroutine. The only parameter that can be specified as a reference is the self + void requestAvatarNameCache_(LLCoros::self& self, std::string url, std::vector<LLUUID> agentIds); + + void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult); } /* Sample response: @@ -163,94 +184,125 @@ 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_(LLCoros::self& self, 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(); + LLEventStream replyPump("NameCacheReply", true); + LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler = + LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump)); - 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(); + LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::instance().getName(self) + << " with url '" << url << "', requesting " << agentIds.size() << " Agent Ids" << LL_ENDL; - LLAvatarName av_name; - av_name.fromLLSD(row); + try + { + bool success = true; - // Use expiration time from header - av_name.mExpires = expires; + LLAvatarNameCache::sHttpRequest->requestGet( + LLAvatarNameCache::sHttpPolicy, LLAvatarNameCache::sHttpPriority, + url, LLAvatarNameCache::sHttpOptions.get(), + LLAvatarNameCache::sHttpHeaders.get(), httpHandler.get()); - LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL; - av_name.dump(); - - // cache it and fire signals - LLAvatarNameCache::processName(agent_id, av_name); - } + LLSD results = waitForEventOn(self, replyPump); + LLSD httpResults; - // 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; + LL_DEBUGS() << results << LL_ENDL; - LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " - << "failed id " << agent_id - << LL_ENDL; + 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; + } + } + 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); - } - } - LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result " - << LLAvatarNameCache::sCache.size() << " cached names" - << LL_ENDL; + } + return; + } + + LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults); + } + 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,12 +405,17 @@ void LLAvatarNameCache::requestNamesViaCapability() } } - if (!url.empty()) - { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " - << 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_, _1, url, agent_ids)); + LL_DEBUGS("AvNameCache") << coroname << " with url '" << url << "', agent_ids.size()=" << agent_ids.size() << LL_ENDL; + } } @@ -422,11 +479,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(), false); + sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); + sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; + sHttpPriority = 0; } void LLAvatarNameCache::cleanupClass() { - sCache.clear(); + sHttpRequest.reset(); + sHttpHeaders.reset(); + sHttpOptions.reset(); + sCache.clear(); } void LLAvatarNameCache::importFile(std::istream& istr) @@ -498,6 +564,8 @@ void LLAvatarNameCache::idle() // By convention, start running at first idle() call sRunning = true; + sHttpRequest->update(0L); + // *TODO: Possibly re-enabled this based on People API load measurements // 100 ms is the threshold for "user speed" operations, so we can // stall for about that long to batch up requests. @@ -697,6 +765,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; @@ -741,7 +853,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 ea016b3125..17b948f799 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 void importFile(std::istream& istr); void exportFile(std::ostream& ostr); - // On the viewer, usually a simulator capabilitity. + // On the viewer, usually a simulator capabilities. // If empty, name cache will fall back to using legacy name lookup system. void setNameLookupURL(const std::string& name_lookup_url); @@ -90,7 +89,7 @@ namespace LLAvatarNameCache // Compute name expiration time from HTTP Cache-Control header, // or return default value, in seconds from epoch. - F64 nameExpirationFromHeaders(const LLSD& headers); + F64 nameExpirationFromHeaders(const LLSD& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); } diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index ee80b0fd94..30f5f3d3ed 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -30,15 +30,17 @@ #include <sstream> #include "llcorehttputil.h" +#include "llhttpconstants.h" #include "llsdserialize.h" - using namespace LLCore; namespace LLCoreHttpUtil { + + // *TODO: Currently converts only from XML content. A mode // to convert using fromBinary() might be useful as well. Mesh // headers could use it. @@ -88,6 +90,57 @@ HttpHandle requestPostWithLLSD(HttpRequest * request, return handle; } +HttpHandle requestPostWithLLSD(HttpRequest::ptr_t & request, + HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const LLSD & body, + HttpOptions::ptr_t & options, + HttpHeaders::ptr_t & headers, + HttpHandler * handler) +{ + return requestPostWithLLSD(request.get(), policy_id, priority, + url, body, options.get(), headers.get(), handler); +} + +HttpHandle requestPutWithLLSD(HttpRequest * request, + HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const LLSD & body, + HttpOptions * options, + HttpHeaders * headers, + HttpHandler * handler) +{ + HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + + BufferArray * ba = new BufferArray(); + BufferArrayStream bas(ba); + LLSDSerialize::toXML(body, bas); + + handle = request->requestPut(policy_id, + priority, + url, + ba, + options, + headers, + handler); + ba->release(); + return handle; +} + +HttpHandle requestPutWithLLSD(HttpRequest::ptr_t & request, + HttpRequest::policy_t policy_id, + HttpRequest::priority_t priority, + const std::string & url, + const LLSD & body, + HttpOptions::ptr_t & options, + HttpHeaders::ptr_t & headers, + HttpHandler * handler) +{ + return requestPutWithLLSD(request.get(), policy_id, priority, + url, body, options.get(), headers.get(), handler); +} std::string responseToString(LLCore::HttpResponse * response) { @@ -135,5 +188,118 @@ std::string responseToString(LLCore::HttpResponse * response) } +HttpCoroHandler::HttpCoroHandler(LLEventStream &reply) : + mReplyPump(reply) +{ +} + +void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ + LLSD result; + + LLCore::HttpStatus status = response->getStatus(); + + if (!status) + { + result = LLSD::emptyMap(); + LL_WARNS() + << "\n--------------------------------------------------------------------------\n" + << " Error[" << status.toULong() << "] cannot access url '" << response->getRequestURL() + << "' because " << status.toString() + << "\n--------------------------------------------------------------------------" + << LL_ENDL; + + } + else + { + 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(); + } + } + + buildStatusEntry(response, status, result); + mReplyPump.post(result); +} + +void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) +{ + LLSD httpresults = LLSD::emptyMap(); + + httpresults["success"] = static_cast<LLSD::Boolean>(status); + httpresults["type"] = static_cast<LLSD::Integer>(status.getType()); + httpresults["status"] = static_cast<LLSD::Integer>(status.getStatus()); + httpresults["message"] = static_cast<LLSD::String>(status.getMessage()); + httpresults["url"] = static_cast<LLSD::String>(response->getRequestURL()); + + LLSD httpHeaders = LLSD::emptyMap(); + LLCore::HttpHeaders * hdrs = response->getHeaders(); + + if (hdrs) + { + for (LLCore::HttpHeaders::iterator it = hdrs->begin(); it != hdrs->end(); ++it) + { + if (!(*it).second.empty()) + { + httpHeaders[(*it).first] = (*it).second; + } + else + { + httpHeaders[(*it).first] = static_cast<LLSD::Boolean>(true); + } + } + } + + httpresults["headers"] = httpHeaders; + result["http_result"] = httpresults; +} + +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&) +{ + mHttpRequest->update(0L); + return false; +} + + } // end namespace LLCoreHttpUtil diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index d40172bc7a..4ae6e112b3 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -39,6 +39,7 @@ #include "bufferarray.h" #include "bufferstream.h" #include "llsd.h" +#include "llevents.h" /// /// The base llcorehttp library implements many HTTP idioms @@ -109,6 +110,92 @@ LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request, LLCore::HttpHeaders * headers, LLCore::HttpHandler * handler); +LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, + LLCore::HttpRequest::policy_t policy_id, + LLCore::HttpRequest::priority_t priority, + const std::string & url, + const LLSD & body, + LLCore::HttpOptions::ptr_t & options, + LLCore::HttpHeaders::ptr_t & headers, + LLCore::HttpHandler * handler); + +/// Issue a standard HttpRequest::requestPut() call but using +/// and LLSD object as the request body. Conventions are the +/// same as with that method. Caller is expected to provide +/// an HttpHeaders object with a correct 'Content-Type:' header. +/// One will not be provided by this call. +/// +/// @return If request is successfully issued, the +/// HttpHandle representing the request. +/// On error, LLCORE_HTTP_HANDLE_INVALID +/// is returned and caller can fetch detailed +/// status with the getStatus() method on the +/// request object. In case of error, no +/// request is queued and caller may need to +/// perform additional cleanup such as freeing +/// a now-useless HttpHandler object. +/// +LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request, + LLCore::HttpRequest::policy_t policy_id, + LLCore::HttpRequest::priority_t priority, + const std::string & url, + const LLSD & body, + LLCore::HttpOptions * options, + LLCore::HttpHeaders * headers, + LLCore::HttpHandler * handler); + +LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, + LLCore::HttpRequest::policy_t policy_id, + LLCore::HttpRequest::priority_t priority, + const std::string & url, + const LLSD & body, + LLCore::HttpOptions::ptr_t & options, + LLCore::HttpHeaders::ptr_t & headers, + LLCore::HttpHandler * handler); + +/// 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: + HttpCoroHandler(LLEventStream &reply); + + virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + + typedef boost::shared_ptr<HttpCoroHandler> ptr_t; + +private: + void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result); + + LLEventStream &mReplyPump; +}; + +/// 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; +}; + } // end namespace LLCoreHttpUtil diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 73df47b933..ef28a4d211 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -69,13 +69,15 @@ do this. */ +// *TODO: TSN remove the commented code from this file ////////////////////////////////////////////////////////////////////////////// static const U32 EASY_HANDLE_POOL_SIZE = 5; static const S32 MULTI_PERFORM_CALL_REPEAT = 5; static const S32 CURL_REQUEST_TIMEOUT = 120; // seconds per operation static const S32 CURL_CONNECT_TIMEOUT = 30; //seconds to wait for a connection -static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; + +//static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; // DEBUG // S32 gCurlEasyCount = 0; @@ -676,6 +678,7 @@ void LLCurl::Easy::prepRequest(const std::string& url, } //////////////////////////////////////////////////////////////////////////// +#if 1 LLCurl::Multi::Multi(F32 idle_time_out) : mQueued(0), mErrorCount(0), @@ -1056,6 +1059,7 @@ void LLCurl::Multi::removeEasy(Easy* easy) easyFree(easy); } +#endif //------------------------------------------------------------ //LLCurlThread LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) : @@ -1176,428 +1180,428 @@ std::string LLCurl::strerror(CURLcode errorcode) // For generating a simple request for data // using one multi and one easy per request -LLCurlRequest::LLCurlRequest() : - mActiveMulti(NULL), - mActiveRequestCount(0) -{ - mProcessing = FALSE; -} - -LLCurlRequest::~LLCurlRequest() -{ - //stop all Multi handle background threads - for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter) - { - LLCurl::getCurlThread()->killMulti(*iter) ; - } - mMultiSet.clear() ; -} - -void LLCurlRequest::addMulti() -{ - LLCurl::Multi* multi = new LLCurl::Multi(); - if(!multi->isValid()) - { - LLCurl::getCurlThread()->killMulti(multi) ; - mActiveMulti = NULL ; - mActiveRequestCount = 0 ; - return; - } - - mMultiSet.insert(multi); - mActiveMulti = multi; - mActiveRequestCount = 0; -} - -LLCurl::Easy* LLCurlRequest::allocEasy() -{ - if (!mActiveMulti || - mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT || - mActiveMulti->mErrorCount > 0) - { - addMulti(); - } - if(!mActiveMulti) - { - return NULL ; - } - - //llassert_always(mActiveMulti); - ++mActiveRequestCount; - LLCurl::Easy* easy = mActiveMulti->allocEasy(); - return easy; -} - -bool LLCurlRequest::addEasy(LLCurl::Easy* easy) -{ - llassert_always(mActiveMulti); - - if (mProcessing) - { - LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL; - } - bool res = mActiveMulti->addEasy(easy); - return res; -} - -void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder) -{ - getByteRange(url, headers_t(), 0, -1, responder); -} - -// Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or -// the remainder of the file if not. -bool LLCurlRequest::getByteRange(const std::string& url, - const headers_t& headers, - S32 offset, S32 length, - LLCurl::ResponderPtr responder) -{ - llassert(LLCurl::sNotQuitting); - LLCurl::Easy* easy = allocEasy(); - if (!easy) - { - return false; - } - easy->prepRequest(url, headers, responder); - easy->setopt(CURLOPT_HTTPGET, 1); - if (length > 0) - { - std::string range = llformat("bytes=%d-%d", offset,offset+length-1); - easy->slist_append(HTTP_OUT_HEADER_RANGE, range); - } - else if (offset > 0) - { - std::string range = llformat("bytes=%d-", offset); - easy->slist_append(HTTP_OUT_HEADER_RANGE, range); - } - easy->setHeaders(); - bool res = addEasy(easy); - return res; -} - -bool LLCurlRequest::post(const std::string& url, - const headers_t& headers, - const LLSD& data, - LLCurl::ResponderPtr responder, S32 time_out) -{ - llassert(LLCurl::sNotQuitting); - LLCurl::Easy* easy = allocEasy(); - if (!easy) - { - return false; - } - easy->prepRequest(url, headers, responder, time_out); - - LLSDSerialize::toXML(data, easy->getInput()); - S32 bytes = easy->getInput().str().length(); - - easy->setopt(CURLOPT_POST, 1); - easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); - easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - - easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); - easy->setHeaders(); - - LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; - bool res = addEasy(easy); - return res; -} - -bool LLCurlRequest::post(const std::string& url, - const headers_t& headers, - const std::string& data, - LLCurl::ResponderPtr responder, S32 time_out) -{ - llassert(LLCurl::sNotQuitting); - LLCurl::Easy* easy = allocEasy(); - if (!easy) - { - return false; - } - easy->prepRequest(url, headers, responder, time_out); - - easy->getInput().write(data.data(), data.size()); - S32 bytes = easy->getInput().str().length(); - - easy->setopt(CURLOPT_POST, 1); - easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); - easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - - easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); - easy->setHeaders(); - - LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; - bool res = addEasy(easy); - return res; -} - -// Note: call once per frame -S32 LLCurlRequest::process() -{ - S32 res = 0; - - mProcessing = TRUE; - for (curlmulti_set_t::iterator iter = mMultiSet.begin(); - iter != mMultiSet.end(); ) - { - curlmulti_set_t::iterator curiter = iter++; - LLCurl::Multi* multi = *curiter; - - if(!multi->isValid()) - { - if(multi == mActiveMulti) - { - mActiveMulti = NULL ; - mActiveRequestCount = 0 ; - } - mMultiSet.erase(curiter) ; - LLCurl::getCurlThread()->killMulti(multi) ; - continue ; - } - - S32 tres = multi->process(); - res += tres; - if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0) - { - mMultiSet.erase(curiter); - LLCurl::getCurlThread()->killMulti(multi); - } - } - mProcessing = FALSE; - return res; -} - -S32 LLCurlRequest::getQueued() -{ - S32 queued = 0; - for (curlmulti_set_t::iterator iter = mMultiSet.begin(); - iter != mMultiSet.end(); ) - { - curlmulti_set_t::iterator curiter = iter++; - LLCurl::Multi* multi = *curiter; - - if(!multi->isValid()) - { - if(multi == mActiveMulti) - { - mActiveMulti = NULL ; - mActiveRequestCount = 0 ; - } - LLCurl::getCurlThread()->killMulti(multi); - mMultiSet.erase(curiter) ; - continue ; - } - - queued += multi->mQueued; - if (multi->getState() != LLCurl::Multi::STATE_READY) - { - ++queued; - } - } - return queued; -} - -LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) : - LLCurlRequest(), - mConcurrency(concurrency), - mInQueue(0), - mMutex(NULL), - mHandleCounter(1), - mTotalIssuedRequests(0), - mTotalReceivedBits(0) -{ - mGlobalTimer.reset(); -} - -LLCurlTextureRequest::~LLCurlTextureRequest() -{ - mRequestMap.clear(); - - for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter) - { - delete *iter; - } - mCachedRequests.clear(); -} - -//return 0: success -// > 0: cached handle -U32 LLCurlTextureRequest::getByteRange(const std::string& url, - const headers_t& headers, - S32 offset, S32 length, U32 pri, - LLCurl::ResponderPtr responder, F32 delay_time) -{ - U32 ret_val = 0; - bool success = false; - - if(mInQueue < mConcurrency && delay_time < 0.f) - { - success = LLCurlRequest::getByteRange(url, headers, offset, length, responder); - } - - LLMutexLock lock(&mMutex); - - if(success) - { - mInQueue++; - mTotalIssuedRequests++; - } - else - { - request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder); - if(delay_time > 0.f) - { - request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time; - } - - mCachedRequests.insert(request); - mRequestMap[mHandleCounter] = request; - ret_val = mHandleCounter; - mHandleCounter++; - - if(!mHandleCounter) - { - mHandleCounter = 1; - } - } - - return ret_val; -} - -void LLCurlTextureRequest::completeRequest(S32 received_bytes) -{ - LLMutexLock lock(&mMutex); - - llassert_always(mInQueue > 0); - - mInQueue--; - mTotalReceivedBits += received_bytes * 8; -} - -void LLCurlTextureRequest::nextRequests() -{ - if(mCachedRequests.empty() || mInQueue >= mConcurrency) - { - return; - } - - F32 cur_time = mGlobalTimer.getElapsedTimeF32(); - - req_queue_t::iterator iter; - { - LLMutexLock lock(&mMutex); - iter = mCachedRequests.begin(); - } - while(1) - { - request_t* request = *iter; - if(request->mStartTime < cur_time) - { - if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder)) - { - break; - } - - LLMutexLock lock(&mMutex); - ++iter; - mInQueue++; - mTotalIssuedRequests++; - mCachedRequests.erase(request); - mRequestMap.erase(request->mHandle); - delete request; - - if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) - { - break; - } - } - else - { - LLMutexLock lock(&mMutex); - ++iter; - if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) - { - break; - } - } - } - - return; -} - -void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri) -{ - if(!handle) - { - return; - } - - LLMutexLock lock(&mMutex); - - std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); - if(iter != mRequestMap.end()) - { - request_t* req = iter->second; - - if(req->mPriority != pri) - { - mCachedRequests.erase(req); - req->mPriority = pri; - mCachedRequests.insert(req); - } - } -} - -void LLCurlTextureRequest::removeRequest(U32 handle) -{ - if(!handle) - { - return; - } - - LLMutexLock lock(&mMutex); - - std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); - if(iter != mRequestMap.end()) - { - request_t* req = iter->second; - mRequestMap.erase(iter); - mCachedRequests.erase(req); - delete req; - } -} - -bool LLCurlTextureRequest::isWaiting(U32 handle) -{ - if(!handle) - { - return false; - } - - LLMutexLock lock(&mMutex); - return mRequestMap.find(handle) != mRequestMap.end(); -} - -U32 LLCurlTextureRequest::getTotalReceivedBits() -{ - LLMutexLock lock(&mMutex); - - U32 bits = mTotalReceivedBits; - mTotalReceivedBits = 0; - return bits; -} - -U32 LLCurlTextureRequest::getTotalIssuedRequests() -{ - LLMutexLock lock(&mMutex); - return mTotalIssuedRequests; -} - -S32 LLCurlTextureRequest::getNumRequests() -{ - LLMutexLock lock(&mMutex); - return mInQueue; -} +// LLCurlRequest::LLCurlRequest() : +// mActiveMulti(NULL), +// mActiveRequestCount(0) +// { +// mProcessing = FALSE; +// } +// +// LLCurlRequest::~LLCurlRequest() +// { +// //stop all Multi handle background threads +// for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter) +// { +// LLCurl::getCurlThread()->killMulti(*iter) ; +// } +// mMultiSet.clear() ; +// } +// +// void LLCurlRequest::addMulti() +// { +// LLCurl::Multi* multi = new LLCurl::Multi(); +// if(!multi->isValid()) +// { +// LLCurl::getCurlThread()->killMulti(multi) ; +// mActiveMulti = NULL ; +// mActiveRequestCount = 0 ; +// return; +// } +// +// mMultiSet.insert(multi); +// mActiveMulti = multi; +// mActiveRequestCount = 0; +// } +// +// LLCurl::Easy* LLCurlRequest::allocEasy() +// { +// if (!mActiveMulti || +// mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT || +// mActiveMulti->mErrorCount > 0) +// { +// addMulti(); +// } +// if(!mActiveMulti) +// { +// return NULL ; +// } +// +// //llassert_always(mActiveMulti); +// ++mActiveRequestCount; +// LLCurl::Easy* easy = mActiveMulti->allocEasy(); +// return easy; +// } +// +// bool LLCurlRequest::addEasy(LLCurl::Easy* easy) +// { +// llassert_always(mActiveMulti); +// +// if (mProcessing) +// { +// LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL; +// } +// bool res = mActiveMulti->addEasy(easy); +// return res; +// } +// +// void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder) +// { +// getByteRange(url, headers_t(), 0, -1, responder); +// } +// +// // Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or +// // the remainder of the file if not. +// bool LLCurlRequest::getByteRange(const std::string& url, +// const headers_t& headers, +// S32 offset, S32 length, +// LLCurl::ResponderPtr responder) +// { +// llassert(LLCurl::sNotQuitting); +// LLCurl::Easy* easy = allocEasy(); +// if (!easy) +// { +// return false; +// } +// easy->prepRequest(url, headers, responder); +// easy->setopt(CURLOPT_HTTPGET, 1); +// if (length > 0) +// { +// std::string range = llformat("bytes=%d-%d", offset,offset+length-1); +// easy->slist_append(HTTP_OUT_HEADER_RANGE, range); +// } +// else if (offset > 0) +// { +// std::string range = llformat("bytes=%d-", offset); +// easy->slist_append(HTTP_OUT_HEADER_RANGE, range); +// } +// easy->setHeaders(); +// bool res = addEasy(easy); +// return res; +// } +// +// bool LLCurlRequest::post(const std::string& url, +// const headers_t& headers, +// const LLSD& data, +// LLCurl::ResponderPtr responder, S32 time_out) +// { +// llassert(LLCurl::sNotQuitting); +// LLCurl::Easy* easy = allocEasy(); +// if (!easy) +// { +// return false; +// } +// easy->prepRequest(url, headers, responder, time_out); +// +// LLSDSerialize::toXML(data, easy->getInput()); +// S32 bytes = easy->getInput().str().length(); +// +// easy->setopt(CURLOPT_POST, 1); +// easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); +// easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); +// +// easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); +// easy->setHeaders(); +// +// LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; +// bool res = addEasy(easy); +// return res; +// } +// +// bool LLCurlRequest::post(const std::string& url, +// const headers_t& headers, +// const std::string& data, +// LLCurl::ResponderPtr responder, S32 time_out) +// { +// llassert(LLCurl::sNotQuitting); +// LLCurl::Easy* easy = allocEasy(); +// if (!easy) +// { +// return false; +// } +// easy->prepRequest(url, headers, responder, time_out); +// +// easy->getInput().write(data.data(), data.size()); +// S32 bytes = easy->getInput().str().length(); +// +// easy->setopt(CURLOPT_POST, 1); +// easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); +// easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); +// +// easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); +// easy->setHeaders(); +// +// LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; +// bool res = addEasy(easy); +// return res; +// } +// +// // Note: call once per frame +// S32 LLCurlRequest::process() +// { +// S32 res = 0; +// +// mProcessing = TRUE; +// for (curlmulti_set_t::iterator iter = mMultiSet.begin(); +// iter != mMultiSet.end(); ) +// { +// curlmulti_set_t::iterator curiter = iter++; +// LLCurl::Multi* multi = *curiter; +// +// if(!multi->isValid()) +// { +// if(multi == mActiveMulti) +// { +// mActiveMulti = NULL ; +// mActiveRequestCount = 0 ; +// } +// mMultiSet.erase(curiter) ; +// LLCurl::getCurlThread()->killMulti(multi) ; +// continue ; +// } +// +// S32 tres = multi->process(); +// res += tres; +// if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0) +// { +// mMultiSet.erase(curiter); +// LLCurl::getCurlThread()->killMulti(multi); +// } +// } +// mProcessing = FALSE; +// return res; +// } +// +// S32 LLCurlRequest::getQueued() +// { +// S32 queued = 0; +// for (curlmulti_set_t::iterator iter = mMultiSet.begin(); +// iter != mMultiSet.end(); ) +// { +// curlmulti_set_t::iterator curiter = iter++; +// LLCurl::Multi* multi = *curiter; +// +// if(!multi->isValid()) +// { +// if(multi == mActiveMulti) +// { +// mActiveMulti = NULL ; +// mActiveRequestCount = 0 ; +// } +// LLCurl::getCurlThread()->killMulti(multi); +// mMultiSet.erase(curiter) ; +// continue ; +// } +// +// queued += multi->mQueued; +// if (multi->getState() != LLCurl::Multi::STATE_READY) +// { +// ++queued; +// } +// } +// return queued; +// } + +// LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) : +// LLCurlRequest(), +// mConcurrency(concurrency), +// mInQueue(0), +// mMutex(NULL), +// mHandleCounter(1), +// mTotalIssuedRequests(0), +// mTotalReceivedBits(0) +// { +// mGlobalTimer.reset(); +// } +// +// LLCurlTextureRequest::~LLCurlTextureRequest() +// { +// mRequestMap.clear(); +// +// for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter) +// { +// delete *iter; +// } +// mCachedRequests.clear(); +// } +// +// //return 0: success +// // > 0: cached handle +// U32 LLCurlTextureRequest::getByteRange(const std::string& url, +// const headers_t& headers, +// S32 offset, S32 length, U32 pri, +// LLCurl::ResponderPtr responder, F32 delay_time) +// { +// U32 ret_val = 0; +// bool success = false; +// +// if(mInQueue < mConcurrency && delay_time < 0.f) +// { +// success = LLCurlRequest::getByteRange(url, headers, offset, length, responder); +// } +// +// LLMutexLock lock(&mMutex); +// +// if(success) +// { +// mInQueue++; +// mTotalIssuedRequests++; +// } +// else +// { +// request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder); +// if(delay_time > 0.f) +// { +// request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time; +// } +// +// mCachedRequests.insert(request); +// mRequestMap[mHandleCounter] = request; +// ret_val = mHandleCounter; +// mHandleCounter++; +// +// if(!mHandleCounter) +// { +// mHandleCounter = 1; +// } +// } +// +// return ret_val; +// } +// +// void LLCurlTextureRequest::completeRequest(S32 received_bytes) +// { +// LLMutexLock lock(&mMutex); +// +// llassert_always(mInQueue > 0); +// +// mInQueue--; +// mTotalReceivedBits += received_bytes * 8; +// } +// +// void LLCurlTextureRequest::nextRequests() +// { +// if(mCachedRequests.empty() || mInQueue >= mConcurrency) +// { +// return; +// } +// +// F32 cur_time = mGlobalTimer.getElapsedTimeF32(); +// +// req_queue_t::iterator iter; +// { +// LLMutexLock lock(&mMutex); +// iter = mCachedRequests.begin(); +// } +// while(1) +// { +// request_t* request = *iter; +// if(request->mStartTime < cur_time) +// { +// if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder)) +// { +// break; +// } +// +// LLMutexLock lock(&mMutex); +// ++iter; +// mInQueue++; +// mTotalIssuedRequests++; +// mCachedRequests.erase(request); +// mRequestMap.erase(request->mHandle); +// delete request; +// +// if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) +// { +// break; +// } +// } +// else +// { +// LLMutexLock lock(&mMutex); +// ++iter; +// if(iter == mCachedRequests.end() || mInQueue >= mConcurrency) +// { +// break; +// } +// } +// } +// +// return; +// } +// +// void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri) +// { +// if(!handle) +// { +// return; +// } +// +// LLMutexLock lock(&mMutex); +// +// std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); +// if(iter != mRequestMap.end()) +// { +// request_t* req = iter->second; +// +// if(req->mPriority != pri) +// { +// mCachedRequests.erase(req); +// req->mPriority = pri; +// mCachedRequests.insert(req); +// } +// } +// } +// +// void LLCurlTextureRequest::removeRequest(U32 handle) +// { +// if(!handle) +// { +// return; +// } +// +// LLMutexLock lock(&mMutex); +// +// std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle); +// if(iter != mRequestMap.end()) +// { +// request_t* req = iter->second; +// mRequestMap.erase(iter); +// mCachedRequests.erase(req); +// delete req; +// } +// } +// +// bool LLCurlTextureRequest::isWaiting(U32 handle) +// { +// if(!handle) +// { +// return false; +// } +// +// LLMutexLock lock(&mMutex); +// return mRequestMap.find(handle) != mRequestMap.end(); +// } +// +// U32 LLCurlTextureRequest::getTotalReceivedBits() +// { +// LLMutexLock lock(&mMutex); +// +// U32 bits = mTotalReceivedBits; +// mTotalReceivedBits = 0; +// return bits; +// } +// +// U32 LLCurlTextureRequest::getTotalIssuedRequests() +// { +// LLMutexLock lock(&mMutex); +// return mTotalIssuedRequests; +// } +// +// S32 LLCurlTextureRequest::getNumRequests() +// { +// LLMutexLock lock(&mMutex); +// return mInQueue; +// } //////////////////////////////////////////////////////////////////////////// // For generating one easy request @@ -1988,10 +1992,10 @@ void LLCurlFF::check_easy_code(CURLcode code) { check_curl_code(code); } -void LLCurlFF::check_multi_code(CURLMcode code) -{ - check_curl_multi_code(code); -} +// void LLCurlFF::check_multi_code(CURLMcode code) +// { +// check_curl_multi_code(code); +// } // Static diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 385d9fffa8..06b3ce45e1 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -418,100 +418,6 @@ private: } ; -class LLCurlRequest -{ -public: - typedef std::vector<std::string> headers_t; - - LLCurlRequest(); - ~LLCurlRequest(); - - void get(const std::string& url, LLCurl::ResponderPtr responder); - bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder); - bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0); - bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0); - - S32 process(); - S32 getQueued(); - -private: - void addMulti(); - LLCurl::Easy* allocEasy(); - bool addEasy(LLCurl::Easy* easy); - -private: - typedef std::set<LLCurl::Multi*> curlmulti_set_t; - curlmulti_set_t mMultiSet; - LLCurl::Multi* mActiveMulti; - S32 mActiveRequestCount; - BOOL mProcessing; -}; - -//for texture fetch only -class LLCurlTextureRequest : public LLCurlRequest -{ -public: - LLCurlTextureRequest(S32 concurrency); - ~LLCurlTextureRequest(); - - U32 getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder, F32 delay_time = -1.f); - void nextRequests(); - void completeRequest(S32 received_bytes); - - void updatePriority(U32 handle, U32 pri); - void removeRequest(U32 handle); - - U32 getTotalReceivedBits(); - U32 getTotalIssuedRequests(); - S32 getNumRequests(); - bool isWaiting(U32 handle); - -private: - LLMutex mMutex; - S32 mConcurrency; - S32 mInQueue; //request currently in queue. - U32 mHandleCounter; - U32 mTotalIssuedRequests; - U32 mTotalReceivedBits; - - typedef struct _request_t - { - _request_t(U32 handle, const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder) : - mHandle(handle), mUrl(url), mHeaders(headers), mOffset(offset), mLength(length), mPriority(pri), mResponder(responder), mStartTime(0.f) - {} - - U32 mHandle; - std::string mUrl; - LLCurlRequest::headers_t mHeaders; - S32 mOffset; - S32 mLength; - LLCurl::ResponderPtr mResponder; - U32 mPriority; - F32 mStartTime; //start time to issue this request - } request_t; - - struct request_compare - { - bool operator()(const request_t* lhs, const request_t* rhs) const - { - if(lhs->mPriority != rhs->mPriority) - { - return lhs->mPriority > rhs->mPriority; // higher priority in front of queue (set) - } - else - { - return (U32)lhs < (U32)rhs; - } - } - }; - - typedef std::set<request_t*, request_compare> req_queue_t; - req_queue_t mCachedRequests; - std::map<S32, request_t*> mRequestMap; - - LLFrameTimer mGlobalTimer; -}; - class LLCurlEasyRequest { public: @@ -550,7 +456,7 @@ private: namespace LLCurlFF { void check_easy_code(CURLcode code); - void check_multi_code(CURLMcode code); + //void check_multi_code(CURLMcode code); } #endif // LL_LLCURL_H diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 200116337d..b4a76cb808 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 index b56a804f94..8c2a0ad9cf 100755 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -26,48 +26,48 @@ #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); -} +// +// 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 index 270282c66f..0067703895 100755 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -30,6 +30,7 @@ #include "llhttpclientinterface.h" #include "llsingleton.h" // LLSingleton<> +/* class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLHTTPClientAdapter> { public: @@ -46,6 +47,7 @@ public: 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..159d03b176 --- /dev/null +++ b/indra/llmessage/llhttpsdhandler.cpp @@ -0,0 +1,103 @@ +/** +* @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() +{ +} + +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. + delete this; +} + +//======================================================================== +LLHttpSDGenericHandler::LLHttpSDGenericHandler(const std::string &caps) : + LLHttpSDHandler(), + mCaps(caps) +{ +} + +void LLHttpSDGenericHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) +{ + LL_DEBUGS() << mCaps << " Success." << LL_ENDL; +} + +void LLHttpSDGenericHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) +{ + LL_WARNS() + << "\n--------------------------------------------------------------------------\n" + << mCaps << " 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..7c28dbcab6 --- /dev/null +++ b/indra/llmessage/llhttpsdhandler.h @@ -0,0 +1,67 @@ +/** +* @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: + LLHttpSDHandler(); + + virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +protected: + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0; + virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0; + +}; + +/// A trivial implementation of LLHttpSDHandler. This success and failure +/// methods log the action taken, the URI accessed and the status code retuned +/// in the response. +class LLHttpSDGenericHandler : public LLHttpSDHandler +{ +public: + LLHttpSDGenericHandler(const std::string &action); + +protected: + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); + virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + +private: + std::string mCaps; +}; +#endif
\ No newline at end of file diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index c4e0333ca3..d097ecdff7 100755 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -37,7 +37,9 @@ #include "llchainio.h" #include "llfiltersd2xmlrpc.h" #include "lliopipe.h" -#include "llurlrequest.h" +#if 0 +//#include "llurlrequest.h" +#endif /** * @class LLSDRPCClientResponse @@ -218,6 +220,7 @@ protected: LLIOPipe::ptr_t mResponse; }; +#if 0 /** * @class LLSDRPCClientFactory * @brief Basic implementation for making an SD RPC client factory @@ -267,7 +270,9 @@ public: protected: std::string mURL; }; +#endif +#if 0 /** * @class LLXMLSDRPCClientFactory * @brief Basic implementation for making an XMLRPC to SD RPC client factory @@ -319,5 +324,6 @@ public: protected: std::string mURL; }; +#endif #endif // LL_LLSDRPCCLIENT_H diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp index e9ce116bb3..e0a82e237b 100755 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -23,7 +23,7 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - +#if 0 #include "llhttpclientadapter.h" #include "../test/lltut.h" @@ -219,3 +219,4 @@ namespace tut } } +#endif
\ No newline at end of file |