From f945415210f0e18c2c6d941fda6b7d45cb0f06f1 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Wed, 13 Mar 2013 06:26:25 +0000 Subject: Large changes to the LLCurl::Responder API, as well as pulling in some changes to common libraries from the server codebase: * Additional error checking in http handlers. * Uniform log spam for http errors. * Switch to using constants for http heads and status codes. * Fixed bugs in incorrectly checking if parsing LLSD xml resulted in an error. * Reduced spam regarding LLSD parsing errors in the default completedRaw http handler. It should not longer be necessary to short-circuit completedRaw to avoid spam. * Ported over a few bug fixes from the server code. * Switch mode http status codes to use S32 instead of U32. * Ported LLSD::asStringRef from server code; avoids copying strings all over the place. * Ported server change to LLSD::asBinary; this always returns a reference now instead of copying the entire binary blob. * Ported server pretty notation format (and pretty binary format) to llsd serialization. * The new LLCurl::Responder API no longer has two error handlers to choose from. Overriding the following methods have been deprecated: ** error - use httpFailure ** errorWithContent - use httpFailure ** result - use httpSuccess ** completed - use httpCompleted ** completedHeader - no longer necessary; call getResponseHeaders() from a completion method to obtain these headers. * In order to 'catch' a completed http request, override one of these methods: ** httpSuccess - Called for any 2xx status code. ** httpFailure - Called for any non-2xx status code. ** httpComplete - Called for all status codes. Default implementation is to call either httpSuccess or httpFailure. * It is recommended to keep these methods protected/private in order to avoid triggering of these methods without using a 'push' method (see below). * Uniform error handling should followed whenever possible by calling a variant of this during httpFailure: ** llwarns << dumpResponse() << llendl; * Be sure to include LOG_CLASS(your_class_name) in your class in order for the log entry to give more context. * In order to 'push' a result into the responder, you should no longer call error, errorWithContent, result, or completed. * Nor should you directly call httpSuccess/Failure/Completed (unless passing a message up to a parent class). * Instead, you can set the internal content of a responder and trigger a corresponding method using the following methods: ** successResult - Sets results and calls httpSuccess ** failureResult - Sets results and calls httpFailure ** completedResult - Sets results and calls httpCompleted * To obtain information about a the response from a reponder method, use the following getters: ** getStatus - HTTP status code ** getReason - Reason string ** getContent - Content (Parsed body LLSD) ** getResponseHeaders - Response Headers (LLSD map) ** getHTTPMethod - HTTP method of the request ** getURL - URL of the request * It is still possible to override completeRaw if you want to manipulate data directly out of LLPumpIO. * See indra/llmessage/llcurl.h for more information. --- indra/llmessage/CMakeLists.txt | 10 +- indra/llmessage/llavatarnamecache.cpp | 53 ++--- indra/llmessage/llavatarnamecache.h | 2 +- indra/llmessage/llcurl.cpp | 225 ++++++++++++++++----- indra/llmessage/llcurl.h | 112 ++++++---- indra/llmessage/llhttpassetstorage.cpp | 21 +- indra/llmessage/llhttpclient.cpp | 137 +++++++------ indra/llmessage/llhttpclientadapter.cpp | 26 ++- indra/llmessage/llhttpclientadapter.h | 8 + indra/llmessage/llhttpconstants.cpp | 219 ++++++++++++++++++++ indra/llmessage/llhttpconstants.h | 220 ++++++++++++++++++++ indra/llmessage/llhttpnode.cpp | 22 +- indra/llmessage/llhttpnode.h | 11 +- indra/llmessage/lliohttpserver.cpp | 68 +++++-- indra/llmessage/lliohttpserver.h | 5 - indra/llmessage/llmime.cpp | 39 ++-- indra/llmessage/llregionpresenceverifier.cpp | 153 -------------- indra/llmessage/llregionpresenceverifier.h | 98 --------- indra/llmessage/llsdmessage.cpp | 21 +- indra/llmessage/llsdmessage.h | 6 +- indra/llmessage/llsdrpcclient.h | 8 +- indra/llmessage/lltrustedmessageservice.cpp | 2 +- indra/llmessage/llurlrequest.cpp | 43 ++-- indra/llmessage/llurlrequest.h | 42 +--- indra/llmessage/message.cpp | 12 +- indra/llmessage/tests/llcurl_stub.cpp | 59 ++++-- indra/llmessage/tests/llhttpclient_test.cpp | 31 ++- indra/llmessage/tests/llhttpclientadapter_test.cpp | 81 ++++++-- indra/llmessage/tests/llmime_test.cpp | 1 + .../tests/llregionpresenceverifier_test.cpp | 108 ---------- 30 files changed, 1093 insertions(+), 750 deletions(-) create mode 100644 indra/llmessage/llhttpconstants.cpp create mode 100644 indra/llmessage/llhttpconstants.h delete mode 100644 indra/llmessage/llregionpresenceverifier.cpp delete mode 100644 indra/llmessage/llregionpresenceverifier.h delete mode 100644 indra/llmessage/tests/llregionpresenceverifier_test.cpp (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 1a90c32fe4..181718f465 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -43,6 +43,7 @@ set(llmessage_SOURCE_FILES llhttpassetstorage.cpp llhttpclient.cpp llhttpclientadapter.cpp + llhttpconstants.cpp llhttpnode.cpp llhttpsender.cpp llinstantmessage.cpp @@ -67,7 +68,6 @@ set(llmessage_SOURCE_FILES llpartdata.cpp llproxy.cpp llpumpio.cpp - llregionpresenceverifier.cpp llsdappservices.cpp llsdhttpserver.cpp llsdmessage.cpp @@ -135,6 +135,7 @@ set(llmessage_HEADER_FILES llhttpclient.h llhttpclientinterface.h llhttpclientadapter.h + llhttpconstants.h llhttpnode.h llhttpnodeadapter.h llhttpsender.h @@ -166,7 +167,6 @@ set(llmessage_HEADER_FILES llqueryflags.h llregionflags.h llregionhandle.h - llregionpresenceverifier.h llsdappservices.h llsdhttpserver.h llsdmessage.h @@ -230,17 +230,15 @@ target_link_libraries( # tests if (LL_TESTS) SET(llmessage_TEST_SOURCE_FILES - # llhttpclientadapter.cpp - llmime.cpp llnamevalue.cpp lltrustedmessageservice.cpp lltemplatemessagedispatcher.cpp - llregionpresenceverifier.cpp ) 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} @@ -267,6 +265,8 @@ if (LL_TESTS) 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(llmime "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index f9e3ad26f7..87c4b5952c 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -126,7 +126,7 @@ namespace LLAvatarNameCache // Erase expired names from cache void eraseUnrefreshed(); - bool expirationFromCacheControl(LLSD headers, F64 *expires); + bool expirationFromCacheControl(const LLSD& headers, F64 *expires); } /* Sample response: @@ -170,33 +170,31 @@ namespace LLAvatarNameCache class LLAvatarNameResponder : public LLHTTPClient::Responder { + 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 mAgentIDs; - // Need the headers to look up Expires: and Retry-After: - LLSD mHeaders; - public: LLAvatarNameResponder(const std::vector& agent_ids) - : mAgentIDs(agent_ids), - mHeaders() + : mAgentIDs(agent_ids) { } - /*virtual*/ void completedHeader(U32 status, const std::string& reason, - const LLSD& headers) - { - mHeaders = headers; - } - - /*virtual*/ void result(const LLSD& content) +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(mHeaders); + F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders()); F64 now = LLFrameTimer::getTotalSeconds(); - LLSD agents = content["agents"]; + const LLSD& agents = content["agents"]; LLSD::array_const_iterator it = agents.beginArray(); for ( ; it != agents.endArray(); ++it) { @@ -226,7 +224,7 @@ public: } // Same logic as error response case - LLSD unresolved_agents = content["bad_ids"]; + const LLSD& unresolved_agents = content["bad_ids"]; S32 num_unresolved = unresolved_agents.size(); if (num_unresolved > 0) { @@ -250,14 +248,13 @@ public: << LL_ENDL; } - /*virtual*/ void error(U32 status, const std::string& reason) + /*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") << "LLAvatarNameResponder::error " << status << " " << reason - << LL_ENDL; + 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::const_iterator it = mAgentIDs.begin(); @@ -748,7 +745,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na sCache[agent_id] = av_name; } -F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) +F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers) { F64 expires = 0.0; if (expirationFromCacheControl(headers, &expires)) @@ -764,17 +761,25 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) } } -bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) +bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *expires) { bool fromCacheControl = false; F64 now = LLFrameTimer::getTotalSeconds(); // Allow the header to override the default - LLSD cache_control_header = headers["cache-control"]; - if (cache_control_header.isDefined()) + std::string cache_control; + if (headers.has(HTTP_HEADER_CACHE_CONTROL)) + { + cache_control = headers[HTTP_HEADER_CACHE_CONTROL].asString(); + } + else if (headers.has(HTTP_HEADER_LOWER_CACHE_CONTROL)) + { + cache_control = headers[HTTP_HEADER_LOWER_CACHE_CONTROL].asString(); + } + + if (!cache_control.empty()) { S32 max_age = 0; - std::string cache_control = cache_control_header.asString(); if (max_age_from_cache_control(cache_control, &max_age)) { *expires = now + (F64)max_age; diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 79f170f7c8..42c76fe058 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -90,7 +90,7 @@ namespace LLAvatarNameCache // Compute name expiration time from HTTP Cache-Control header, // or return default value, in seconds from epoch. - F64 nameExpirationFromHeaders(LLSD headers); + F64 nameExpirationFromHeaders(const LLSD& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); } diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 47041a2880..1269b6bc5d 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -49,6 +49,7 @@ #include "llproxy.h" #include "llsdserialize.h" #include "llstl.h" +#include "llstring.h" #include "llthread.h" #include "lltimer.h" @@ -98,7 +99,7 @@ void check_curl_code(CURLcode code) { // linux appears to throw a curl error once per session for a bad initialization // at a pretty random time (when enabling cookies). - llinfos << "curl error detected: " << curl_easy_strerror(code) << llendl; + LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL; } } @@ -108,7 +109,7 @@ void check_curl_multi_code(CURLMcode code) { // linux appears to throw a curl error once per session for a bad initialization // at a pretty random time (when enabling cookies). - llinfos << "curl multi error detected: " << curl_multi_strerror(code) << llendl; + LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL; } } @@ -133,6 +134,7 @@ std::string LLCurl::getVersionString() ////////////////////////////////////////////////////////////////////////////// LLCurl::Responder::Responder() + : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR) { } @@ -142,22 +144,30 @@ LLCurl::Responder::~Responder() } // virtual -void LLCurl::Responder::errorWithContent( - U32 status, - const std::string& reason, - const LLSD&) +void LLCurl::Responder::httpFailure() { - error(status, reason); + LL_WARNS("curl") << dumpResponse() << LL_ENDL; } -// virtual -void LLCurl::Responder::error(U32 status, const std::string& reason) +std::string LLCurl::Responder::dumpResponse() const { - llinfos << mURL << " [" << status << "]: " << reason << llendl; + std::ostringstream s; + s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] " + << "[status:" << mStatus << "] " + << "[reason:" << mReason << "] "; + + if (mResponseHeaders.has(HTTP_HEADER_CONTENT_TYPE)) + { + s << "[content-type:" << mResponseHeaders[HTTP_HEADER_CONTENT_TYPE] << "] "; + } + + s << "[content:" << mContent << "]"; + + return s.str(); } // virtual -void LLCurl::Responder::result(const LLSD& content) +void LLCurl::Responder::httpSuccess() { } @@ -166,44 +176,124 @@ void LLCurl::Responder::setURL(const std::string& url) mURL = url; } +void LLCurl::Responder::successResult(const LLSD& content) +{ + setResult(HTTP_OK, "", content); + httpSuccess(); +} + +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ + setResult(status, reason, content); + httpFailure(); +} + +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ + setResult(status, reason, content); + httpCompleted(); +} + +void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ + mStatus = status; + mReason = reason; + mContent = content; +} + +void LLCurl::Responder::setHTTPMethod(EHTTPMethod method) +{ + mHTTPMethod = method; +} + +void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value) +{ + mResponseHeaders[header] = value; +} + +const std::string& LLCurl::Responder::getResponseHeader(const std::string& header, bool check_lower) const +{ + if (mResponseHeaders.has(header)) + { + return mResponseHeaders[header].asStringRef(); + } + if (check_lower) + { + std::string header_lower(header); + LLStringUtil::toLower(header_lower); + if (mResponseHeaders.has(header_lower)) + { + return mResponseHeaders[header_lower].asStringRef(); + } + } + static const std::string empty; + return empty; +} + +bool LLCurl::Responder::hasResponseHeader(const std::string& header, bool check_lower) const +{ + if (mResponseHeaders.has(header)) return true; + if (check_lower) + { + std::string header_lower(header); + LLStringUtil::toLower(header_lower); + return mResponseHeaders.has(header_lower); + } + return false; +} + // virtual void LLCurl::Responder::completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - LLSD content; LLBufferStream istr(channels, buffer.get()); - const bool emit_errors = false; - if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(content, istr, emit_errors)) + const bool emit_parse_errors = false; + + std::string debug_body("(empty)"); + bool parsed=true; + if (EOF == istr.peek()) + { + parsed=false; + } + // Try to parse body as llsd, no matter what 'Content-Type' says. + else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors)) + { + parsed=false; + char body[1025]; + body[1024] = '\0'; + istr.seekg(0, std::ios::beg); + istr.get(body,1024); + if (strlen(body) > 0) + { + mContent = body; + debug_body = body; + } + } + + // Only emit an warning if we failed to parse when 'Content-Type' == 'application/llsd+xml' + if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_HEADER_CONTENT_TYPE))) { - llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; - content["reason"] = reason; + llwarns << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] " + << "(" << mReason << ") body: " << debug_body << llendl; } - completed(status, reason, content); + httpCompleted(); } // virtual -void LLCurl::Responder::completed(U32 status, const std::string& reason, const LLSD& content) +void LLCurl::Responder::httpCompleted() { - if (isGoodStatus(status)) + if (isGoodStatus()) { - result(content); + httpSuccess(); } else { - errorWithContent(status, reason, content); + httpFailure(); } } -//virtual -void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, const LLSD& content) -{ - -} - ////////////////////////////////////////////////////////////////////////////// std::set LLCurl::Easy::sFreeHandles; @@ -287,7 +377,8 @@ LLCurl::Easy* LLCurl::Easy::getEasy() if (!easy->mCurlEasyHandle) { // this can happen if we have too many open files (fails in c-ares/ares_init.c) - llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl; + LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: " + << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; delete easy; return NULL; } @@ -312,10 +403,14 @@ LLCurl::Easy::~Easy() for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); LL_CHECK_MEMORY if (mResponder && LLCurl::sNotQuitting) //aborted - { - std::string reason("Request timeout, aborted.") ; - mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort - reason, mChannels, mOutput); + { + // HTTP_REQUEST_TIME_OUT, timeout, abort + // *TODO: This looks like improper use of the 408 status code. + // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9 + // This status code should be returned by the *server* when: + // "The client did not produce a request within the time that the server was prepared to wait." + mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted."); + mResponder->completedRaw(mChannels, mOutput); LL_CHECK_MEMORY } mResponder = NULL; @@ -379,9 +474,9 @@ void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info) check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload)); } -U32 LLCurl::Easy::report(CURLcode code) +S32 LLCurl::Easy::report(CURLcode code) { - U32 responseCode = 0; + S32 responseCode = 0; std::string responseReason; if (code == CURLE_OK) @@ -391,14 +486,15 @@ U32 LLCurl::Easy::report(CURLcode code) } else { - responseCode = 499; + responseCode = HTTP_INTERNAL_ERROR; responseReason = strerror(code) + " : " + mErrorBuffer; setopt(CURLOPT_FRESH_CONNECT, TRUE); } if (mResponder) { - mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput); + mResponder->setResult(responseCode, responseReason); + mResponder->completedRaw(mChannels, mOutput); mResponder = NULL; } @@ -435,9 +531,31 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value) check_curl_code(result); } +void LLCurl::Easy::slist_append(const std::string& header, const std::string& value) +{ + std::string pair(header); + if (value.empty()) + { + pair += ":"; + } + else + { + pair += ": "; + pair += value; + } + slist_append(pair.c_str()); +} + void LLCurl::Easy::slist_append(const char* str) { - mHeaders = curl_slist_append(mHeaders, str); + if (str) + { + mHeaders = curl_slist_append(mHeaders, str); + if (!mHeaders) + { + llwarns << "curl_slist_append() call returned NULL appending " << str << llendl; + } + } } size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) @@ -524,8 +642,9 @@ void LLCurl::Easy::prepRequest(const std::string& url, if (!post) { - slist_append("Connection: keep-alive"); - slist_append("Keep-alive: 300"); + // *TODO: Should this be set to 'Keep-Alive' ? + slist_append(HTTP_HEADER_CONNECTION, "keep-alive"); + slist_append(HTTP_HEADER_KEEP_ALIVE, "300"); // Accept and other headers for (std::vector::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) @@ -804,7 +923,7 @@ S32 LLCurl::Multi::process() ++processed; if (msg->msg == CURLMSG_DONE) { - U32 response = 0; + S32 response = 0; Easy* easy = NULL ; { @@ -823,7 +942,7 @@ S32 LLCurl::Multi::process() } else { - response = 499; + response = HTTP_INTERNAL_ERROR; //*TODO: change to llwarns llerrs << "cleaned up curl request completed!" << llendl; } @@ -1122,13 +1241,13 @@ bool LLCurlRequest::getByteRange(const std::string& url, easy->setopt(CURLOPT_HTTPGET, 1); if (length > 0) { - std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1); - easy->slist_append(range.c_str()); + std::string range = llformat("bytes=%d-%d", offset,offset+length-1); + easy->slist_append(HTTP_HEADER_RANGE, range); } else if (offset > 0) { - std::string range = llformat("Range: bytes=%d-", offset); - easy->slist_append(range.c_str()); + std::string range = llformat("bytes=%d-", offset); + easy->slist_append(HTTP_HEADER_RANGE, range); } easy->setHeaders(); bool res = addEasy(easy); @@ -1155,7 +1274,7 @@ bool LLCurlRequest::post(const std::string& url, easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append("Content-Type: application/llsd+xml"); + easy->slist_append(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); easy->setHeaders(); lldebugs << "POSTING: " << bytes << " bytes." << llendl; @@ -1183,7 +1302,7 @@ bool LLCurlRequest::post(const std::string& url, easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append("Content-Type: application/octet-stream"); + easy->slist_append(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); easy->setHeaders(); lldebugs << "POSTING: " << bytes << " bytes." << llendl; @@ -1555,6 +1674,14 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* } } +void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value) +{ + if (isValid() && mEasy) + { + mEasy->slist_append(header, value); + } +} + void LLCurlEasyRequest::slist_append(const char* str) { if (isValid() && mEasy) diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 7bcf61e233..c72e1e493a 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -39,6 +39,7 @@ #include // TODO: remove dependency #include "llbuffer.h" +#include "llhttpconstants.h" #include "lliopipe.h" #include "llsd.h" #include "llthread.h" @@ -77,59 +78,92 @@ public: Responder(); virtual ~Responder(); - /** - * @brief return true if the status code indicates success. - */ - static bool isGoodStatus(U32 status) + virtual bool followRedir() { - return((200 <= status) && (status < 300)); + return false; } - - virtual void errorWithContent( - U32 status, - const std::string& reason, - const LLSD& content); - //< called by completed() on bad status - - virtual void error(U32 status, const std::string& reason); - //< called by default error(status, reason, content) - - virtual void result(const LLSD& content); - //< called by completed for good status codes. + /** + * @brief return true if the status code indicates success. + */ + bool isGoodStatus() const { return isHttpGoodStatus(mStatus); } + + S32 getStatus() const { return mStatus; } + const std::string& getReason() const { return mReason; } + const LLSD& getContent() const { return mContent; } + bool hasResponseHeader(const std::string& header, bool check_lower=false) const; + const std::string& getResponseHeader(const std::string& header, bool check_lower=true) const; + const LLSD& getResponseHeaders() const { return mResponseHeaders; } + const std::string& getURL() const { return mURL; } + EHTTPMethod getHTTPMethod() const { return mHTTPMethod; } + + // This formats response information for use in log spam. Includes content spam. + std::string dumpResponse() const; + + // Allows direct triggering of success/error with different results. + void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + void successResult(const LLSD& content); + void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + + // The default implementation will try to parse body content as an LLSD, however + // it should not spam about parsing failures unless the server sent a + // Content-Type: application/llsd+xml header. virtual void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer); /**< Override point for clients that may want to use this class when the response is some other format besides LLSD */ + - virtual void completed( - U32 status, - const std::string& reason, - const LLSD& content); - /**< The default implemetnation calls + // The http* methods are not public since these should be triggered internally + // after status, reason, content, etc have been set. + // If you need to trigger a completion method, use the *Result methods, above. + protected: + // These methods are the preferred way to process final results. + // By default, when one of these is called the following information will be resolved: + // * HTTP status code - getStatus() + // * Reason string - getReason() + // * Content - getContent() + // * Response Headers - getResponseHeaders() + + // By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code. + virtual void httpSuccess(); + //< called by completed for good status codes. + + // By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code. + virtual void httpFailure(); + //< called by httpCompleted() on bad status + + // httpCompleted does not generally need to be overridden, unless + // you don't care about the status code (which determine httpFailure or httpSuccess) + // or if you want to re-interpret what a 'good' vs' bad' status code is. + virtual void httpCompleted(); + /**< The default implementation calls either: - * result(), or - * error() + * httpSuccess(), or + * httpFailure() */ - - // Override to handle parsing of the header only. Note: this is the only place where the contents - // of the header can be parsed. In the ::completed call above only the body is contained in the LLSD. - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content); - - // Used internally to set the url for debugging later. - void setURL(const std::string& url); - virtual bool followRedir() - { - return false; - } + public: + void setHTTPMethod(EHTTPMethod method); + void setURL(const std::string& url); + void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + void setResponseHeader(const std::string& header, const std::string& value); private: + // These can be accessed by the get* methods. Treated as 'read-only' during completion handlers. + EHTTPMethod mHTTPMethod; std::string mURL; + LLSD mResponseHeaders; + + protected: + // These should also generally be treated as 'read-only' during completion handlers + // and should be accessed by the get* methods. The exception to this rule would + // be when overriding the completedRaw method in preparation for calling httpCompleted(). + S32 mStatus; + std::string mReason; + LLSD mContent; }; typedef LLPointer ResponderPtr; @@ -225,10 +259,11 @@ public: // Copies the string so that it is guaranteed to stick around void setoptString(CURLoption option, const std::string& value); + void slist_append(const std::string& header, const std::string& value); void slist_append(const char* str); void setHeaders(); - U32 report(CURLcode); + S32 report(CURLcode); void getTransferInfo(LLCurl::TransferInfo* info); void prepRequest(const std::string& url, const std::vector& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false); @@ -484,6 +519,7 @@ public: void setWriteCallback(curl_write_callback callback, void* userdata); void setReadCallback(curl_read_callback callback, void* userdata); void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata); + void slist_append(const std::string& header, const std::string& value); void slist_append(const char* str); void sendRequest(const std::string& url); void requestComplete(); diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index 7dcf160c9b..e841c8e3ed 100644 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -51,13 +51,6 @@ const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f; const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096; -const S32 HTTP_OK = 200; -const S32 HTTP_PUT_OK = 201; -const S32 HTTP_NO_CONTENT = 204; -const S32 HTTP_MISSING = 404; -const S32 HTTP_SERVER_BAD_GATEWAY = 502; -const S32 HTTP_SERVER_TEMP_UNAVAILABLE = 503; - ///////////////////////////////////////////////////////////////////////////////// // LLTempAssetData // An asset not stored on central asset store, but on a simulator node somewhere. @@ -952,7 +945,7 @@ void LLHTTPAssetStorage::checkForTimeouts() { if (curl_msg->data.result == CURLE_OK && ( curl_result == HTTP_OK - || curl_result == HTTP_PUT_OK + || curl_result == HTTP_CREATED || curl_result == HTTP_NO_CONTENT)) { llinfos << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << llendl; @@ -963,8 +956,8 @@ void LLHTTPAssetStorage::checkForTimeouts() } else if (curl_msg->data.result == CURLE_COULDNT_CONNECT || curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || - curl_result == HTTP_SERVER_BAD_GATEWAY || - curl_result == HTTP_SERVER_TEMP_UNAVAILABLE) + curl_result == HTTP_BAD_GATEWAY || + curl_result == HTTP_SERVICE_UNAVAILABLE) { llwarns << "Re-requesting upload for " << req->getUUID() << ". Received upload error to " << req->mURLBuffer << " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; @@ -985,8 +978,8 @@ void LLHTTPAssetStorage::checkForTimeouts() if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT || curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || - curl_result == HTTP_SERVER_BAD_GATEWAY || - curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)) + curl_result == HTTP_BAD_GATEWAY || + curl_result == HTTP_SERVICE_UNAVAILABLE)) { // shared upload finished callback // in the base class, this is called from processUploadComplete @@ -1018,7 +1011,7 @@ void LLHTTPAssetStorage::checkForTimeouts() llwarns << "Failure downloading " << req->mURLBuffer << " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; - xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; + xfer_result = (curl_result == HTTP_NOT_FOUND) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; if (req->mVFile) { @@ -1240,7 +1233,7 @@ S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asse } else { - xfer_result = curl_result == HTTP_MISSING ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; + xfer_result = curl_result == HTTP_NOT_FOUND ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; llinfos << "Failure downloading " << req.mURLBuffer << " with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl; } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 0c325a68aa..a4a1f02cd3 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -54,7 +54,7 @@ namespace { public: LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder) - : LLURLRequestComplete(), mResponder(responder), mStatus(499), + : LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR), mReason("LLURLRequest complete w/no status") { } @@ -63,7 +63,7 @@ namespace { } - virtual void httpStatus(U32 status, const std::string& reason) + virtual void httpStatus(S32 status, const std::string& reason) { LLURLRequestComplete::httpStatus(status,reason); @@ -74,30 +74,33 @@ namespace virtual void complete(const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) { + // *TODO: Re-interpret mRequestStatus codes? + // Would like to detect curl errors, such as + // connection errors, write erros, etc. if (mResponder.get()) { - // Allow clients to parse headers before we attempt to parse - // the body and provide completed/result/error calls. - mResponder->completedHeader(mStatus, mReason, mHeaderOutput); - mResponder->completedRaw(mStatus, mReason, channels, buffer); + mResponder->setResult(mStatus, mReason); + mResponder->completedRaw(channels, buffer); } } virtual void header(const std::string& header, const std::string& value) { - mHeaderOutput[header] = value; + if (mResponder.get()) + { + mResponder->setResponseHeader(header, value); + } } private: LLCurl::ResponderPtr mResponder; - U32 mStatus; + S32 mStatus; std::string mReason; - LLSD mHeaderOutput; }; class Injector : public LLIOPipe { public: - virtual const char* contentType() = 0; + virtual const std::string& contentType() = 0; }; class LLSDInjector : public Injector @@ -106,7 +109,7 @@ namespace LLSDInjector(const LLSD& sd) : mSD(sd) {} virtual ~LLSDInjector() {} - const char* contentType() { return "application/llsd+xml"; } + const std::string& contentType() { return HTTP_CONTENT_LLSD_XML; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -126,7 +129,7 @@ namespace RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {} virtual ~RawInjector() {delete mData;} - const char* contentType() { return "application/octet-stream"; } + const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -147,7 +150,7 @@ namespace FileInjector(const std::string& filename) : mFilename(filename) {} virtual ~FileInjector() {} - const char* contentType() { return "application/octet-stream"; } + const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -180,7 +183,7 @@ namespace VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {} virtual ~VFileInjector() {} - const char* contentType() { return "application/octet-stream"; } + const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; } virtual EStatus process_impl(const LLChannelDescriptors& channels, buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -213,7 +216,7 @@ void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback cal static void request( const std::string& url, - LLURLRequest::ERequestAction method, + EHTTPMethod method, Injector* body_injector, LLCurl::ResponderPtr responder, const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, @@ -222,7 +225,11 @@ static void request( { if (!LLHTTPClient::hasPump()) { - responder->completed(U32_MAX, "No pump", LLSD()); + if (responder) + { + responder->completeResult(HTTP_INTERNAL_ERROR, "No pump"); + } + delete body_injector; return; } LLPumpIO::chain_t chain; @@ -230,20 +237,24 @@ static void request( LLURLRequest* req = new LLURLRequest(method, url); if(!req->isValid())//failed { - delete req ; - return ; + if (responder) + { + responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure"); + } + delete req; + delete body_injector; + return; } req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); - lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " - << headers << llendl; + LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL; // Insert custom headers if the caller sent any if (headers.isMap()) { - if (headers.has("Cookie")) + if (headers.has(HTTP_HEADER_COOKIE)) { req->allowCookies(); } @@ -253,62 +264,56 @@ static void request( for (; iter != end; ++iter) { - std::ostringstream header; //if the header is "Pragma" with no value //the caller intends to force libcurl to drop //the Pragma header it so gratuitously inserts //Before inserting the header, force libcurl //to not use the proxy (read: llurlrequest.cpp) - static const std::string PRAGMA("Pragma"); - if ((iter->first == PRAGMA) && (iter->second.asString().empty())) + if ((iter->first == HTTP_HEADER_PRAGMA) && (iter->second.asString().empty())) { req->useProxy(false); } - header << iter->first << ": " << iter->second.asString() ; - lldebugs << "header = " << header.str() << llendl; - req->addHeader(header.str().c_str()); + LL_DEBUGS("LLHTTPClient") << "header = " << iter->first + << ": " << iter->second.asString() << LL_ENDL; + req->addHeader(iter->first, iter->second.asString()); } } // Check to see if we have already set Accept or not. If no one // set it, set it to application/llsd+xml since that's what we // almost always want. - if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST ) + if( method != HTTP_PUT && method != HTTP_POST ) { - static const std::string ACCEPT("Accept"); - if(!headers.has(ACCEPT)) + if(!headers.has(HTTP_HEADER_ACCEPT)) { - req->addHeader("Accept: application/llsd+xml"); + req->addHeader(HTTP_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); } } if (responder) { responder->setURL(url); + responder->setHTTPMethod(method); } req->setCallback(new LLHTTPClientURLAdaptor(responder)); - if (method == LLURLRequest::HTTP_POST && gMessageSystem) + if (method == HTTP_POST && gMessageSystem) { - req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", - gMessageSystem->mPort).c_str()); + req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", + gMessageSystem->mPort)); } - if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) + if (method == HTTP_PUT || method == HTTP_POST) { - static const std::string CONTENT_TYPE("Content-Type"); - if(!headers.has(CONTENT_TYPE)) + if(!headers.has(HTTP_HEADER_CONTENT_TYPE)) { // If the Content-Type header was passed in, it has // already been added as a header through req->addHeader // in the loop above. We defer to the caller's wisdom, but // if they did not specify a Content-Type, then ask the // injector. - req->addHeader( - llformat( - "Content-Type: %s", - body_injector->contentType()).c_str()); + req->addHeader(HTTP_HEADER_CONTENT_TYPE, body_injector->contentType()); } chain.push_back(LLIOPipe::ptr_t(body_injector)); } @@ -331,9 +336,9 @@ void LLHTTPClient::getByteRange( if(offset > 0 || bytes > 0) { std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1); - headers["Range"] = range; + headers[HTTP_HEADER_RANGE] = range; } - request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers); + request(url,HTTP_GET, NULL, responder, timeout, headers); } void LLHTTPClient::head( @@ -342,16 +347,16 @@ void LLHTTPClient::head( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers); + request(url, HTTP_HEAD, NULL, responder, timeout, headers); } void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers); + request(url, HTTP_GET, NULL, responder, timeout, headers); } void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers); + request(url, HTTP_HEAD, NULL, responder, timeout, headers); } void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout) { @@ -392,7 +397,7 @@ public: return content; } - std::string asString() + const std::string& asString() { return mBuffer; } @@ -421,7 +426,7 @@ private: */ static LLSD blocking_request( const std::string& url, - LLURLRequest::ERequestAction method, + EHTTPMethod method, const LLSD& body, const LLSD& headers = LLSD(), const F32 timeout = 5 @@ -464,11 +469,11 @@ static LLSD blocking_request( } // * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy) - if (method == LLURLRequest::HTTP_GET) + if (method == HTTP_GET) { curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1); } - else if (method == LLURLRequest::HTTP_POST) + else if (method == HTTP_POST) { curl_easy_setopt(curlp, CURLOPT_POST, 1); //serialize to ostr then copy to str - need to because ostr ptr is unstable :( @@ -477,18 +482,20 @@ static LLSD blocking_request( body_str = ostr.str(); curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str()); //copied from PHP libs, correct? - headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml"); + headers_list = curl_slist_append(headers_list, + llformat("%s: %s", HTTP_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); // copied from llurlrequest.cpp // it appears that apache2.2.3 or django in etch is busted. If // we do not clear the expect header, we get a 500. May be // limited to django/mod_wsgi. - headers_list = curl_slist_append(headers_list, "Expect:"); + headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_HEADER_EXPECT.c_str()).c_str()); } // * Do the action using curl, handle results lldebugs << "HTTP body: " << body_str << llendl; - headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml"); + headers_list = curl_slist_append(headers_list, + llformat("%s: %s", HTTP_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list); if ( curl_result != CURLE_OK ) { @@ -497,11 +504,11 @@ static LLSD blocking_request( LLSD response = LLSD::emptyMap(); S32 curl_success = curl_easy_perform(curlp); - S32 http_status = 499; + S32 http_status = HTTP_INTERNAL_ERROR; curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status); response["status"] = http_status; // if we get a non-404 and it's not a 200 OR maybe it is but you have error bits, - if ( http_status != 404 && (http_status != 200 || curl_success != 0) ) + if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) ) { // We expect 404s, don't spam for them. llwarns << "CURL REQ URL: " << url << llendl; @@ -531,12 +538,12 @@ static LLSD blocking_request( LLSD LLHTTPClient::blockingGet(const std::string& url) { - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD()); + return blocking_request(url, HTTP_GET, LLSD()); } LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { - return blocking_request(url, LLURLRequest::HTTP_POST, body); + return blocking_request(url, HTTP_POST, body); } void LLHTTPClient::put( @@ -546,7 +553,7 @@ void LLHTTPClient::put( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); + request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); } void LLHTTPClient::post( @@ -556,7 +563,7 @@ void LLHTTPClient::post( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers); + request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers); } void LLHTTPClient::postRaw( @@ -567,7 +574,7 @@ void LLHTTPClient::postRaw( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers); + request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers); } void LLHTTPClient::postFile( @@ -577,7 +584,7 @@ void LLHTTPClient::postFile( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers); + request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers); } void LLHTTPClient::postFile( @@ -588,7 +595,7 @@ void LLHTTPClient::postFile( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers); + request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers); } // static @@ -598,7 +605,7 @@ void LLHTTPClient::del( const LLSD& headers, const F32 timeout) { - request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers); + request(url, HTTP_DELETE, NULL, responder, timeout, headers); } // static @@ -610,8 +617,8 @@ void LLHTTPClient::move( const F32 timeout) { LLSD headers = hdrs; - headers["Destination"] = destination; - request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers); + headers[HTTP_HEADER_DESTINATION] = destination; + request(url, HTTP_MOVE, NULL, responder, timeout, headers); } diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index f5d7a9abb6..aaa31e36fc 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -35,16 +35,19 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo { LLSD empty_pragma_header; // Pragma is required to stop curl adding "no-cache" - // Space is required to stop llurlrequest from turnning off proxying - empty_pragma_header["Pragma"] = " "; + // Space is required to stop llurlrequest from turning off proxying + empty_pragma_header[HTTP_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; - // as above - empty_pragma_header["Pragma"] = " "; + if (!empty_pragma_header.has(HTTP_HEADER_PRAGMA)) + { + // as above + empty_pragma_header[HTTP_HEADER_PRAGMA] = " "; + } LLHTTPClient::get(url, responder, empty_pragma_header); } @@ -53,3 +56,18 @@ void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl:: 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 aae6426a59..270282c66f 100644 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -37,6 +37,14 @@ public: 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/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp new file mode 100644 index 0000000000..2134024a14 --- /dev/null +++ b/indra/llmessage/llhttpconstants.cpp @@ -0,0 +1,219 @@ +/** + * @file llhttpconstants.cpp + * @brief Implementation of the HTTP request / response constant lookups + * + * $LicenseInfo:firstyear=2013&license=viewergpl$ + * + * Copyright (c) 2013, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llhttpconstants.h" +#include "lltimer.h" + +// for curl_getdate() (apparently parsing RFC 1123 dates is hard) +#include + +const std::string HTTP_HEADER_ACCEPT("Accept"); +const std::string HTTP_HEADER_ACCEPT_CHARSET("Accept-Charset"); +const std::string HTTP_HEADER_ACCEPT_ENCODING("Accept-Encoding"); +const std::string HTTP_HEADER_ACCEPT_LANGUAGE("Accept-Language"); +const std::string HTTP_HEADER_ACCEPT_RANGES("Accept-Ranges"); +const std::string HTTP_HEADER_AGE("Age"); +const std::string HTTP_HEADER_ALLOW("Allow"); +const std::string HTTP_HEADER_AUTHORIZATION("Authorization"); +const std::string HTTP_HEADER_CACHE_CONTROL("Cache-Control"); +const std::string HTTP_HEADER_CONNECTION("Connection"); +const std::string HTTP_HEADER_CONTENT_DESCRIPTION("Content-Description"); +const std::string HTTP_HEADER_CONTENT_ENCODING("Content-Encoding"); +const std::string HTTP_HEADER_CONTENT_ID("Content-ID"); +const std::string HTTP_HEADER_CONTENT_LANGUAGE("Content-Language"); +const std::string HTTP_HEADER_CONTENT_LENGTH("Content-Length"); +const std::string HTTP_HEADER_CONTENT_LOCATION("Content-Location"); +const std::string HTTP_HEADER_CONTENT_MD5("Content-MD5"); +const std::string HTTP_HEADER_CONTENT_RANGE("Content-Range"); +const std::string HTTP_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding"); +const std::string HTTP_HEADER_CONTENT_TYPE("Content-Type"); +const std::string HTTP_HEADER_COOKIE("Cookie"); +const std::string HTTP_HEADER_DATE("Date"); +const std::string HTTP_HEADER_DESTINATION("Destination"); +const std::string HTTP_HEADER_ETAG("ETag"); +const std::string HTTP_HEADER_EXPECT("Expect"); +const std::string HTTP_HEADER_EXPIRES("Expires"); +const std::string HTTP_HEADER_FROM("From"); +const std::string HTTP_HEADER_HOST("Host"); +const std::string HTTP_HEADER_IF_MATCH("If-Match"); +const std::string HTTP_HEADER_IF_MODIFIED_SINCE("If-Modified-Since"); +const std::string HTTP_HEADER_IF_NONE_MATCH("If-None-Match"); +const std::string HTTP_HEADER_IF_RANGE("If-Range"); +const std::string HTTP_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since"); +const std::string HTTP_HEADER_KEEP_ALIVE("Keep-Alive"); +const std::string HTTP_HEADER_LAST_MODIFIED("Last-Modified"); +const std::string HTTP_HEADER_LOCATION("Location"); +const std::string HTTP_HEADER_MAX_FORWARDS("Max-Forwards"); +const std::string HTTP_HEADER_MIME_VERSION("MIME-Version"); +const std::string HTTP_HEADER_PRAGMA("Pragma"); +const std::string HTTP_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate"); +const std::string HTTP_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization"); +const std::string HTTP_HEADER_RANGE("Range"); +const std::string HTTP_HEADER_REFERER("Referer"); +const std::string HTTP_HEADER_RETRY_AFTER("Retry-After"); +const std::string HTTP_HEADER_SERVER("Server"); +const std::string HTTP_HEADER_SET_COOKIE("Set-Cookie"); +const std::string HTTP_HEADER_TE("TE"); +const std::string HTTP_HEADER_TRAILER("Trailer"); +const std::string HTTP_HEADER_TRANSFER_ENCODING("Transfer-Encoding"); +const std::string HTTP_HEADER_UPGRADE("Upgrade"); +const std::string HTTP_HEADER_USER_AGENT("User-Agent"); +const std::string HTTP_HEADER_VARY("Vary"); +const std::string HTTP_HEADER_VIA("Via"); +const std::string HTTP_HEADER_WARNING("Warning"); +const std::string HTTP_HEADER_WWW_AUTHENTICATE("WWW-Authenticate"); + + +// Sadly, our proxied headers do not follow http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html +// We need to deal with lowercase headers +const std::string HTTP_HEADER_LOWER_ACCEPT_LANGUAGE("accept-language"); +const std::string HTTP_HEADER_LOWER_CACHE_CONTROL("cache-control"); +const std::string HTTP_HEADER_LOWER_CONTENT_LENGTH("content-length"); +const std::string HTTP_HEADER_LOWER_CONTENT_TYPE("content-type"); +const std::string HTTP_HEADER_LOWER_HOST("host"); +const std::string HTTP_HEADER_LOWER_USER_AGENT("user-agent"); +const std::string HTTP_HEADER_LOWER_X_FORWARDED_FOR("x-forwarded-for"); + +const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml"); +const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream"); +const std::string HTTP_CONTENT_XML("application/xml"); +const std::string HTTP_CONTENT_JSON("application/json"); +const std::string HTTP_CONTENT_TEXT_HTML("text/html"); +const std::string HTTP_CONTENT_TEXT_HTML_UTF8("text/html; charset=utf-8"); +const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8("text/plain; charset=utf-8"); +const std::string HTTP_CONTENT_TEXT_LLSD("text/llsd"); +const std::string HTTP_CONTENT_TEXT_XML("text/xml"); +const std::string HTTP_CONTENT_TEXT_LSL("text/lsl"); +const std::string HTTP_CONTENT_TEXT_PLAIN("text/plain"); +const std::string HTTP_CONTENT_IMAGE_X_J2C("image/x-j2c"); +const std::string HTTP_CONTENT_IMAGE_J2C("image/j2c"); +const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg"); +const std::string HTTP_CONTENT_IMAGE_PNG("image/png"); +const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp"); + +const std::string HTTP_VERB_INVALID("(invalid)"); +const std::string HTTP_VERB_HEAD("HEAD"); +const std::string HTTP_VERB_GET("GET"); +const std::string HTTP_VERB_PUT("PUT"); +const std::string HTTP_VERB_POST("POST"); +const std::string HTTP_VERB_DELETE("DELETE"); +const std::string HTTP_VERB_MOVE("MOVE"); +const std::string HTTP_VERB_OPTIONS("OPTIONS"); + +const std::string& httpMethodAsVerb(EHTTPMethod method) +{ + static const std::string VERBS[] = + { + HTTP_VERB_INVALID, + HTTP_VERB_HEAD, + HTTP_VERB_GET, + HTTP_VERB_PUT, + HTTP_VERB_POST, + HTTP_VERB_DELETE, + HTTP_VERB_MOVE, + HTTP_VERB_OPTIONS + }; + if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT)) + { + return VERBS[0]; + } + return VERBS[method]; +} + +bool isHttpInformationalStatus(S32 status) +{ + // Check for status 1xx. + return((100 <= status) && (status < 200)); +} + +bool isHttpGoodStatus(S32 status) +{ + // Check for status 2xx. + return((200 <= status) && (status < 300)); +} + +bool isHttpRedirectStatus(S32 status) +{ + // Check for status 3xx. + return((300 <= status) && (status < 400)); +} + +bool isHttpClientErrorStatus(S32 status) +{ + // Status 499 is sometimes used for re-interpreted status 2xx errors + // based on body content. Treat these as potentially retryable 'server' status errors, + // since we do not have enough context to know if this will always fail. + if (HTTP_INTERNAL_ERROR == status) return false; + + // Check for status 5xx. + return((400 <= status) && (status < 500)); +} + +bool isHttpServerErrorStatus(S32 status) +{ + // Status 499 is sometimes used for re-interpreted status 2xx errors. + // Allow retry of these, since we don't have enough information in this + // context to know if this will always fail. + if (HTTP_INTERNAL_ERROR == status) return true; + + // Check for status 5xx. + return((500 <= status) && (status < 600)); +} + +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait) +{ + // *TODO: This needs testing! Not in use yet. + // Examples of Retry-After headers: + // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT + // Retry-After: 120 + + // Check for number of seconds version, first: + char* end = 0; + // Parse as double + double seconds = std::strtod(retry_after.c_str(), &end); + if ( end != 0 && *end == 0 ) + { + // Successful parse + seconds_to_wait = (F32) seconds; + return true; + } + + // Parse rfc1123 date. + time_t date = curl_getdate(retry_after.c_str(), NULL ); + if (-1 == date) return false; + + seconds_to_wait = (F32)date - (F32)LLTimer::getTotalSeconds(); + return true; +} + diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h new file mode 100644 index 0000000000..34263e17c8 --- /dev/null +++ b/indra/llmessage/llhttpconstants.h @@ -0,0 +1,220 @@ +/** + * @file llhttpconstants.h + * @brief Constants for HTTP requests and responses + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2013, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_HTTP_CONSTANTS_H +#define LL_HTTP_CONSTANTS_H + +#include "stdtypes.h" + +/////// HTTP STATUS CODES /////// + +// Standard errors from HTTP spec: +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1 +const S32 HTTP_CONTINUE = 100; +const S32 HTTP_SWITCHING_PROTOCOLS = 101; + +// Success +const S32 HTTP_OK = 200; +const S32 HTTP_CREATED = 201; +const S32 HTTP_ACCEPTED = 202; +const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203; +const S32 HTTP_NO_CONTENT = 204; +const S32 HTTP_RESET_CONTENT = 205; +const S32 HTTP_PARTIAL_CONTENT = 206; + +// Redirection +const S32 HTTP_MULTIPLE_CHOICES = 300; +const S32 HTTP_MOVED_PERMANENTLY = 301; +const S32 HTTP_FOUND = 302; +const S32 HTTP_SEE_OTHER = 303; +const S32 HTTP_NOT_MODIFIED = 304; +const S32 HTTP_USE_PROXY = 305; +const S32 HTTP_TEMPORARY_REDIRECT = 307; + +// Client Error +const S32 HTTP_BAD_REQUEST = 400; +const S32 HTTP_UNAUTHORIZED = 401; +const S32 HTTP_PAYMENT_REQUIRED = 402; +const S32 HTTP_FORBIDDEN = 403; +const S32 HTTP_NOT_FOUND = 404; +const S32 HTTP_METHOD_NOT_ALLOWED = 405; +const S32 HTTP_NOT_ACCEPTABLE = 406; +const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; +const S32 HTTP_REQUEST_TIME_OUT = 408; +const S32 HTTP_CONFLICT = 409; +const S32 HTTP_GONE = 410; +const S32 HTTP_LENGTH_REQUIRED = 411; +const S32 HTTP_PRECONDITION_FAILED = 412; +const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413; +const S32 HTTP_REQUEST_URI_TOO_LARGE = 414; +const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415; +const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +const S32 HTTP_EXPECTATION_FAILED = 417; + +// Server Error +const S32 HTTP_INTERNAL_SERVER_ERROR = 500; +const S32 HTTP_NOT_IMPLEMENTED = 501; +const S32 HTTP_BAD_GATEWAY = 502; +const S32 HTTP_SERVICE_UNAVAILABLE = 503; +const S32 HTTP_GATEWAY_TIME_OUT = 504; +const S32 HTTP_VERSION_NOT_SUPPORTED = 505; + +// We combine internal process errors with status codes +// These status codes should not be sent over the wire +// and indicate something went wrong internally. +// If you get these they are not normal. +const S32 HTTP_INTERNAL_CURL_ERROR = 498; +const S32 HTTP_INTERNAL_ERROR = 499; + + +////// HTTP Methods ////// + +extern const std::string HTTP_VERB_INVALID; +extern const std::string HTTP_VERB_HEAD; +extern const std::string HTTP_VERB_GET; +extern const std::string HTTP_VERB_PUT; +extern const std::string HTTP_VERB_POST; +extern const std::string HTTP_VERB_DELETE; +extern const std::string HTTP_VERB_MOVE; +extern const std::string HTTP_VERB_OPTIONS; + +enum EHTTPMethod +{ + HTTP_INVALID = 0, + HTTP_HEAD, + HTTP_GET, + HTTP_PUT, + HTTP_POST, + HTTP_DELETE, + HTTP_MOVE, // Caller will need to set 'Destination' header + HTTP_OPTIONS, + HTTP_METHOD_COUNT +}; + +const std::string& httpMethodAsVerb(EHTTPMethod method); +bool isHttpInformationalStatus(S32 status); +bool isHttpGoodStatus(S32 status); +bool isHttpRedirectStatus(S32 status); +bool isHttpClientErrorStatus(S32 status); +bool isHttpServerErrorStatus(S32 status); + +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait); + +//// HTTP Headers ///// + +extern const std::string HTTP_HEADER_ACCEPT; +extern const std::string HTTP_HEADER_ACCEPT_CHARSET; +extern const std::string HTTP_HEADER_ACCEPT_ENCODING; +extern const std::string HTTP_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_HEADER_ACCEPT_RANGES; +extern const std::string HTTP_HEADER_AGE; +extern const std::string HTTP_HEADER_ALLOW; +extern const std::string HTTP_HEADER_AUTHORIZATION; +extern const std::string HTTP_HEADER_CACHE_CONTROL; +extern const std::string HTTP_HEADER_CONNECTION; +extern const std::string HTTP_HEADER_CONTENT_DESCRIPTION; +extern const std::string HTTP_HEADER_CONTENT_ENCODING; +extern const std::string HTTP_HEADER_CONTENT_ID; +extern const std::string HTTP_HEADER_CONTENT_LANGUAGE; +extern const std::string HTTP_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_HEADER_CONTENT_MD5; +extern const std::string HTTP_HEADER_CONTENT_RANGE; +extern const std::string HTTP_HEADER_CONTENT_TRANSFER_ENCODING; +extern const std::string HTTP_HEADER_CONTENT_TYPE; +extern const std::string HTTP_HEADER_COOKIE; +extern const std::string HTTP_HEADER_DATE; +extern const std::string HTTP_HEADER_DESTINATION; +extern const std::string HTTP_HEADER_ETAG; +extern const std::string HTTP_HEADER_EXPECT; +extern const std::string HTTP_HEADER_EXPIRES; +extern const std::string HTTP_HEADER_FROM; +extern const std::string HTTP_HEADER_HOST; +extern const std::string HTTP_HEADER_IF_MATCH; +extern const std::string HTTP_HEADER_IF_MODIFIED_SINCE; +extern const std::string HTTP_HEADER_IF_NONE_MATCH; +extern const std::string HTTP_HEADER_IF_RANGE; +extern const std::string HTTP_HEADER_IF_UNMODIFIED_SINCE; +extern const std::string HTTP_HEADER_KEEP_ALIVE; +extern const std::string HTTP_HEADER_LAST_MODIFIED; +extern const std::string HTTP_HEADER_LOCATION; +extern const std::string HTTP_HEADER_MAX_FORWARDS; +extern const std::string HTTP_HEADER_MIME_VERSION; +extern const std::string HTTP_HEADER_PRAGMA; +extern const std::string HTTP_HEADER_PROXY_AUTHENTICATE; +extern const std::string HTTP_HEADER_PROXY_AUTHORIZATION; +extern const std::string HTTP_HEADER_RANGE; +extern const std::string HTTP_HEADER_REFERER; +extern const std::string HTTP_HEADER_RETRY_AFTER; +extern const std::string HTTP_HEADER_SERVER; +extern const std::string HTTP_HEADER_SET_COOKIE; +extern const std::string HTTP_HEADER_TE; +extern const std::string HTTP_HEADER_TRAILER; +extern const std::string HTTP_HEADER_TRANSFER_ENCODING; +extern const std::string HTTP_HEADER_UPGRADE; +extern const std::string HTTP_HEADER_USER_AGENT; +extern const std::string HTTP_HEADER_VARY; +extern const std::string HTTP_HEADER_VIA; +extern const std::string HTTP_HEADER_WARNING; +extern const std::string HTTP_HEADER_WWW_AUTHENTICATE; + +// Sadly, our proxied headers do not follow http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html +// We need to deal with lowercase headers +extern const std::string HTTP_HEADER_LOWER_ACCEPT_LANGUAGE; +extern const std::string HTTP_HEADER_LOWER_CACHE_CONTROL; +extern const std::string HTTP_HEADER_LOWER_CONTENT_LENGTH; +extern const std::string HTTP_HEADER_LOWER_CONTENT_TYPE; +extern const std::string HTTP_HEADER_LOWER_HOST; +extern const std::string HTTP_HEADER_LOWER_USER_AGENT; +extern const std::string HTTP_HEADER_LOWER_X_FORWARDED_FOR; + +//// HTTP Content Types //// + +extern const std::string HTTP_CONTENT_LLSD_XML; +extern const std::string HTTP_CONTENT_OCTET_STREAM; +extern const std::string HTTP_CONTENT_XML; +extern const std::string HTTP_CONTENT_JSON; +extern const std::string HTTP_CONTENT_TEXT_HTML; +extern const std::string HTTP_CONTENT_TEXT_HTML_UTF8; +extern const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8; +extern const std::string HTTP_CONTENT_TEXT_LLSD; +extern const std::string HTTP_CONTENT_TEXT_XML; +extern const std::string HTTP_CONTENT_TEXT_LSL; +extern const std::string HTTP_CONTENT_TEXT_PLAIN; +extern const std::string HTTP_CONTENT_IMAGE_X_J2C; +extern const std::string HTTP_CONTENT_IMAGE_J2C; +extern const std::string HTTP_CONTENT_IMAGE_JPEG; +extern const std::string HTTP_CONTENT_IMAGE_PNG; +extern const std::string HTTP_CONTENT_IMAGE_BMP; + +#endif diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 5c2f73eccb..e3b42b1b16 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -30,6 +30,7 @@ #include #include "llstl.h" +#include "llhttpconstants.h" #include "lliohttpserver.h" // for string constants static const std::string CONTEXT_WILDCARD("wildcard"); @@ -173,13 +174,15 @@ LLSD LLHTTPNode::simpleDel(const LLSD&) const void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const { //llinfos << "options context: " << context << llendl; + LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL; // default implementation constructs an url to the documentation. + // *TODO: Check for 'Host' header instead of 'host' header? std::string host( - context[CONTEXT_REQUEST][CONTEXT_HEADERS]["host"].asString()); + context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_HEADER_LOWER_HOST].asString()); if(host.empty()) { - response->status(400, "Bad Request -- need Host header"); + response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header"); return; } std::ostringstream ostr; @@ -187,7 +190,7 @@ void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const ostr << context[CONTEXT_REQUEST]["path"].asString(); static const std::string DOC_HEADER("X-Documentation-URL"); response->addHeader(DOC_HEADER, ostr.str()); - response->status(200, "OK"); + response->status(HTTP_OK, "OK"); } @@ -389,17 +392,17 @@ void LLHTTPNode::Response::statusUnknownError(S32 code) void LLHTTPNode::Response::notFound(const std::string& message) { - status(404, message); + status(HTTP_NOT_FOUND, message); } void LLHTTPNode::Response::notFound() { - status(404, "Not Found"); + status(HTTP_NOT_FOUND, "Not Found"); } void LLHTTPNode::Response::methodNotAllowed() { - status(405, "Method Not Allowed"); + status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed"); } void LLHTTPNode::Response::addHeader( @@ -467,7 +470,7 @@ LLSimpleResponse::~LLSimpleResponse() void LLSimpleResponse::result(const LLSD& result) { - status(200, "OK"); + status(HTTP_OK, "OK"); } void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const LLSD& headers) @@ -475,6 +478,11 @@ void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const L status(code,body); } +void LLSimpleResponse::extendedResult(S32 code, const LLSD& r, const LLSD& headers) +{ + status(code,"(LLSD)"); +} + void LLSimpleResponse::status(S32 code, const std::string& message) { mCode = code; diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index 148647ddde..2539eec6c3 100644 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -60,6 +60,8 @@ class LLChainIOFactory; */ class LLHTTPNode { +protected: + LOG_CLASS(LLHTTPNode); public: LLHTTPNode(); virtual ~LLHTTPNode(); @@ -100,7 +102,12 @@ public: /** * @brief return status code and message with headers. */ - virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) = 0; + virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0; + + /** + * @brief return status code and LLSD result with headers. + */ + virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0; /** * @brief return status code and reason string on http header, @@ -287,7 +294,7 @@ public: void result(const LLSD& result); void extendedResult(S32 code, const std::string& body, const LLSD& headers); - + void extendedResult(S32 code, const LLSD& result, const LLSD& headers); void status(S32 code, const std::string& message); void print(std::ostream& out) const; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 1236fc8b71..509719786c 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -33,6 +33,7 @@ #include "llapr.h" #include "llbuffer.h" #include "llbufferstream.h" +#include "llhttpconstants.h" #include "llhttpnode.h" #include "lliopipe.h" #include "lliosocket.h" @@ -53,11 +54,6 @@ const std::string CONTEXT_REQUEST("request"); const std::string CONTEXT_RESPONSE("response"); const std::string CONTEXT_VERB("verb"); const std::string CONTEXT_HEADERS("headers"); -const std::string HTTP_VERB_GET("GET"); -const std::string HTTP_VERB_PUT("PUT"); -const std::string HTTP_VERB_POST("POST"); -const std::string HTTP_VERB_DELETE("DELETE"); -const std::string HTTP_VERB_OPTIONS("OPTIONS"); static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL; static void* sTimingCallbackData = NULL; @@ -102,7 +98,7 @@ private: // from LLHTTPNode::Response virtual void result(const LLSD&); virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers); - + virtual void extendedResult(S32 code, const LLSD& body, const LLSD& headers); virtual void status(S32 code, const std::string& message); void nullPipe(); @@ -122,7 +118,8 @@ private: STATE_LOCKED, STATE_GOOD_RESULT, STATE_STATUS_RESULT, - STATE_EXTENDED_RESULT + STATE_EXTENDED_RESULT, + STATE_EXTENDED_LLSD_RESULT }; State mState; @@ -132,7 +129,7 @@ private: void lockChain(LLPumpIO*); void unlockChain(); - LLSD mGoodResult; + LLSD mResult; S32 mStatusCode; std::string mStatusMessage; LLSD mHeaders; @@ -193,7 +190,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT) { - std::stringstream strstrm; + std::ostringstream strstrm; strstrm << istr.rdbuf(); input = strstrm.str(); } @@ -209,7 +206,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT) { - std::stringstream strstrm; + std::ostringstream strstrm; strstrm << istr.rdbuf(); input = strstrm.str(); } @@ -249,7 +246,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( << "s" << llendl; // Log Internal Server Errors - //if(mStatusCode == 500) + //if(mStatusCode == HTTP_INTERNAL_SERVER_ERROR) //{ // llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" // << llendl; @@ -271,10 +268,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( case STATE_GOOD_RESULT: { LLSD headers = mHeaders; - headers["Content-Type"] = "application/llsd+xml"; + headers[HTTP_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; LLBufferStream ostr(channels, buffer.get()); - LLSDSerialize::toXML(mGoodResult, ostr); + LLSDSerialize::toXML(mResult, ostr); return STATUS_DONE; } @@ -282,7 +279,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( case STATE_STATUS_RESULT: { LLSD headers = mHeaders; - headers["Content-Type"] = "text/plain"; + headers[HTTP_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN; context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage; @@ -300,6 +297,17 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( return STATUS_DONE; } + case STATE_EXTENDED_LLSD_RESULT: + { + LLSD headers = mHeaders; + headers[HTTP_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; + context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; + LLBufferStream ostr(channels, buffer.get()); + LLSDSerialize::toXML(mResult, ostr); + + return STATUS_DONE; + } default: llwarns << "LLHTTPPipe::process_impl: unexpected state " << mState << llendl; @@ -335,19 +343,35 @@ void LLHTTPPipe::Response::result(const LLSD& r) return; } - mPipe->mStatusCode = 200; + mPipe->mStatusCode = HTTP_OK; mPipe->mStatusMessage = "OK"; - mPipe->mGoodResult = r; + mPipe->mResult = r; mPipe->mState = STATE_GOOD_RESULT; mPipe->mHeaders = mHeaders; - mPipe->unlockChain(); + mPipe->unlockChain(); +} + +void LLHTTPPipe::Response::extendedResult(S32 code, const LLSD& r, const LLSD& headers) +{ + if(! mPipe) + { + llwarns << "LLHTTPPipe::Response::extendedResult: NULL pipe" << llendl; + return; + } + + mPipe->mStatusCode = code; + mPipe->mStatusMessage = "(LLSD)"; + mPipe->mResult = r; + mPipe->mHeaders = headers; + mPipe->mState = STATE_EXTENDED_LLSD_RESULT; + mPipe->unlockChain(); } void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers) { if(! mPipe) { - llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl; + llwarns << "LLHTTPPipe::Response::extendedResult: NULL pipe" << llendl; return; } @@ -454,9 +478,9 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( std::string message = context[CONTEXT_RESPONSE]["statusMessage"]; int code = context[CONTEXT_RESPONSE]["statusCode"]; - if (code < 200) + if (code < HTTP_OK) { - code = 200; + code = HTTP_OK; message = "OK"; } @@ -465,7 +489,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( S32 content_length = buffer->countAfter(channels.in(), NULL); if(0 < content_length) { - ostr << "Content-Length: " << content_length << "\r\n"; + ostr << HTTP_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n"; } // *NOTE: This guard can go away once the LLSD static map // iterator is available. Phoenix. 2008-05-09 @@ -771,7 +795,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( std::string name(buf, pos_colon - buf); std::string value(pos_colon + 2); LLStringUtil::toLower(name); - if("content-length" == name) + if(HTTP_HEADER_LOWER_CONTENT_LENGTH == name) { lldebugs << "Content-Length: " << value << llendl; mContentLength = atoi(value.c_str()); diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index 5c1b0531ff..40537e05bc 100644 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -39,11 +39,6 @@ extern const std::string CONTEXT_REQUEST; extern const std::string CONTEXT_RESPONSE; extern const std::string CONTEXT_VERB; extern const std::string CONTEXT_HEADERS; -extern const std::string HTTP_VERB_GET; -extern const std::string HTTP_VERB_PUT; -extern const std::string HTTP_VERB_POST; -extern const std::string HTTP_VERB_DELETE; -extern const std::string HTTP_VERB_OPTIONS; class LLIOHTTPServer { diff --git a/indra/llmessage/llmime.cpp b/indra/llmessage/llmime.cpp index 9d9c4ebd68..90653098db 100644 --- a/indra/llmessage/llmime.cpp +++ b/indra/llmessage/llmime.cpp @@ -27,6 +27,7 @@ */ #include "linden_common.h" +#include "llhttpconstants.h" #include "llmime.h" #include @@ -36,20 +37,6 @@ /** * Useful constants. */ -// Headers specified in rfc-2045 will be canonicalized below. -static const std::string CONTENT_LENGTH("Content-Length"); -static const std::string CONTENT_TYPE("Content-Type"); -static const S32 KNOWN_HEADER_COUNT = 6; -static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] = -{ - CONTENT_LENGTH, - CONTENT_TYPE, - std::string("MIME-Version"), - std::string("Content-Transfer-Encoding"), - std::string("Content-ID"), - std::string("Content-Description"), -}; - // parser helpers static const std::string MULTIPART("multipart"); static const std::string BOUNDARY("boundary"); @@ -115,7 +102,7 @@ S32 LLMimeIndex::contentLength() const { // Find the content length in the headers. S32 length = -1; - LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH]; + LLSD content_length = mImpl->mHeaders[HTTP_HEADER_CONTENT_LENGTH]; if(content_length.isDefined()) { length = content_length.asInteger(); @@ -126,7 +113,7 @@ S32 LLMimeIndex::contentLength() const std::string LLMimeIndex::contentType() const { std::string type; - LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; + LLSD content_type = mImpl->mHeaders[HTTP_HEADER_CONTENT_TYPE]; if(content_type.isDefined()) { type = content_type.asString(); @@ -137,7 +124,7 @@ std::string LLMimeIndex::contentType() const bool LLMimeIndex::isMultipart() const { bool multipart = false; - LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; + LLSD content_type = mImpl->mHeaders[HTTP_HEADER_CONTENT_TYPE]; if(content_type.isDefined()) { std::string type = content_type.asString(); @@ -354,7 +341,7 @@ bool LLMimeParser::Impl::parseIndex( if(index.isMultipart()) { // Figure out the separator, scan past it, and recurse. - std::string ct = headers[CONTENT_TYPE].asString(); + std::string ct = headers[HTTP_HEADER_CONTENT_TYPE].asString(); std::string sep = findSeparator(ct); scanPastSeparator(istr, limit, sep); while(continueParse() && parseIndex(istr, limit, sep, true, mime)) @@ -381,6 +368,18 @@ bool LLMimeParser::Impl::parseHeaders( S32 limit, LLSD& headers) { + // Headers specified in rfc-2045 will be canonicalized below. + static const S32 KNOWN_HEADER_COUNT = 6; + static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] = + { + HTTP_HEADER_CONTENT_LENGTH, + HTTP_HEADER_CONTENT_TYPE, + HTTP_HEADER_MIME_VERSION, + HTTP_HEADER_CONTENT_TRANSFER_ENCODING, + HTTP_HEADER_CONTENT_ID, + HTTP_HEADER_CONTENT_DESCRIPTION, + }; + while(continueParse()) { // Get the next line. @@ -531,9 +530,9 @@ void LLMimeParser::Impl::scanPastContent( LLSD headers, const std::string separator) { - if(headers.has(CONTENT_LENGTH)) + if(headers.has(HTTP_HEADER_CONTENT_LENGTH)) { - S32 content_length = headers[CONTENT_LENGTH].asInteger(); + S32 content_length = headers[HTTP_HEADER_CONTENT_LENGTH].asInteger(); // Subtract 2 here for the \r\n after the content. S32 max_skip = llmin(content_length, limit - mScanCount - 2); istr.ignore(max_skip); diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp deleted file mode 100644 index 932cbf375e..0000000000 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file llregionpresenceverifier.cpp - * @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 "linden_common.h" - -#include "llregionpresenceverifier.h" -#include "llhttpclientinterface.h" -#include -#include "net.h" -#include "message.h" - -namespace boost -{ - void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p) - { - ++p->mReferenceCount; - } - - void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p) - { - if(p && 0 == --p->mReferenceCount) - { - delete p; - } - } -}; - -LLRegionPresenceVerifier::Response::~Response() -{ -} - -LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string& - uri, - ResponsePtr data, - S32 retry_count) : - mUri(uri), - mSharedData(data), - mRetryCount(retry_count) -{ -} - -//virtual -LLRegionPresenceVerifier::RegionResponder::~RegionResponder() -{ -} - -void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content) -{ - std::string host = content["private_host"].asString(); - U32 port = content["private_port"].asInteger(); - LLHost destination(host, port); - LLUUID id = content["region_id"]; - - lldebugs << "Verifying " << destination.getString() << " is region " << id << llendl; - - std::stringstream uri; - uri << "http://" << destination.getString() << "/state/basic/"; - mSharedData->getHttpClient().get( - uri.str(), - new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount)); -} - -void LLRegionPresenceVerifier::RegionResponder::error(U32 status, - const std::string& reason) -{ - // TODO: babbage: distinguish between region presence service and - // region verification errors? - mSharedData->onRegionVerificationFailed(); -} - -LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content, - S32 retry_count): - mUri(uri), - mSharedData(data), - mContent(content), - mRetryCount(retry_count) -{ -} - -//virtual -LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder() -{ -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content) -{ - LLUUID actual_region_id = content["region_id"]; - LLUUID expected_region_id = mContent["region_id"]; - - lldebugs << "Actual region: " << content << llendl; - lldebugs << "Expected region: " << mContent << llendl; - - if (mSharedData->checkValidity(content) && - (actual_region_id == expected_region_id)) - { - mSharedData->onRegionVerified(mContent); - } - else if (mRetryCount > 0) - { - retry(); - } - else - { - llwarns << "Simulator verification failed. Region: " << mUri << llendl; - mSharedData->onRegionVerificationFailed(); - } -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry() -{ - LLSD headers; - headers["Cache-Control"] = "no-cache, max-age=0"; - llinfos << "Requesting region information, get uncached for region " - << mUri << llendl; - --mRetryCount; - mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers); -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason) -{ - if(mRetryCount > 0) - { - retry(); - } - else - { - llwarns << "Failed to contact simulator for verification. Region: " << mUri << llendl; - mSharedData->onRegionVerificationFailed(); - } -} diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h deleted file mode 100644 index 5e8251e519..0000000000 --- a/indra/llmessage/llregionpresenceverifier.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @file llregionpresenceverifier.cpp - * @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_LLREGIONPRESENCEVERIFIER_H -#define LL_LLREGIONPRESENCEVERIFIER_H - -#include "llhttpclient.h" -#include -#include "llsd.h" -#include - -class LLHTTPClientInterface; - -class LLRegionPresenceVerifier -{ -public: - class Response - { - public: - virtual ~Response() = 0; - - virtual bool checkValidity(const LLSD& content) const = 0; - virtual void onRegionVerified(const LLSD& region_details) = 0; - virtual void onRegionVerificationFailed() = 0; - - virtual LLHTTPClientInterface& getHttpClient() = 0; - - public: /* but not really -- don't touch this */ - U32 mReferenceCount; - }; - - typedef boost::intrusive_ptr ResponsePtr; - - class RegionResponder : public LLHTTPClient::Responder - { - public: - RegionResponder(const std::string& uri, ResponsePtr data, - S32 retry_count); - virtual ~RegionResponder(); - virtual void result(const LLSD& content); - virtual void error(U32 status, const std::string& reason); - - private: - ResponsePtr mSharedData; - std::string mUri; - S32 mRetryCount; - }; - - class VerifiedDestinationResponder : public LLHTTPClient::Responder - { - public: - VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, - const LLSD& content, S32 retry_count); - virtual ~VerifiedDestinationResponder(); - virtual void result(const LLSD& content); - - virtual void error(U32 status, const std::string& reason); - - private: - void retry(); - ResponsePtr mSharedData; - LLSD mContent; - std::string mUri; - S32 mRetryCount; - }; -}; - -namespace boost -{ - void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p); - void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p); -}; - -#endif //LL_LLREGIONPRESENCEVERIFIER_H diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 1c93c12d99..376f69ea36 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -92,14 +92,14 @@ bool LLSDMessage::httpListener(const LLSD& request) return false; } -void LLSDMessage::EventResponder::result(const LLSD& data) +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(data); + LLSD response(getContent()); mReqID.stamp(response); mPumps.obtain(mReplyPump).post(response); } @@ -111,7 +111,7 @@ void LLSDMessage::EventResponder::result(const LLSD& data) } } -void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +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 @@ -121,19 +121,16 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string LLSD info(mReqID.makeResponse()); info["target"] = mTarget; info["message"] = mMessage; - info["status"] = LLSD::Integer(status); - info["reason"] = reason; - info["content"] = content; + info["status"] = getStatus(); + info["reason"] = getReason(); + info["content"] = getContent(); mPumps.obtain(mErrorPump).post(info); } else // default error handling { - // convention seems to be to use llinfos, but that seems a bit casual? LL_WARNS("LLSDMessage::EventResponder") << "'" << mMessage << "' to '" << mTarget - << "' failed with code " << status << ": " << reason << '\n' - << ll_pretty_print_sd(content) - << LL_ENDL; + << "' failed " << dumpResponse() << LL_ENDL; } } @@ -151,11 +148,11 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) { if (success) { - mResponder->result(payload); + mResponder->successResult(payload); } else { - mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); + mResponder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"]); } /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 0d34847ff2..e5d532d6a4 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -123,6 +123,7 @@ private: /// LLCapabilityListener. Others should use higher-level APIs. class EventResponder: public LLHTTPClient::Responder { + LOG_CLASS(EventResponder); public: /** * LLHTTPClient::Responder that dispatches via named LLEventPump instances. @@ -149,8 +150,9 @@ private: mErrorPump(errorPump) {} - virtual void result(const LLSD& data); - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: LLEventPumps& mPumps; diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index 0cecf4f688..02891d4f32 100644 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -240,7 +240,7 @@ public: virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const { lldebugs << "LLSDRPCClientFactory::build" << llendl; - LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); + LLURLRequest* http(new LLURLRequest(HTTP_POST)); if(!http->isValid()) { llwarns << "Creating LLURLRequest failed." << llendl ; @@ -251,7 +251,7 @@ public: LLIOPipe::ptr_t service(new Client); chain.push_back(service); LLIOPipe::ptr_t http_pipe(http); - http->addHeader("Content-Type: text/llsd"); + http->addHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD); if(mURL.empty()) { chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); @@ -291,7 +291,7 @@ public: { lldebugs << "LLXMLSDRPCClientFactory::build" << llendl; - LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); + LLURLRequest* http(new LLURLRequest(HTTP_POST)); if(!http->isValid()) { llwarns << "Creating LLURLRequest failed." << llendl ; @@ -301,7 +301,7 @@ public: LLIOPipe::ptr_t service(new Client); chain.push_back(service); LLIOPipe::ptr_t http_pipe(http); - http->addHeader("Content-Type: text/xml"); + http->addHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); if(mURL.empty()) { chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index fea7fc72c4..8248b184e9 100644 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -64,7 +64,7 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response, LL_WARNS("Messaging") << "trusted message POST to /trusted-message/" << name << " from unknown or untrusted sender " << sender << llendl; - response->status(403, "Unknown or untrusted sender"); + response->status(HTTP_FORBIDDEN, "Unknown or untrusted sender"); } else { diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 627d591839..f354f5ab5d 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -40,7 +40,6 @@ #include "llstring.h" #include "apr_env.h" #include "llapr.h" -static const U32 HTTP_STATUS_PIPE_ERROR = 499; /** * String constants @@ -130,34 +129,15 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param) * class LLURLRequest */ -// static -std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) -{ - static const std::string VERBS[] = - { - "(invalid)", - "HEAD", - "GET", - "PUT", - "POST", - "DELETE", - "MOVE" - }; - if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT)) - { - return VERBS[0]; - } - return VERBS[action]; -} -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) : +LLURLRequest::LLURLRequest(EHTTPMethod action) : mAction(action) { initialize(); } LLURLRequest::LLURLRequest( - LLURLRequest::ERequestAction action, + EHTTPMethod action, const std::string& url) : mAction(action) { @@ -180,12 +160,17 @@ void LLURLRequest::setURL(const std::string& url) } } -std::string LLURLRequest::getURL() const +const std::string& LLURLRequest::getURL() const { return mDetail->mURL; } -void LLURLRequest::addHeader(const char* header) +void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */) +{ + mDetail->mCurlRequest->slist_append(header, value); +} + +void LLURLRequest::addHeaderRaw(const char* header) { mDetail->mCurlRequest->slist_append(header); } @@ -272,7 +257,7 @@ LLIOPipe::EStatus LLURLRequest::handleError( LLURLRequestComplete* complete = NULL; complete = (LLURLRequestComplete*)mCompletionCallback.get(); complete->httpStatus( - HTTP_STATUS_PIPE_ERROR, + HTTP_INTERNAL_ERROR, LLIOPipe::lookupStatusString(status)); complete->responseStatus(status); pump->respond(complete); @@ -494,7 +479,7 @@ bool LLURLRequest::configure() case HTTP_PUT: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. - addHeader("Expect:"); + addHeader(HTTP_HEADER_EXPECT); mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); @@ -504,11 +489,11 @@ bool LLURLRequest::configure() case HTTP_POST: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. - addHeader("Expect:"); + addHeader(HTTP_HEADER_EXPECT); // Disable the content type http header. // *FIX: what should it be? - addHeader("Content-Type:"); + addHeader(HTTP_HEADER_CONTENT_TYPE); // Set the handle for an http post mDetail->mCurlRequest->setPost(NULL, bytes); @@ -638,7 +623,7 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user) S32 status_code = atoi(status.c_str()); if (status_code > 0) { - complete->httpStatus((U32)status_code, reason); + complete->httpStatus(status_code, reason); return header_len; } } diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 44d358d906..f334c92cc3 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -68,42 +68,22 @@ class LLURLRequest : public LLIOPipe { LOG_CLASS(LLURLRequest); public: - typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param); - /** - * @brief This enumeration is for specifying the type of request. - */ - enum ERequestAction - { - INVALID, - HTTP_HEAD, - HTTP_GET, - HTTP_PUT, - HTTP_POST, - HTTP_DELETE, - HTTP_MOVE, // Caller will need to set 'Destination' header - REQUEST_ACTION_COUNT - }; - - /** - * @brief Turn the requst action into an http verb. - */ - static std::string actionAsVerb(ERequestAction action); /** * @brief Constructor. * - * @param action One of the ERequestAction enumerations. + * @param action One of the EHTTPMethod enumerations. */ - LLURLRequest(ERequestAction action); + LLURLRequest(EHTTPMethod action); /** * @brief Constructor. * - * @param action One of the ERequestAction enumerations. + * @param action One of the EHTTPMethod enumerations. * @param url The url of the request. It should already be encoded. */ - LLURLRequest(ERequestAction action, const std::string& url); + LLURLRequest(EHTTPMethod action, const std::string& url); /** * @brief Destructor. @@ -123,17 +103,17 @@ public: * */ void setURL(const std::string& url); - std::string getURL() const; + const std::string& getURL() const; /** * @brief Add a header to the http post. * - * The header must be correctly formatted for HTTP requests. This - * provides a raw interface if you know what kind of request you + * This provides a raw interface if you know what kind of request you * will be making during construction of this instance. All * required headers will be automatically constructed, so this is * usually useful for encoding parameters. */ - void addHeader(const char* header); + void addHeader(const std::string& header, const std::string& value = ""); + void addHeaderRaw(const char* header); /** * @brief Check remote server certificate signed by a known root CA. @@ -218,7 +198,7 @@ protected: STATE_HAVE_RESPONSE, }; EState mState; - ERequestAction mAction; + EHTTPMethod mAction; LLURLRequestDetail* mDetail; LLIOPipe::ptr_t mCompletionCallback; S32 mRequestTransferedBytes; @@ -315,7 +295,7 @@ public: // May be called more than once, particularly for redirects and proxy madness. // Ex. a 200 for a connection to https through a proxy, followed by the "real" status // a 3xx for a redirect followed by a "real" status, or more redirects. - virtual void httpStatus(U32 status, const std::string& reason) { } + virtual void httpStatus(S32 status, const std::string& reason) { } virtual void complete( const LLChannelDescriptors& channels, @@ -368,7 +348,7 @@ protected: //@} // value to note if we actually got the response. This value - // depends on correct useage from the LLURLRequest instance. + // depends on correct usage from the LLURLRequest instance. EStatus mRequestStatus; }; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index ae95087377..78b259c3f1 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -113,20 +113,20 @@ namespace { } - virtual void error(U32 status, const std::string& reason) + protected: + virtual void httpFailure() { // don't spam when agent communication disconnected already - if (status != 410) + if (HTTP_GONE != getStatus()) { - LL_WARNS("Messaging") << "error status " << status - << " for message " << mMessageName - << " reason " << reason << llendl; + 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 result(const LLSD& content) + virtual void httpSuccess() { if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR); } diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index 9b298d0c04..b7fdf4f437 100644 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -24,55 +24,76 @@ * $/LicenseInfo$ */ +#ifndef LL_CURL_STUB_CPP +#define LL_CURL_STUB_CPP + + #include "linden_common.h" #include "llcurl.h" +#include "llhttpconstants.cpp" LLCurl::Responder::Responder() { } -void LLCurl::Responder::completed(U32 status, std::basic_string, std::allocator > const &reason, - LLSD const& mContent) +void LLCurl::Responder::httpCompleted() { - if (isGoodStatus(status)) + if (isGoodStatus()) { - result(mContent); + httpSuccess(); } else { - errorWithContent(status, reason, mContent); + httpFailure(); } } -void LLCurl::Responder::completedHeader(unsigned, - std::basic_string, std::allocator > const&, - LLSD const&) +void LLCurl::Responder::completedRaw(LLChannelDescriptors const&, + boost::shared_ptr const&) { } -void LLCurl::Responder::completedRaw(unsigned, - std::basic_string, std::allocator > const&, - LLChannelDescriptors const&, - boost::shared_ptr const&) +void LLCurl::Responder::httpFailure() { } -void LLCurl::Responder::errorWithContent(unsigned, - std::basic_string, std::allocator > const&, - LLSD const&) +LLCurl::Responder::~Responder () { } -LLCurl::Responder::~Responder () +void LLCurl::Responder::httpSuccess() +{ +} + +std::string LLCurl::Responder::dumpResponse() const +{ + return "dumpResponse()"; +} + +void LLCurl::Responder::successResult(const LLSD& content) { + setResult(HTTP_OK, "", content); + httpSuccess(); } -void LLCurl::Responder::error(unsigned, - std::basic_string, std::allocator > const&) +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) +{ + setResult(status, reason, content); + httpFailure(); +} + + +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content) { + setResult(status, reason, content); + httpCompleted(); } -void LLCurl::Responder::result(LLSD const&) +void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) { + mStatus = status; + mReason = reason; + mContent = content; } +#endif diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index 87cbafa404..bdc48ce53d 100644 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -101,7 +101,7 @@ namespace tut if (mSawError) { std::string msg = - llformat("error() called when not expected, status %d", + llformat("httpFailure() called when not expected, status %d", mStatus); fail(msg); } @@ -111,7 +111,7 @@ namespace tut { if (!mSawError) { - fail("error() wasn't called"); + fail("httpFailure() wasn't called"); } } @@ -153,33 +153,26 @@ namespace tut mClient.mResultDeleted = true; } - virtual void error(U32 status, const std::string& reason) + protected: + virtual void httpFailure() { mClient.mSawError = true; - mClient.mStatus = status; - mClient.mReason = reason; + mClient.mStatus = getStatus(); + mClient.mReason = getReason(); } - virtual void result(const LLSD& content) + virtual void httpSuccess() { - mClient.mResult = content; + mClient.mResult = getContent(); } - virtual void completed( - U32 status, const std::string& reason, - const LLSD& content) + virtual void httpCompleted() { - LLHTTPClient::Responder::completed(status, reason, content); - + LLHTTPClient::Responder::httpCompleted(); + mClient.mSawCompleted = true; - } - - virtual void completedHeader( - U32 status, const std::string& reason, - const LLSD& content) - { - mClient.mHeader = content; mClient.mSawCompletedHeader = true; + mClient.mHeader = getResponseHeaders(); } private: diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp index 13ce0a0edd..cc7feeab4f 100644 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -1,6 +1,6 @@ /** - * @file - * @brief + * @file llhttpclientadapter_test.cpp + * @brief Tests for LLHTTPClientAdapter * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code @@ -33,8 +33,8 @@ float const HTTP_REQUEST_EXPIRY_SECS = 1.0F; std::vector get_urls; -std::vector > get_responders; -void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr responder, const LLSD& headers, const F32 timeout) +std::vector< LLCurl::ResponderPtr > get_responders; +void LLHTTPClient::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout) { get_urls.push_back(url); get_responders.push_back(responder); @@ -42,16 +42,30 @@ void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr put_urls; std::vector put_body; -std::vector > put_responders; +std::vector put_headers; +std::vector put_responders; -void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr responder, const LLSD& headers, const F32 timeout) +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 delete_urls; +std::vector 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 { @@ -64,6 +78,9 @@ namespace tut put_urls.clear(); put_responders.clear(); put_body.clear(); + put_headers.clear(); + delete_urls.clear(); + delete_responders.clear(); } }; @@ -73,7 +90,7 @@ namespace tut namespace { - tut::factory tf("LLHTTPClientAdapterData test"); + tut::factory tf("LLHTTPClientAdapterData"); } namespace tut @@ -91,7 +108,7 @@ namespace tut { LLHTTPClientAdapter adapter; - boost::intrusive_ptr responder = new LLCurl::Responder(); + LLCurl::ResponderPtr responder = new LLCurl::Responder(); adapter.get("Made up URL", responder); ensure_equals(get_urls.size(), 1); @@ -103,7 +120,7 @@ namespace tut void object::test<3>() { LLHTTPClientAdapter adapter; - boost::intrusive_ptr responder = new LLCurl::Responder(); + LLCurl::ResponderPtr responder = new LLCurl::Responder(); adapter.get("Made up URL", responder); @@ -117,7 +134,7 @@ namespace tut { LLHTTPClientAdapter adapter; - boost::intrusive_ptr responder = new LLCurl::Responder(); + LLCurl::ResponderPtr responder = new LLCurl::Responder(); LLSD body; body["TestBody"] = "Foobar"; @@ -133,7 +150,7 @@ namespace tut { LLHTTPClientAdapter adapter; - boost::intrusive_ptr responder = new LLCurl::Responder(); + LLCurl::ResponderPtr responder = new LLCurl::Responder(); LLSD body; body["TestBody"] = "Foobar"; @@ -150,7 +167,7 @@ namespace tut { LLHTTPClientAdapter adapter; - boost::intrusive_ptr responder = new LLCurl::Responder(); + LLCurl::ResponderPtr responder = new LLCurl::Responder(); LLSD body; body["TestBody"] = "Foobar"; @@ -160,5 +177,45 @@ namespace tut 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/llmime_test.cpp b/indra/llmessage/tests/llmime_test.cpp index aed5c4589c..f8bf03bbcb 100644 --- a/indra/llmessage/tests/llmime_test.cpp +++ b/indra/llmessage/tests/llmime_test.cpp @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llsdserialize.h" +#include "llhttpconstants.cpp" #include "../llmime.h" diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp deleted file mode 100644 index 5b89f2a8c6..0000000000 --- a/indra/llmessage/tests/llregionpresenceverifier_test.cpp +++ /dev/null @@ -1,108 +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 "linden_common.h" - -#include "../test/lltut.h" -#include "llregionpresenceverifier.h" -#include "llcurl_stub.cpp" -#include "llhost.cpp" -#include "net.cpp" -#include "lltesthttpclientadapter.cpp" - -class LLTestResponse : public LLRegionPresenceVerifier::Response -{ -public: - - virtual bool checkValidity(const LLSD& content) const - { - return true; - } - - virtual void onRegionVerified(const LLSD& region_details) - { - } - - virtual void onRegionVerificationFailed() - { - } - - virtual LLHTTPClientInterface& getHttpClient() - { - return mHttpInterface; - } - - LLTestHTTPClientAdapter mHttpInterface; -}; - -namespace tut -{ - struct LLRegionPresenceVerifierData - { - LLRegionPresenceVerifierData() : - mResponse(new LLTestResponse()), - mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse), - LLSD(), 3) - { - } - - LLTestResponse* mResponse; - LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder; - }; - - typedef test_group factory; - typedef factory::object object; -} - -namespace -{ - tut::factory tf("LLRegionPresenceVerifier"); -} - -namespace tut -{ - // Test that VerifiedDestinationResponder does retry - // on error when shouldRetry returns true. - template<> template<> - void object::test<1>() - { - mResponder.error(500, "Internal server error"); - ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1); - } - - // Test that VerifiedDestinationResponder only retries - // on error until shouldRetry returns false. - template<> template<> - void object::test<2>() - { - mResponder.error(500, "Internal server error"); - mResponder.error(500, "Internal server error"); - mResponder.error(500, "Internal server error"); - mResponder.error(500, "Internal server error"); - ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3); - } -} - -- cgit v1.2.3 From beeefb45269f45ea717f58b30a0985951ae23c20 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 4 Apr 2013 21:50:45 +0000 Subject: Renaming HTTP_HEADER_* into HTTP_IN_HEADER_* and HTTP_OUT_HEADER_* to make it more clear which header strings should be used for incoming vs outgoing situations. Using constants for commonly used llhttpnode context strings. --- indra/llmessage/CMakeLists.txt | 3 - indra/llmessage/llavatarnamecache.cpp | 8 +- indra/llmessage/llcurl.cpp | 41 +- indra/llmessage/llcurl.h | 4 +- indra/llmessage/llhttpclient.cpp | 66 +-- indra/llmessage/llhttpclientadapter.cpp | 6 +- indra/llmessage/llhttpconstants.cpp | 139 ++--- indra/llmessage/llhttpconstants.h | 139 ++--- indra/llmessage/llhttpnode.cpp | 14 +- indra/llmessage/llhttpnode.h | 19 +- indra/llmessage/lliohttpserver.cpp | 28 +- indra/llmessage/lliohttpserver.h | 7 - indra/llmessage/lliosocket.cpp | 7 +- indra/llmessage/lliosocket.h | 3 + indra/llmessage/llmime.cpp | 628 --------------------- indra/llmessage/llmime.h | 292 ---------- indra/llmessage/llsdappservices.cpp | 10 +- indra/llmessage/llsdhttpserver.cpp | 2 +- indra/llmessage/llsdrpcclient.h | 4 +- indra/llmessage/lltrustedmessageservice.cpp | 6 +- indra/llmessage/lltrustedmessageservice.h | 4 + indra/llmessage/llurlrequest.cpp | 11 +- indra/llmessage/llurlrequest.h | 12 +- indra/llmessage/message.cpp | 2 +- indra/llmessage/tests/llhttpclient_test.cpp | 2 - indra/llmessage/tests/llhttpnode_stub.cpp | 112 ++++ indra/llmessage/tests/llmime_test.cpp | 446 --------------- .../tests/lltrustedmessageservice_test.cpp | 1 + 28 files changed, 382 insertions(+), 1634 deletions(-) delete mode 100644 indra/llmessage/llmime.cpp delete mode 100644 indra/llmessage/llmime.h create mode 100644 indra/llmessage/tests/llhttpnode_stub.cpp delete mode 100644 indra/llmessage/tests/llmime_test.cpp (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 181718f465..6fa2669be6 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -59,7 +59,6 @@ set(llmessage_SOURCE_FILES llmessagetemplate.cpp llmessagetemplateparser.cpp llmessagethrottle.cpp - llmime.cpp llnamevalue.cpp llnullcipher.cpp llpacketack.cpp @@ -154,7 +153,6 @@ set(llmessage_HEADER_FILES llmessagetemplate.h llmessagetemplateparser.h llmessagethrottle.h - llmime.h llmsgvariabletype.h llnamevalue.h llnullcipher.h @@ -266,7 +264,6 @@ if (LL_TESTS) 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(llmime "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 1d01b69969..e0b71acbd5 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -711,13 +711,9 @@ bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *exp // Allow the header to override the default std::string cache_control; - if (headers.has(HTTP_HEADER_CACHE_CONTROL)) + if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL)) { - cache_control = headers[HTTP_HEADER_CACHE_CONTROL].asString(); - } - else if (headers.has(HTTP_HEADER_LOWER_CACHE_CONTROL)) - { - cache_control = headers[HTTP_HEADER_LOWER_CACHE_CONTROL].asString(); + cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString(); } if (!cache_control.empty()) diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 1269b6bc5d..68282626ae 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -156,9 +156,9 @@ std::string LLCurl::Responder::dumpResponse() const << "[status:" << mStatus << "] " << "[reason:" << mReason << "] "; - if (mResponseHeaders.has(HTTP_HEADER_CONTENT_TYPE)) + if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) { - s << "[content-type:" << mResponseHeaders[HTTP_HEADER_CONTENT_TYPE] << "] "; + s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] "; } s << "[content:" << mContent << "]"; @@ -211,34 +211,19 @@ void LLCurl::Responder::setResponseHeader(const std::string& header, const std:: mResponseHeaders[header] = value; } -const std::string& LLCurl::Responder::getResponseHeader(const std::string& header, bool check_lower) const +const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const { if (mResponseHeaders.has(header)) { return mResponseHeaders[header].asStringRef(); } - if (check_lower) - { - std::string header_lower(header); - LLStringUtil::toLower(header_lower); - if (mResponseHeaders.has(header_lower)) - { - return mResponseHeaders[header_lower].asStringRef(); - } - } static const std::string empty; return empty; } -bool LLCurl::Responder::hasResponseHeader(const std::string& header, bool check_lower) const +bool LLCurl::Responder::hasResponseHeader(const std::string& header) const { if (mResponseHeaders.has(header)) return true; - if (check_lower) - { - std::string header_lower(header); - LLStringUtil::toLower(header_lower); - return mResponseHeaders.has(header_lower); - } return false; } @@ -256,7 +241,7 @@ void LLCurl::Responder::completedRaw( { parsed=false; } - // Try to parse body as llsd, no matter what 'Content-Type' says. + // Try to parse body as llsd, no matter what 'content-type' says. else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors)) { parsed=false; @@ -271,8 +256,8 @@ void LLCurl::Responder::completedRaw( } } - // Only emit an warning if we failed to parse when 'Content-Type' == 'application/llsd+xml' - if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_HEADER_CONTENT_TYPE))) + // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' + if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE))) { llwarns << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] " << "(" << mReason << ") body: " << debug_body << llendl; @@ -643,8 +628,8 @@ void LLCurl::Easy::prepRequest(const std::string& url, if (!post) { // *TODO: Should this be set to 'Keep-Alive' ? - slist_append(HTTP_HEADER_CONNECTION, "keep-alive"); - slist_append(HTTP_HEADER_KEEP_ALIVE, "300"); + slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive"); + slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300"); // Accept and other headers for (std::vector::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) @@ -1242,12 +1227,12 @@ bool LLCurlRequest::getByteRange(const std::string& url, if (length > 0) { std::string range = llformat("bytes=%d-%d", offset,offset+length-1); - easy->slist_append(HTTP_HEADER_RANGE, range); + easy->slist_append(HTTP_OUT_HEADER_RANGE, range); } else if (offset > 0) { std::string range = llformat("bytes=%d-", offset); - easy->slist_append(HTTP_HEADER_RANGE, range); + easy->slist_append(HTTP_OUT_HEADER_RANGE, range); } easy->setHeaders(); bool res = addEasy(easy); @@ -1274,7 +1259,7 @@ bool LLCurlRequest::post(const std::string& url, easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); easy->setHeaders(); lldebugs << "POSTING: " << bytes << " bytes." << llendl; @@ -1302,7 +1287,7 @@ bool LLCurlRequest::post(const std::string& url, easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); + easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); easy->setHeaders(); lldebugs << "POSTING: " << bytes << " bytes." << llendl; diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index c72e1e493a..8a65c783be 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -91,8 +91,8 @@ public: S32 getStatus() const { return mStatus; } const std::string& getReason() const { return mReason; } const LLSD& getContent() const { return mContent; } - bool hasResponseHeader(const std::string& header, bool check_lower=false) const; - const std::string& getResponseHeader(const std::string& header, bool check_lower=true) const; + bool hasResponseHeader(const std::string& header) const; + const std::string& getResponseHeader(const std::string& header) const; const LLSD& getResponseHeaders() const { return mResponseHeaders; } const std::string& getURL() const { return mURL; } EHTTPMethod getHTTPMethod() const { return mHTTPMethod; } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index a4a1f02cd3..5830a5eca0 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -248,45 +248,45 @@ static void request( req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); - + LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL; // Insert custom headers if the caller sent any if (headers.isMap()) { - if (headers.has(HTTP_HEADER_COOKIE)) + if (headers.has(HTTP_OUT_HEADER_COOKIE)) { req->allowCookies(); } - LLSD::map_const_iterator iter = headers.beginMap(); - LLSD::map_const_iterator end = headers.endMap(); - - for (; iter != end; ++iter) - { - //if the header is "Pragma" with no value - //the caller intends to force libcurl to drop - //the Pragma header it so gratuitously inserts - //Before inserting the header, force libcurl - //to not use the proxy (read: llurlrequest.cpp) - if ((iter->first == HTTP_HEADER_PRAGMA) && (iter->second.asString().empty())) - { - req->useProxy(false); - } - LL_DEBUGS("LLHTTPClient") << "header = " << iter->first - << ": " << iter->second.asString() << LL_ENDL; - req->addHeader(iter->first, iter->second.asString()); - } - } + LLSD::map_const_iterator iter = headers.beginMap(); + LLSD::map_const_iterator end = headers.endMap(); + + for (; iter != end; ++iter) + { + //if the header is "Pragma" with no value + //the caller intends to force libcurl to drop + //the Pragma header it so gratuitously inserts + //Before inserting the header, force libcurl + //to not use the proxy (read: llurlrequest.cpp) + if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty())) + { + req->useProxy(false); + } + LL_DEBUGS("LLHTTPClient") << "header = " << iter->first + << ": " << iter->second.asString() << LL_ENDL; + req->addHeader(iter->first, iter->second.asString()); + } + } // Check to see if we have already set Accept or not. If no one // set it, set it to application/llsd+xml since that's what we // almost always want. if( method != HTTP_PUT && method != HTTP_POST ) { - if(!headers.has(HTTP_HEADER_ACCEPT)) + if(!headers.has(HTTP_OUT_HEADER_ACCEPT)) { - req->addHeader(HTTP_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); + req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); } } @@ -301,21 +301,21 @@ static void request( if (method == HTTP_POST && gMessageSystem) { req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", - gMessageSystem->mPort)); - } + gMessageSystem->mPort)); + } if (method == HTTP_PUT || method == HTTP_POST) { - if(!headers.has(HTTP_HEADER_CONTENT_TYPE)) + if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE)) { // If the Content-Type header was passed in, it has // already been added as a header through req->addHeader // in the loop above. We defer to the caller's wisdom, but // if they did not specify a Content-Type, then ask the // injector. - req->addHeader(HTTP_HEADER_CONTENT_TYPE, body_injector->contentType()); + req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType()); } - chain.push_back(LLIOPipe::ptr_t(body_injector)); + chain.push_back(LLIOPipe::ptr_t(body_injector)); } chain.push_back(LLIOPipe::ptr_t(req)); @@ -336,7 +336,7 @@ void LLHTTPClient::getByteRange( if(offset > 0 || bytes > 0) { std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1); - headers[HTTP_HEADER_RANGE] = range; + headers[HTTP_OUT_HEADER_RANGE] = range; } request(url,HTTP_GET, NULL, responder, timeout, headers); } @@ -483,19 +483,19 @@ static LLSD blocking_request( curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str()); //copied from PHP libs, correct? headers_list = curl_slist_append(headers_list, - llformat("%s: %s", HTTP_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); + llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); // copied from llurlrequest.cpp // it appears that apache2.2.3 or django in etch is busted. If // we do not clear the expect header, we get a 500. May be // limited to django/mod_wsgi. - headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_HEADER_EXPECT.c_str()).c_str()); + headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str()); } // * Do the action using curl, handle results lldebugs << "HTTP body: " << body_str << llendl; headers_list = curl_slist_append(headers_list, - llformat("%s: %s", HTTP_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); + llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str()); CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list); if ( curl_result != CURLE_OK ) { @@ -617,7 +617,7 @@ void LLHTTPClient::move( const F32 timeout) { LLSD headers = hdrs; - headers[HTTP_HEADER_DESTINATION] = destination; + headers[HTTP_OUT_HEADER_DESTINATION] = destination; request(url, HTTP_MOVE, NULL, responder, timeout, headers); } diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index aaa31e36fc..b56a804f94 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -36,17 +36,17 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo 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_HEADER_PRAGMA] = " "; + 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_HEADER_PRAGMA)) + if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA)) { // as above - empty_pragma_header[HTTP_HEADER_PRAGMA] = " "; + empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " "; } LLHTTPClient::get(url, responder, empty_pragma_header); } diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp index 2134024a14..1995fad1e5 100644 --- a/indra/llmessage/llhttpconstants.cpp +++ b/indra/llmessage/llhttpconstants.cpp @@ -37,72 +37,76 @@ // for curl_getdate() (apparently parsing RFC 1123 dates is hard) #include -const std::string HTTP_HEADER_ACCEPT("Accept"); -const std::string HTTP_HEADER_ACCEPT_CHARSET("Accept-Charset"); -const std::string HTTP_HEADER_ACCEPT_ENCODING("Accept-Encoding"); -const std::string HTTP_HEADER_ACCEPT_LANGUAGE("Accept-Language"); -const std::string HTTP_HEADER_ACCEPT_RANGES("Accept-Ranges"); -const std::string HTTP_HEADER_AGE("Age"); -const std::string HTTP_HEADER_ALLOW("Allow"); -const std::string HTTP_HEADER_AUTHORIZATION("Authorization"); -const std::string HTTP_HEADER_CACHE_CONTROL("Cache-Control"); -const std::string HTTP_HEADER_CONNECTION("Connection"); -const std::string HTTP_HEADER_CONTENT_DESCRIPTION("Content-Description"); -const std::string HTTP_HEADER_CONTENT_ENCODING("Content-Encoding"); -const std::string HTTP_HEADER_CONTENT_ID("Content-ID"); -const std::string HTTP_HEADER_CONTENT_LANGUAGE("Content-Language"); -const std::string HTTP_HEADER_CONTENT_LENGTH("Content-Length"); -const std::string HTTP_HEADER_CONTENT_LOCATION("Content-Location"); -const std::string HTTP_HEADER_CONTENT_MD5("Content-MD5"); -const std::string HTTP_HEADER_CONTENT_RANGE("Content-Range"); -const std::string HTTP_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding"); -const std::string HTTP_HEADER_CONTENT_TYPE("Content-Type"); -const std::string HTTP_HEADER_COOKIE("Cookie"); -const std::string HTTP_HEADER_DATE("Date"); -const std::string HTTP_HEADER_DESTINATION("Destination"); -const std::string HTTP_HEADER_ETAG("ETag"); -const std::string HTTP_HEADER_EXPECT("Expect"); -const std::string HTTP_HEADER_EXPIRES("Expires"); -const std::string HTTP_HEADER_FROM("From"); -const std::string HTTP_HEADER_HOST("Host"); -const std::string HTTP_HEADER_IF_MATCH("If-Match"); -const std::string HTTP_HEADER_IF_MODIFIED_SINCE("If-Modified-Since"); -const std::string HTTP_HEADER_IF_NONE_MATCH("If-None-Match"); -const std::string HTTP_HEADER_IF_RANGE("If-Range"); -const std::string HTTP_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since"); -const std::string HTTP_HEADER_KEEP_ALIVE("Keep-Alive"); -const std::string HTTP_HEADER_LAST_MODIFIED("Last-Modified"); -const std::string HTTP_HEADER_LOCATION("Location"); -const std::string HTTP_HEADER_MAX_FORWARDS("Max-Forwards"); -const std::string HTTP_HEADER_MIME_VERSION("MIME-Version"); -const std::string HTTP_HEADER_PRAGMA("Pragma"); -const std::string HTTP_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate"); -const std::string HTTP_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization"); -const std::string HTTP_HEADER_RANGE("Range"); -const std::string HTTP_HEADER_REFERER("Referer"); -const std::string HTTP_HEADER_RETRY_AFTER("Retry-After"); -const std::string HTTP_HEADER_SERVER("Server"); -const std::string HTTP_HEADER_SET_COOKIE("Set-Cookie"); -const std::string HTTP_HEADER_TE("TE"); -const std::string HTTP_HEADER_TRAILER("Trailer"); -const std::string HTTP_HEADER_TRANSFER_ENCODING("Transfer-Encoding"); -const std::string HTTP_HEADER_UPGRADE("Upgrade"); -const std::string HTTP_HEADER_USER_AGENT("User-Agent"); -const std::string HTTP_HEADER_VARY("Vary"); -const std::string HTTP_HEADER_VIA("Via"); -const std::string HTTP_HEADER_WARNING("Warning"); -const std::string HTTP_HEADER_WWW_AUTHENTICATE("WWW-Authenticate"); - - -// Sadly, our proxied headers do not follow http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html -// We need to deal with lowercase headers -const std::string HTTP_HEADER_LOWER_ACCEPT_LANGUAGE("accept-language"); -const std::string HTTP_HEADER_LOWER_CACHE_CONTROL("cache-control"); -const std::string HTTP_HEADER_LOWER_CONTENT_LENGTH("content-length"); -const std::string HTTP_HEADER_LOWER_CONTENT_TYPE("content-type"); -const std::string HTTP_HEADER_LOWER_HOST("host"); -const std::string HTTP_HEADER_LOWER_USER_AGENT("user-agent"); -const std::string HTTP_HEADER_LOWER_X_FORWARDED_FOR("x-forwarded-for"); +// Outgoing headers. Do *not* use these to check incoming headers. +// For incoming headers, use the lower-case headers, below. +const std::string HTTP_OUT_HEADER_ACCEPT("Accept"); +const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET("Accept-Charset"); +const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING("Accept-Encoding"); +const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE("Accept-Language"); +const std::string HTTP_OUT_HEADER_ACCEPT_RANGES("Accept-Ranges"); +const std::string HTTP_OUT_HEADER_AGE("Age"); +const std::string HTTP_OUT_HEADER_ALLOW("Allow"); +const std::string HTTP_OUT_HEADER_AUTHORIZATION("Authorization"); +const std::string HTTP_OUT_HEADER_CACHE_CONTROL("Cache-Control"); +const std::string HTTP_OUT_HEADER_CONNECTION("Connection"); +const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION("Content-Description"); +const std::string HTTP_OUT_HEADER_CONTENT_ENCODING("Content-Encoding"); +const std::string HTTP_OUT_HEADER_CONTENT_ID("Content-ID"); +const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE("Content-Language"); +const std::string HTTP_OUT_HEADER_CONTENT_LENGTH("Content-Length"); +const std::string HTTP_OUT_HEADER_CONTENT_LOCATION("Content-Location"); +const std::string HTTP_OUT_HEADER_CONTENT_MD5("Content-MD5"); +const std::string HTTP_OUT_HEADER_CONTENT_RANGE("Content-Range"); +const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding"); +const std::string HTTP_OUT_HEADER_CONTENT_TYPE("Content-Type"); +const std::string HTTP_OUT_HEADER_COOKIE("Cookie"); +const std::string HTTP_OUT_HEADER_DATE("Date"); +const std::string HTTP_OUT_HEADER_DESTINATION("Destination"); +const std::string HTTP_OUT_HEADER_ETAG("ETag"); +const std::string HTTP_OUT_HEADER_EXPECT("Expect"); +const std::string HTTP_OUT_HEADER_EXPIRES("Expires"); +const std::string HTTP_OUT_HEADER_FROM("From"); +const std::string HTTP_OUT_HEADER_HOST("Host"); +const std::string HTTP_OUT_HEADER_IF_MATCH("If-Match"); +const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE("If-Modified-Since"); +const std::string HTTP_OUT_HEADER_IF_NONE_MATCH("If-None-Match"); +const std::string HTTP_OUT_HEADER_IF_RANGE("If-Range"); +const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since"); +const std::string HTTP_OUT_HEADER_KEEP_ALIVE("Keep-Alive"); +const std::string HTTP_OUT_HEADER_LAST_MODIFIED("Last-Modified"); +const std::string HTTP_OUT_HEADER_LOCATION("Location"); +const std::string HTTP_OUT_HEADER_MAX_FORWARDS("Max-Forwards"); +const std::string HTTP_OUT_HEADER_MIME_VERSION("MIME-Version"); +const std::string HTTP_OUT_HEADER_PRAGMA("Pragma"); +const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate"); +const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization"); +const std::string HTTP_OUT_HEADER_RANGE("Range"); +const std::string HTTP_OUT_HEADER_REFERER("Referer"); +const std::string HTTP_OUT_HEADER_RETRY_AFTER("Retry-After"); +const std::string HTTP_OUT_HEADER_SERVER("Server"); +const std::string HTTP_OUT_HEADER_SET_COOKIE("Set-Cookie"); +const std::string HTTP_OUT_HEADER_TE("TE"); +const std::string HTTP_OUT_HEADER_TRAILER("Trailer"); +const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING("Transfer-Encoding"); +const std::string HTTP_OUT_HEADER_UPGRADE("Upgrade"); +const std::string HTTP_OUT_HEADER_USER_AGENT("User-Agent"); +const std::string HTTP_OUT_HEADER_VARY("Vary"); +const std::string HTTP_OUT_HEADER_VIA("Via"); +const std::string HTTP_OUT_HEADER_WARNING("Warning"); +const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE("WWW-Authenticate"); + +// Incoming headers are normalized to lower-case. +const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE("accept-language"); +const std::string HTTP_IN_HEADER_CACHE_CONTROL("cache-control"); +const std::string HTTP_IN_HEADER_CONTENT_LENGTH("content-length"); +const std::string HTTP_IN_HEADER_CONTENT_LOCATION("content-location"); +const std::string HTTP_IN_HEADER_CONTENT_TYPE("content-type"); +const std::string HTTP_IN_HEADER_HOST("host"); +const std::string HTTP_IN_HEADER_LOCATION("location"); +const std::string HTTP_IN_HEADER_RETRY_AFTER("retry-after"); +const std::string HTTP_IN_HEADER_SET_COOKIE("set-cookie"); +const std::string HTTP_IN_HEADER_USER_AGENT("user-agent"); +const std::string HTTP_IN_HEADER_X_FORWARDED_FOR("x-forwarded-for"); const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml"); const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream"); @@ -121,6 +125,9 @@ const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg"); const std::string HTTP_CONTENT_IMAGE_PNG("image/png"); const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp"); +const std::string HTTP_NO_CACHE("no-cache"); +const std::string HTTP_NO_CACHE_CONTROL("no-cache, max-age=0"); + const std::string HTTP_VERB_INVALID("(invalid)"); const std::string HTTP_VERB_HEAD("HEAD"); const std::string HTTP_VERB_GET("GET"); diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h index 34263e17c8..8cc3459654 100644 --- a/indra/llmessage/llhttpconstants.h +++ b/indra/llmessage/llhttpconstants.h @@ -132,71 +132,76 @@ bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_w //// HTTP Headers ///// -extern const std::string HTTP_HEADER_ACCEPT; -extern const std::string HTTP_HEADER_ACCEPT_CHARSET; -extern const std::string HTTP_HEADER_ACCEPT_ENCODING; -extern const std::string HTTP_HEADER_ACCEPT_LANGUAGE; -extern const std::string HTTP_HEADER_ACCEPT_RANGES; -extern const std::string HTTP_HEADER_AGE; -extern const std::string HTTP_HEADER_ALLOW; -extern const std::string HTTP_HEADER_AUTHORIZATION; -extern const std::string HTTP_HEADER_CACHE_CONTROL; -extern const std::string HTTP_HEADER_CONNECTION; -extern const std::string HTTP_HEADER_CONTENT_DESCRIPTION; -extern const std::string HTTP_HEADER_CONTENT_ENCODING; -extern const std::string HTTP_HEADER_CONTENT_ID; -extern const std::string HTTP_HEADER_CONTENT_LANGUAGE; -extern const std::string HTTP_HEADER_CONTENT_LENGTH; -extern const std::string HTTP_HEADER_CONTENT_LOCATION; -extern const std::string HTTP_HEADER_CONTENT_MD5; -extern const std::string HTTP_HEADER_CONTENT_RANGE; -extern const std::string HTTP_HEADER_CONTENT_TRANSFER_ENCODING; -extern const std::string HTTP_HEADER_CONTENT_TYPE; -extern const std::string HTTP_HEADER_COOKIE; -extern const std::string HTTP_HEADER_DATE; -extern const std::string HTTP_HEADER_DESTINATION; -extern const std::string HTTP_HEADER_ETAG; -extern const std::string HTTP_HEADER_EXPECT; -extern const std::string HTTP_HEADER_EXPIRES; -extern const std::string HTTP_HEADER_FROM; -extern const std::string HTTP_HEADER_HOST; -extern const std::string HTTP_HEADER_IF_MATCH; -extern const std::string HTTP_HEADER_IF_MODIFIED_SINCE; -extern const std::string HTTP_HEADER_IF_NONE_MATCH; -extern const std::string HTTP_HEADER_IF_RANGE; -extern const std::string HTTP_HEADER_IF_UNMODIFIED_SINCE; -extern const std::string HTTP_HEADER_KEEP_ALIVE; -extern const std::string HTTP_HEADER_LAST_MODIFIED; -extern const std::string HTTP_HEADER_LOCATION; -extern const std::string HTTP_HEADER_MAX_FORWARDS; -extern const std::string HTTP_HEADER_MIME_VERSION; -extern const std::string HTTP_HEADER_PRAGMA; -extern const std::string HTTP_HEADER_PROXY_AUTHENTICATE; -extern const std::string HTTP_HEADER_PROXY_AUTHORIZATION; -extern const std::string HTTP_HEADER_RANGE; -extern const std::string HTTP_HEADER_REFERER; -extern const std::string HTTP_HEADER_RETRY_AFTER; -extern const std::string HTTP_HEADER_SERVER; -extern const std::string HTTP_HEADER_SET_COOKIE; -extern const std::string HTTP_HEADER_TE; -extern const std::string HTTP_HEADER_TRAILER; -extern const std::string HTTP_HEADER_TRANSFER_ENCODING; -extern const std::string HTTP_HEADER_UPGRADE; -extern const std::string HTTP_HEADER_USER_AGENT; -extern const std::string HTTP_HEADER_VARY; -extern const std::string HTTP_HEADER_VIA; -extern const std::string HTTP_HEADER_WARNING; -extern const std::string HTTP_HEADER_WWW_AUTHENTICATE; - -// Sadly, our proxied headers do not follow http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html -// We need to deal with lowercase headers -extern const std::string HTTP_HEADER_LOWER_ACCEPT_LANGUAGE; -extern const std::string HTTP_HEADER_LOWER_CACHE_CONTROL; -extern const std::string HTTP_HEADER_LOWER_CONTENT_LENGTH; -extern const std::string HTTP_HEADER_LOWER_CONTENT_TYPE; -extern const std::string HTTP_HEADER_LOWER_HOST; -extern const std::string HTTP_HEADER_LOWER_USER_AGENT; -extern const std::string HTTP_HEADER_LOWER_X_FORWARDED_FOR; +// Outgoing headers. Do *not* use these to check incoming headers. +// For incoming headers, use the lower-case headers, below. +extern const std::string HTTP_OUT_HEADER_ACCEPT; +extern const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET; +extern const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING; +extern const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_OUT_HEADER_ACCEPT_RANGES; +extern const std::string HTTP_OUT_HEADER_AGE; +extern const std::string HTTP_OUT_HEADER_ALLOW; +extern const std::string HTTP_OUT_HEADER_AUTHORIZATION; +extern const std::string HTTP_OUT_HEADER_CACHE_CONTROL; +extern const std::string HTTP_OUT_HEADER_CONNECTION; +extern const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION; +extern const std::string HTTP_OUT_HEADER_CONTENT_ENCODING; +extern const std::string HTTP_OUT_HEADER_CONTENT_ID; +extern const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE; +extern const std::string HTTP_OUT_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_OUT_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_OUT_HEADER_CONTENT_MD5; +extern const std::string HTTP_OUT_HEADER_CONTENT_RANGE; +extern const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING; +extern const std::string HTTP_OUT_HEADER_CONTENT_TYPE; +extern const std::string HTTP_OUT_HEADER_COOKIE; +extern const std::string HTTP_OUT_HEADER_DATE; +extern const std::string HTTP_OUT_HEADER_DESTINATION; +extern const std::string HTTP_OUT_HEADER_ETAG; +extern const std::string HTTP_OUT_HEADER_EXPECT; +extern const std::string HTTP_OUT_HEADER_EXPIRES; +extern const std::string HTTP_OUT_HEADER_FROM; +extern const std::string HTTP_OUT_HEADER_HOST; +extern const std::string HTTP_OUT_HEADER_IF_MATCH; +extern const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE; +extern const std::string HTTP_OUT_HEADER_IF_NONE_MATCH; +extern const std::string HTTP_OUT_HEADER_IF_RANGE; +extern const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE; +extern const std::string HTTP_OUT_HEADER_KEEP_ALIVE; +extern const std::string HTTP_OUT_HEADER_LAST_MODIFIED; +extern const std::string HTTP_OUT_HEADER_LOCATION; +extern const std::string HTTP_OUT_HEADER_MAX_FORWARDS; +extern const std::string HTTP_OUT_HEADER_MIME_VERSION; +extern const std::string HTTP_OUT_HEADER_PRAGMA; +extern const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE; +extern const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION; +extern const std::string HTTP_OUT_HEADER_RANGE; +extern const std::string HTTP_OUT_HEADER_REFERER; +extern const std::string HTTP_OUT_HEADER_RETRY_AFTER; +extern const std::string HTTP_OUT_HEADER_SERVER; +extern const std::string HTTP_OUT_HEADER_SET_COOKIE; +extern const std::string HTTP_OUT_HEADER_TE; +extern const std::string HTTP_OUT_HEADER_TRAILER; +extern const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING; +extern const std::string HTTP_OUT_HEADER_UPGRADE; +extern const std::string HTTP_OUT_HEADER_USER_AGENT; +extern const std::string HTTP_OUT_HEADER_VARY; +extern const std::string HTTP_OUT_HEADER_VIA; +extern const std::string HTTP_OUT_HEADER_WARNING; +extern const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE; + +// Incoming headers are normalized to lower-case. +extern const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_IN_HEADER_CACHE_CONTROL; +extern const std::string HTTP_IN_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_IN_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_IN_HEADER_CONTENT_TYPE; +extern const std::string HTTP_IN_HEADER_HOST; +extern const std::string HTTP_IN_HEADER_LOCATION; +extern const std::string HTTP_IN_HEADER_RETRY_AFTER; +extern const std::string HTTP_IN_HEADER_SET_COOKIE; +extern const std::string HTTP_IN_HEADER_USER_AGENT; +extern const std::string HTTP_IN_HEADER_X_FORWARDED_FOR; //// HTTP Content Types //// @@ -217,4 +222,8 @@ extern const std::string HTTP_CONTENT_IMAGE_JPEG; extern const std::string HTTP_CONTENT_IMAGE_PNG; extern const std::string HTTP_CONTENT_IMAGE_BMP; +//// HTTP Cache Settings //// +extern const std::string HTTP_NO_CACHE; +extern const std::string HTTP_NO_CACHE_CONTROL; + #endif diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index e3b42b1b16..c0c3d0bcbe 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -31,9 +31,14 @@ #include "llstl.h" #include "llhttpconstants.h" -#include "lliohttpserver.h" // for string constants -static const std::string CONTEXT_WILDCARD("wildcard"); +const std::string CONTEXT_HEADERS("headers"); +const std::string CONTEXT_PATH("path"); +const std::string CONTEXT_QUERY_STRING("query-string"); +const std::string CONTEXT_REQUEST("request"); +const std::string CONTEXT_RESPONSE("response"); +const std::string CONTEXT_VERB("verb"); +const std::string CONTEXT_WILDCARD("wildcard"); /** * LLHTTPNode @@ -177,9 +182,8 @@ void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL; // default implementation constructs an url to the documentation. - // *TODO: Check for 'Host' header instead of 'host' header? std::string host( - context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_HEADER_LOWER_HOST].asString()); + context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString()); if(host.empty()) { response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header"); @@ -187,7 +191,7 @@ void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const } std::ostringstream ostr; ostr << "http://" << host << "/web/server/api"; - ostr << context[CONTEXT_REQUEST]["path"].asString(); + ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString(); static const std::string DOC_HEADER("X-Documentation-URL"); response->addHeader(DOC_HEADER, ostr.str()); response->status(HTTP_OK, "OK"); diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index 2539eec6c3..1144d88be1 100644 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -31,6 +31,17 @@ #include "llrefcount.h" #include "llsd.h" +// common strings use for populating the context. basically 'request', +// 'wildcard', and 'headers'. +extern const std::string CONTEXT_HEADERS; +extern const std::string CONTEXT_PATH; +extern const std::string CONTEXT_QUERY_STRING; +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_RESPONSE; +extern const std::string CONTEXT_VERB; +extern const std::string CONTEXT_WILDCARD; + + class LLChainIOFactory; /** @@ -125,7 +136,7 @@ public: virtual void methodNotAllowed(); /** - * @breif Add a name: value http header. + * @brief Add a name: value http header. * * No effort is made to ensure the response is a valid http * header. @@ -194,15 +205,15 @@ public: name, and return true if the name will construct to a valid url. For convenience, the getChild() method above will automatically insert the name in - context["request"]["wildcard"][key] if this method returns true. + context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true. For example, the node "agent//detail" will set - context["request"]["wildcard"]["agent_id"] eqaul to the value + context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value found during traversal. */ const LLHTTPNode* traverse(const std::string& path, LLSD& context) const; /**< find a node, if any, that can service this path - set up context["request"] information + set up context[CONTEXT_REQUEST] information */ //@} diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 509719786c..293e74d0da 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -50,10 +50,6 @@ #include static const char HTTP_VERSION_STR[] = "HTTP/1.0"; -const std::string CONTEXT_REQUEST("request"); -const std::string CONTEXT_RESPONSE("response"); -const std::string CONTEXT_VERB("verb"); -const std::string CONTEXT_HEADERS("headers"); static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL; static void* sTimingCallbackData = NULL; @@ -241,7 +237,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( // Log all HTTP transactions. // TODO: Add a way to log these to their own file instead of indra.log // It is just too spammy to be in indra.log. - lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString() + lldebugs << verb << " " << context[CONTEXT_REQUEST][CONTEXT_PATH].asString() << " " << mStatusCode << " " << mStatusMessage << " " << delta << "s" << llendl; @@ -268,7 +264,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( case STATE_GOOD_RESULT: { LLSD headers = mHeaders; - headers[HTTP_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; LLBufferStream ostr(channels, buffer.get()); LLSDSerialize::toXML(mResult, ostr); @@ -279,7 +275,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( case STATE_STATUS_RESULT: { LLSD headers = mHeaders; - headers[HTTP_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN; context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage; @@ -300,7 +296,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( case STATE_EXTENDED_LLSD_RESULT: { LLSD headers = mHeaders; - headers[HTTP_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; + headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; LLBufferStream ostr(channels, buffer.get()); @@ -489,7 +485,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( S32 content_length = buffer->countAfter(channels.in(), NULL); if(0 < content_length) { - ostr << HTTP_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n"; + ostr << HTTP_OUT_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n"; } // *NOTE: This guard can go away once the LLSD static map // iterator is available. Phoenix. 2008-05-09 @@ -795,7 +791,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( std::string name(buf, pos_colon - buf); std::string value(pos_colon + 2); LLStringUtil::toLower(name); - if(HTTP_HEADER_LOWER_CONTENT_LENGTH == name) + if(HTTP_IN_HEADER_CONTENT_LENGTH == name) { lldebugs << "Content-Length: " << value << llendl; mContentLength = atoi(value.c_str()); @@ -870,12 +866,12 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( // HTTP headers. LLPumpIO::chain_t chain; chain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); - context[CONTEXT_REQUEST]["path"] = mPath; - context[CONTEXT_REQUEST]["query-string"] = mQuery; - context[CONTEXT_REQUEST]["remote-host"] - = mBuildContext["remote-host"]; - context[CONTEXT_REQUEST]["remote-port"] - = mBuildContext["remote-port"]; + context[CONTEXT_REQUEST][CONTEXT_PATH] = mPath; + context[CONTEXT_REQUEST][CONTEXT_QUERY_STRING] = mQuery; + context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST] + = mBuildContext[CONTEXT_REMOTE_HOST]; + context[CONTEXT_REQUEST][CONTEXT_REMOTE_PORT] + = mBuildContext[CONTEXT_REMOTE_PORT]; context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders; const LLChainIOFactory* protocolHandler diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index 40537e05bc..a23eafe58a 100644 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -33,13 +33,6 @@ class LLPumpIO; -// common strings use for populating the context. bascally 'request', -// 'wildcard', and 'headers'. -extern const std::string CONTEXT_REQUEST; -extern const std::string CONTEXT_RESPONSE; -extern const std::string CONTEXT_VERB; -extern const std::string CONTEXT_HEADERS; - class LLIOHTTPServer { public: diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 2043bae5e7..a60b840067 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -39,6 +39,9 @@ // constants // +const std::string CONTEXT_REMOTE_HOST("remote-host"); +const std::string CONTEXT_REMOTE_PORT("remote-port"); + static const S32 LL_DEFAULT_LISTEN_BACKLOG = 10; static const S32 LL_SEND_BUFFER_SIZE = 40000; static const S32 LL_RECV_BUFFER_SIZE = 40000; @@ -619,8 +622,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( apr_sockaddr_ip_get(&remote_host_string, remote_addr); LLSD context; - context["remote-host"] = remote_host_string; - context["remote-port"] = remote_addr->port; + context[CONTEXT_REMOTE_HOST] = remote_host_string; + context[CONTEXT_REMOTE_PORT] = remote_addr->port; LLPumpIO::chain_t chain; chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket))); diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index be0f7dfcc6..08c21a1b97 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -42,6 +42,9 @@ #include "apr_network_io.h" #include "llchainio.h" +extern const std::string CONTEXT_REMOTE_HOST; +extern const std::string CONTEXT_REMOTE_PORT; + class LLHost; /** diff --git a/indra/llmessage/llmime.cpp b/indra/llmessage/llmime.cpp deleted file mode 100644 index 90653098db..0000000000 --- a/indra/llmessage/llmime.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/** - * @file llmime.cpp - * @author Phoenix - * @date 2006-12-20 - * @brief Implementation of mime tools. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llhttpconstants.h" -#include "llmime.h" - -#include - -#include "llmemorystream.h" - -/** - * Useful constants. - */ -// parser helpers -static const std::string MULTIPART("multipart"); -static const std::string BOUNDARY("boundary"); -static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t"); -static const std::string SEPARATOR_PREFIX("--"); -//static const std::string SEPARATOR_SUFFIX("\r\n"); - -/* -Content-Type: multipart/mixed; boundary="segment" -Content-Length: 24832 - ---segment -Content-Type: image/j2c -Content-Length: 23715 - - - ---segment -Content-Type: text/xml; charset=UTF-8 - - -EOF - -*/ - -/** - * LLMimeIndex - */ - -/** - * @class LLMimeIndex::Impl - * @brief Implementation details of the mime index class. - * @see LLMimeIndex - */ -class LLMimeIndex::Impl -{ -public: - Impl() : mOffset(-1), mUseCount(1) - {} - Impl(LLSD headers, S32 offset) : - mHeaders(headers), mOffset(offset), mUseCount(1) - {} -public: - LLSD mHeaders; - S32 mOffset; - S32 mUseCount; - - typedef std::vector sub_part_t; - sub_part_t mAttachments; -}; - -LLSD LLMimeIndex::headers() const -{ - return mImpl->mHeaders; -} - -S32 LLMimeIndex::offset() const -{ - return mImpl->mOffset; -} - -S32 LLMimeIndex::contentLength() const -{ - // Find the content length in the headers. - S32 length = -1; - LLSD content_length = mImpl->mHeaders[HTTP_HEADER_CONTENT_LENGTH]; - if(content_length.isDefined()) - { - length = content_length.asInteger(); - } - return length; -} - -std::string LLMimeIndex::contentType() const -{ - std::string type; - LLSD content_type = mImpl->mHeaders[HTTP_HEADER_CONTENT_TYPE]; - if(content_type.isDefined()) - { - type = content_type.asString(); - } - return type; -} - -bool LLMimeIndex::isMultipart() const -{ - bool multipart = false; - LLSD content_type = mImpl->mHeaders[HTTP_HEADER_CONTENT_TYPE]; - if(content_type.isDefined()) - { - std::string type = content_type.asString(); - int comp = type.compare(0, MULTIPART.size(), MULTIPART); - if(0 == comp) - { - multipart = true; - } - } - return multipart; -} - -S32 LLMimeIndex::subPartCount() const -{ - return mImpl->mAttachments.size(); -} - -LLMimeIndex LLMimeIndex::subPart(S32 index) const -{ - LLMimeIndex part; - if((index >= 0) && (index < (S32)mImpl->mAttachments.size())) - { - part = mImpl->mAttachments[index]; - } - return part; -} - -LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl) -{ -} - -LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) : - mImpl(new LLMimeIndex::Impl(headers, content_offset)) -{ -} - -LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) : - mImpl(mime.mImpl) -{ - ++mImpl->mUseCount; -} - -LLMimeIndex::~LLMimeIndex() -{ - if(0 == --mImpl->mUseCount) - { - delete mImpl; - } -} - -LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime) -{ - // Increment use count first so that we handle self assignment - // automatically. - ++mime.mImpl->mUseCount; - if(0 == --mImpl->mUseCount) - { - delete mImpl; - } - mImpl = mime.mImpl; - return *this; -} - -bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part) -{ - // *FIX: Should we check for multi-part? - if(mImpl->mAttachments.size() < S32_MAX) - { - mImpl->mAttachments.push_back(sub_part); - return true; - } - return false; -} - -/** - * LLMimeParser - */ -/** - * @class LLMimeParser::Impl - * @brief Implementation details of the mime parser class. - * @see LLMimeParser - */ -class LLMimeParser::Impl -{ -public: - // @brief Constructor. - Impl(); - - // @brief Reset this for a new parse. - void reset(); - - /** - * @brief Parse a mime entity to find the index information. - * - * This method will scan the istr until a single complete mime - * entity is read, an EOF, or limit bytes have been scanned. The - * istr will be modified by this parsing, so pass in a temporary - * stream or rewind/reset the stream after this call. - * @param istr An istream which contains a mime entity. - * @param limit The maximum number of bytes to scan. - * @param separator The multipart separator if it is known. - * @param is_subpart Set true if parsing a multipart sub part. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex( - std::istream& istr, - S32 limit, - const std::string& separator, - bool is_subpart, - LLMimeIndex& index); - -protected: - /** - * @brief parse the headers. - * - * At the end of a successful parse, mScanCount will be at the - * start of the content. - * @param istr The input stream. - * @param limit maximum number of bytes to process - * @param headers[out] A map of the headers found. - * @return Returns true if the parse was successful. - */ - bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers); - - /** - * @brief Figure out the separator string from a content type header. - * - * @param multipart_content_type The content type value from the headers. - * @return Returns the separator string. - */ - std::string findSeparator(std::string multipart_content_type); - - /** - * @brief Scan through istr past the separator. - * - * @param istr The input stream. - * @param limit Maximum number of bytes to scan. - * @param separator The multipart separator. - */ - void scanPastSeparator( - std::istream& istr, - S32 limit, - const std::string& separator); - - /** - * @brief Scan through istr past the content of the current mime part. - * - * @param istr The input stream. - * @param limit Maximum number of bytes to scan. - * @param headers The headers for this mime part. - * @param separator The multipart separator if known. - */ - void scanPastContent( - std::istream& istr, - S32 limit, - LLSD headers, - const std::string separator); - - /** - * @brief Eat CRLF. - * - * This method has no concept of the limit, so ensure you have at - * least 2 characters left to eat before hitting the limit. This - * method will increment mScanCount as it goes. - * @param istr The input stream. - * @return Returns true if CRLF was found and consumed off of istr. - */ - bool eatCRLF(std::istream& istr); - - // @brief Returns true if parsing should continue. - bool continueParse() const { return (!mError && mContinue); } - - // @brief anonymous enumeration for parse buffer size. - enum - { - LINE_BUFFER_LENGTH = 1024 - }; - -protected: - S32 mScanCount; - bool mContinue; - bool mError; - char mBuffer[LINE_BUFFER_LENGTH]; -}; - -LLMimeParser::Impl::Impl() -{ - reset(); -} - -void LLMimeParser::Impl::reset() -{ - mScanCount = 0; - mContinue = true; - mError = false; - mBuffer[0] = '\0'; -} - -bool LLMimeParser::Impl::parseIndex( - std::istream& istr, - S32 limit, - const std::string& separator, - bool is_subpart, - LLMimeIndex& index) -{ - LLSD headers; - bool parsed_something = false; - if(parseHeaders(istr, limit, headers)) - { - parsed_something = true; - LLMimeIndex mime(headers, mScanCount); - index = mime; - if(index.isMultipart()) - { - // Figure out the separator, scan past it, and recurse. - std::string ct = headers[HTTP_HEADER_CONTENT_TYPE].asString(); - std::string sep = findSeparator(ct); - scanPastSeparator(istr, limit, sep); - while(continueParse() && parseIndex(istr, limit, sep, true, mime)) - { - index.attachSubPart(mime); - } - } - else - { - // Scan to the end of content. - scanPastContent(istr, limit, headers, separator); - if(is_subpart) - { - scanPastSeparator(istr, limit, separator); - } - } - } - if(mError) return false; - return parsed_something; -} - -bool LLMimeParser::Impl::parseHeaders( - std::istream& istr, - S32 limit, - LLSD& headers) -{ - // Headers specified in rfc-2045 will be canonicalized below. - static const S32 KNOWN_HEADER_COUNT = 6; - static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] = - { - HTTP_HEADER_CONTENT_LENGTH, - HTTP_HEADER_CONTENT_TYPE, - HTTP_HEADER_MIME_VERSION, - HTTP_HEADER_CONTENT_TRANSFER_ENCODING, - HTTP_HEADER_CONTENT_ID, - HTTP_HEADER_CONTENT_DESCRIPTION, - }; - - while(continueParse()) - { - // Get the next line. - // We subtract 1 from the limit so that we make sure - // not to read past limit when we get() the newline. - S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); - istr.getline(mBuffer, max_get, '\r'); - mScanCount += (S32)istr.gcount(); - int c = istr.get(); - if(EOF == c) - { - mContinue = false; - return false; - } - ++mScanCount; - if(c != '\n') - { - mError = true; - return false; - } - if(mScanCount >= limit) - { - mContinue = false; - } - - // Check if that's the end of headers. - if('\0' == mBuffer[0]) - { - break; - } - - // Split out the name and value. - // *NOTE: The use of strchr() here is safe since mBuffer is - // guaranteed to be NULL terminated from the call to getline() - // above. - char* colon = strchr(mBuffer, ':'); - if(!colon) - { - mError = true; - return false; - } - - // Cononicalize the name part, and store the name: value in - // the headers structure. We do this by iterating through - // 'known' headers and replacing the value found with the - // correct one. - // *NOTE: Not so efficient, but iterating through a small - // subset should not be too much of an issue. - std::string name(mBuffer, colon++ - mBuffer); - while(isspace(*colon)) ++colon; - std::string value(colon); - for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii) - { - if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii])) - { - name = KNOWN_HEADER[ii]; - break; - } - } - headers[name] = value; - } - if(headers.isUndefined()) return false; - return true; -} - -std::string LLMimeParser::Impl::findSeparator(std::string header) -{ - // 01234567890 - //Content-Type: multipart/mixed; boundary="segment" - std::string separator; - std::string::size_type pos = header.find(BOUNDARY); - if(std::string::npos == pos) return separator; - pos += BOUNDARY.size() + 1; - std::string::size_type end; - if(header[pos] == '"') - { - // the boundary is quoted, find the end from pos, and take the - // substring. - end = header.find('"', ++pos); - if(std::string::npos == end) - { - // poorly formed boundary. - mError = true; - } - } - else - { - // otherwise, it's every character until a whitespace, end of - // line, or another parameter begins. - end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos); - if(std::string::npos == end) - { - // it goes to the end of the string. - end = header.size(); - } - } - if(!mError) separator = header.substr(pos, end - pos); - return separator; -} - -void LLMimeParser::Impl::scanPastSeparator( - std::istream& istr, - S32 limit, - const std::string& sep) -{ - std::ostringstream ostr; - ostr << SEPARATOR_PREFIX << sep; - std::string separator = ostr.str(); - bool found_separator = false; - while(!found_separator && continueParse()) - { - // Subtract 1 from the limit so that we make sure not to read - // past limit when we get() the newline. - S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); - istr.getline(mBuffer, max_get, '\r'); - mScanCount += (S32)istr.gcount(); - if(istr.gcount() >= LINE_BUFFER_LENGTH - 1) - { - // that's way too long to be a separator, so ignore it. - continue; - } - int c = istr.get(); - if(EOF == c) - { - mContinue = false; - return; - } - ++mScanCount; - if(c != '\n') - { - mError = true; - return; - } - if(mScanCount >= limit) - { - mContinue = false; - } - if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator)) - { - found_separator = true; - } - } -} - -void LLMimeParser::Impl::scanPastContent( - std::istream& istr, - S32 limit, - LLSD headers, - const std::string separator) -{ - if(headers.has(HTTP_HEADER_CONTENT_LENGTH)) - { - S32 content_length = headers[HTTP_HEADER_CONTENT_LENGTH].asInteger(); - // Subtract 2 here for the \r\n after the content. - S32 max_skip = llmin(content_length, limit - mScanCount - 2); - istr.ignore(max_skip); - mScanCount += max_skip; - - // *NOTE: Check for hitting the limit and eof here before - // checking for the trailing EOF, because our mime parser has - // to gracefully handle incomplete mime entites. - if((mScanCount >= limit) || istr.eof()) - { - mContinue = false; - } - else if(!eatCRLF(istr)) - { - mError = true; - return; - } - } -} - -bool LLMimeParser::Impl::eatCRLF(std::istream& istr) -{ - int c = istr.get(); - ++mScanCount; - if(c != '\r') - { - return false; - } - c = istr.get(); - ++mScanCount; - if(c != '\n') - { - return false; - } - return true; -} - - -LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl) -{ -} - -LLMimeParser::~LLMimeParser() -{ - delete & mImpl; -} - -void LLMimeParser::reset() -{ - mImpl.reset(); -} - -bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index) -{ - std::string separator; - return mImpl.parseIndex(istr, S32_MAX, separator, false, index); -} - -bool LLMimeParser::parseIndex( - const std::vector& buffer, - LLMimeIndex& index) -{ - LLMemoryStream mstr(&buffer[0], buffer.size()); - return parseIndex(mstr, buffer.size() + 1, index); -} - -bool LLMimeParser::parseIndex( - std::istream& istr, - S32 limit, - LLMimeIndex& index) -{ - std::string separator; - return mImpl.parseIndex(istr, limit, separator, false, index); -} - -bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index) -{ - LLMemoryStream mstr(buffer, length); - return parseIndex(mstr, length + 1, index); -} - -/* -bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const -{ - return false; -} - -bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const -{ - LLMemoryStream mstr(buffer, length); - return verify(mstr, index); -} -*/ diff --git a/indra/llmessage/llmime.h b/indra/llmessage/llmime.h deleted file mode 100644 index e6617fb503..0000000000 --- a/indra/llmessage/llmime.h +++ /dev/null @@ -1,292 +0,0 @@ -/** - * @file llmime.h - * @author Phoenix - * @date 2006-12-20 - * @brief Declaration of mime tools. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLMIME_H -#define LL_LLMIME_H - -#include -#include "llsd.h" - -/** - * This file declares various tools for parsing and creating MIME - * objects as described in RFCs 2045, 2046, 2047, 2048, and 2049. - */ - -/** - * @class LLMimeIndex - * @brief Skeletal information useful for handling mime packages. - * @see LLMimeParser - * - * An instance of this class is the parsed output from a LLMimeParser - * which then allows for easy access into a data stream to find and - * get what you want out of it. - * - * This class meant as a tool to quickly find what you seek in a - * parsed mime entity. As such, it does not have useful support for - * modification of a mime entity and specializes the interface toward - * querying data from a fixed mime entity. Modifying an instance of - * LLMimeIndx does not alter a mime entity and changes to a mime - * entity itself are not propogated into an instance of a LLMimeIndex. - * - * Usage:
- * LLMimeIndex mime_index;
- * std::ifstream fstr("package.mime", ios::binary);
- * LLMimeParser parser;
- * if(parser.parseIndex(fstr, mime_index))
- * {
- * std::vector content;
- * content.resize(mime_index.contentLength());
- * fstr.seekg(mime_index.offset(), ios::beg);
- * // ...do work on fstr and content
- * }
- */ -class LLMimeIndex -{ -public: - /* @name Client interface. - */ - //@{ - /** - * @brief Get the full parsed headers for this. - * - * If there are any headers, it will be a map of header name to - * the value found on the line. The name is everything before the - * colon, and the value is the string found after the colon to the - * end of the line after trimming leading whitespace. So, for - * example: - * Content-Type: text/plain - * would become an entry in the headers of: - * headers["Content-Type"] == "text/plain" - * - * If this instance of an index was generated by the - * LLMimeParser::parseIndex() call, all header names in rfc2045 - * will be capitalized as in rfc, eg Content-Length and - * MIME-Version, not content-length and mime-version. - * @return Returns an LLSD map of header name to value. Returns - * undef if there are no headers. - */ - LLSD headers() const; - - /** - * @brief Get the content offset. - * - * @return Returns the number of bytes to the start of the data - * segment from the start of serialized mime entity. Returns -1 if - * offset is not known. - */ - S32 offset() const; - - /** - * @brief Get the length of the data segment for this mime part. - * - * @return Returns the content length in bytes. Returns -1 if - * length is not known. - */ - S32 contentLength() const; - - /** - * @brief Get the mime type associated with this node. - * - * @return Returns the mimetype. - */ - std::string contentType() const; - - /** - * @brief Helper method which simplifies parsing the return from type() - * - * @return Returns true if this is a multipart mime, and therefore - * getting subparts will succeed. - */ - bool isMultipart() const; - - /** - * @brief Get the number of atachments. - * - * @return Returns the number of sub-parts for this. - */ - S32 subPartCount() const; - - /** - * @brief Get the indicated attachment. - * - * @param index Value from 0 to (subPartCount() - 1). - * @return Returns the indicated sub-part, or an invalid mime - * index on failure. - */ - LLMimeIndex subPart(S32 index) const; - //@} - - /* @name Interface for building, testing, and helpers for typical use. - */ - //@{ - /** - * @brief Default constructor - creates a useless LLMimeIndex. - */ - LLMimeIndex(); - - /** - * @brief Full constructor. - * - * @param headers The complete headers. - * @param content_offset The number of bytes to the start of the - * data segment of this mime entity from the start of the stream - * or buffer. - */ - LLMimeIndex(LLSD headers, S32 content_offset); - - /** - * @brief Copy constructor. - * - * @param mime The other mime object. - */ - LLMimeIndex(const LLMimeIndex& mime); - - // @brief Destructor. - ~LLMimeIndex(); - - /* - * @breif Assignment operator. - * - * @param mime The other mime object. - * @return Returns this after assignment. - */ - LLMimeIndex& operator=(const LLMimeIndex& mime); - - /** - * @brief Add attachment information as a sub-part to a multipart mime. - * - * @param sub_part the part to attach. - * @return Returns true on success, false on failure. - */ - bool attachSubPart(LLMimeIndex sub_part); - //@} - -protected: - // Implementation. - class Impl; - Impl* mImpl; -}; - - -/** - * @class LLMimeParser - * @brief This class implements a MIME parser and verifier. - * - * THOROUGH_DESCRIPTION - */ -class LLMimeParser -{ -public: - // @brief Make a new mime parser. - LLMimeParser(); - - // @brief Mime parser Destructor. - ~LLMimeParser(); - - // @brief Reset internal state of this parser. - void reset(); - - - /* @name Index generation interface. - */ - //@{ - /** - * @brief Parse a stream to find the mime index information. - * - * This method will scan the istr until a single complete mime - * entity is read or EOF. The istr will be modified by this - * parsing, so pass in a temporary stream or rewind/reset the - * stream after this call. - * @param istr An istream which contains a mime entity. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(std::istream& istr, LLMimeIndex& index); - - /** - * @brief Parse a vector to find the mime index information. - * - * @param buffer A vector with data to parse. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(const std::vector& buffer, LLMimeIndex& index); - - /** - * @brief Parse a stream to find the mime index information. - * - * This method will scan the istr until a single complete mime - * entity is read, an EOF, or limit bytes have been scanned. The - * istr will be modified by this parsing, so pass in a temporary - * stream or rewind/reset the stream after this call. - * @param istr An istream which contains a mime entity. - * @param limit The maximum number of bytes to scan. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(std::istream& istr, S32 limit, LLMimeIndex& index); - - /** - * @brief Parse a memory bufffer to find the mime index information. - * - * @param buffer The start of the buffer to parse. - * @param buffer_length The length of the buffer. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(const U8* buffer, S32 buffer_length, LLMimeIndex& index); - //@} - - /** - * @brief - * - * @return - */ - //bool verify(std::istream& istr, LLMimeIndex& index) const; - - /** - * @brief - * - * @return - */ - //bool verify(U8* buffer, S32 buffer_length, LLMimeIndex& index) const; - -protected: - // Implementation. - class Impl; - Impl& mImpl; - -private: - // @brief Not implemneted to prevent copy consturction. - LLMimeParser(const LLMimeParser& parser); - - // @brief Not implemneted to prevent assignment. - LLMimeParser& operator=(const LLMimeParser& mime); -}; - -#endif // LL_LLMIME_H diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index 8bab91b0c0..c593027802 100644 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -121,7 +121,7 @@ public: { //llinfos << "validate: " << name << ", " // << LLSDOStreamer(context) << llendl; - if((std::string("PUT") == context["request"]["verb"].asString()) && !name.empty()) + if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty()) { return true; } @@ -139,7 +139,7 @@ public: LLHTTPNode::ResponsePtr response, const LLSD& context) const { - std::string name = context["request"]["wildcard"]["option-name"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; LLSD options = LLApp::instance()->getOptionData( LLApp::PRIORITY_RUNTIME_OVERRIDE); response->result(options[name]); @@ -150,7 +150,7 @@ public: const LLSD& context, const LLSD& input) const { - std::string name = context["request"]["wildcard"]["option-name"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; LLSD options = LLApp::instance()->getOptionData( LLApp::PRIORITY_RUNTIME_OVERRIDE); options[name] = input; @@ -164,7 +164,7 @@ public: LLHTTPNode::ResponsePtr response, const LLSD& context) const { - std::string name = context["request"]["wildcard"]["option-name"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; LLSD options = LLApp::instance()->getOptionData( LLApp::PRIORITY_RUNTIME_OVERRIDE); options.erase(name); @@ -268,7 +268,7 @@ public: LLHTTPNode::ResponsePtr response, const LLSD& context) const { - std::string name = context["request"]["wildcard"]["option-name"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"]; response->result(LLApp::instance()->getOption(name)); } }; diff --git a/indra/llmessage/llsdhttpserver.cpp b/indra/llmessage/llsdhttpserver.cpp index 5c8fc7b2bb..8ac6b3cb12 100644 --- a/indra/llmessage/llsdhttpserver.cpp +++ b/indra/llmessage/llsdhttpserver.cpp @@ -109,7 +109,7 @@ public: virtual void get(ResponsePtr response, const LLSD& context) const { - const LLSD& remainder = context["request"]["remainder"]; + const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"]; if (remainder.size() > 0) { diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index 02891d4f32..dfd3b7e1d0 100644 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -251,7 +251,7 @@ public: LLIOPipe::ptr_t service(new Client); chain.push_back(service); LLIOPipe::ptr_t http_pipe(http); - http->addHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD); + http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD); if(mURL.empty()) { chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); @@ -301,7 +301,7 @@ public: LLIOPipe::ptr_t service(new Client); chain.push_back(service); LLIOPipe::ptr_t http_pipe(http); - http->addHeader(HTTP_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); + http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); if(mURL.empty()) { chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index 8248b184e9..a67ba35879 100644 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -42,9 +42,9 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { - std::string name = context["request"]["wildcard"]["message-name"]; - std::string senderIP = context["request"]["remote-host"]; - std::string senderPort = context["request"]["headers"] + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; + std::string senderIP = context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST]; + std::string senderPort = context[CONTEXT_REQUEST][CONTEXT_HEADERS] ["x-secondlife-udp-listen-port"]; LLSD message_data; diff --git a/indra/llmessage/lltrustedmessageservice.h b/indra/llmessage/lltrustedmessageservice.h index 688937ac2c..12a37bb535 100644 --- a/indra/llmessage/lltrustedmessageservice.h +++ b/indra/llmessage/lltrustedmessageservice.h @@ -30,6 +30,10 @@ #include "linden_common.h" #include "llhttpnode.h" +// These are defined in lliosocket.h/lliosocket.cpp +extern const std::string CONTEXT_REMOTE_HOST; +extern const std::string CONTEXT_REMOTE_PORT; + class LLSD; class LLTrustedMessageService diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index f354f5ab5d..49cfef2771 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -47,11 +47,12 @@ const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri"); const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); +// These are defined in llhttpnode.h/llhttpnode.cpp +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_RESPONSE; static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); - - /** * class LLURLRequestDetail */ @@ -479,7 +480,7 @@ bool LLURLRequest::configure() case HTTP_PUT: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. - addHeader(HTTP_HEADER_EXPECT); + addHeader(HTTP_OUT_HEADER_EXPECT); mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); @@ -489,11 +490,11 @@ bool LLURLRequest::configure() case HTTP_POST: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. - addHeader(HTTP_HEADER_EXPECT); + addHeader(HTTP_OUT_HEADER_EXPECT); // Disable the content type http header. // *FIX: what should it be? - addHeader(HTTP_HEADER_CONTENT_TYPE); + addHeader(HTTP_OUT_HEADER_CONTENT_TYPE); // Set the handle for an http post mDetail->mCurlRequest->setPost(NULL, bytes); diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index f334c92cc3..f3d32f5419 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -42,9 +42,10 @@ #include "llcurl.h" -extern const std::string CONTEXT_REQUEST; +/** + * External constants + */ extern const std::string CONTEXT_DEST_URI_SD_LABEL; -extern const std::string CONTEXT_RESPONSE; extern const std::string CONTEXT_TRANSFERED_BYTES; class LLURLRequestDetail; @@ -352,11 +353,4 @@ protected: EStatus mRequestStatus; }; - - -/** - * External constants - */ -extern const std::string CONTEXT_DEST_URI_SD_LABEL; - #endif // LL_LLURLREQUEST_H diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 78b259c3f1..5a63da628d 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -152,7 +152,7 @@ class LLMessageHandlerBridge : public LLHTTPNode void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { - std::string name = context["request"]["wildcard"]["message-name"]; + std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str()); lldebugs << "Setting mLastSender " << input["sender"].asString() << llendl; diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index bdc48ce53d..43fac83c57 100644 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -40,8 +40,6 @@ #include "llproxy.h" #include "llpumpio.h" -#include "llsdhttpserver.h" -#include "lliohttpserver.h" #include "lliosocket.h" #include "stringize.h" diff --git a/indra/llmessage/tests/llhttpnode_stub.cpp b/indra/llmessage/tests/llhttpnode_stub.cpp new file mode 100644 index 0000000000..cc2108fed5 --- /dev/null +++ b/indra/llmessage/tests/llhttpnode_stub.cpp @@ -0,0 +1,112 @@ +/** + * @file llhttpnode_stub.cpp + * @brief STUB Implementation of classes for generic HTTP/LSL/REST handling. + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llhttpnode.h" + +const std::string CONTEXT_VERB("verb"); +const std::string CONTEXT_REQUEST("request"); +const std::string CONTEXT_WILDCARD("wildcard"); +const std::string CONTEXT_PATH("path"); +const std::string CONTEXT_QUERY_STRING("query-string"); +const std::string CONTEXT_REMOTE_HOST("remote-host"); +const std::string CONTEXT_REMOTE_PORT("remote-port"); +const std::string CONTEXT_HEADERS("headers"); +const std::string CONTEXT_RESPONSE("response"); + +/** + * LLHTTPNode + */ +class LLHTTPNode::Impl +{ + // dummy +}; + +LLHTTPNode::LLHTTPNode(): impl(*new Impl) {} +LLHTTPNode::~LLHTTPNode() {} +LLSD LLHTTPNode::simpleGet() const { return LLSD(); } +LLSD LLHTTPNode::simplePut(const LLSD& input) const { return LLSD(); } +LLSD LLHTTPNode::simplePost(const LLSD& input) const { return LLSD(); } +LLSD LLHTTPNode::simpleDel(const LLSD&) const { return LLSD(); } +void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const {} +void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {} +void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {} +void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const {} +void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const {} +LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const { return NULL; } +bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const { return false; } +bool LLHTTPNode::validate(const std::string& name, LLSD& context) const { return false; } +const LLHTTPNode* LLHTTPNode::traverse(const std::string& path, LLSD& context) const { return NULL; } +void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) { } +LLSD LLHTTPNode::allNodePaths() const { return LLSD(); } +const LLHTTPNode* LLHTTPNode::rootNode() const { return NULL; } +const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { return NULL; } + +LLHTTPNode::Response::~Response(){} +void LLHTTPNode::Response::notFound(const std::string& message) +{ + status(404, message); +} +void LLHTTPNode::Response::notFound() +{ + status(404, "Not Found"); +} +void LLHTTPNode::Response::methodNotAllowed() +{ + status(405, "Method Not Allowed"); +} +void LLHTTPNode::Response::statusUnknownError(S32 code) +{ + status(code, "Unknown Error"); +} + +void LLHTTPNode::Response::status(S32 code, const std::string& message) +{ +} + +void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value) +{ + mHeaders[name] = value; +} +void LLHTTPNode::describe(Description& desc) const { } + + +const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const { return NULL; } + + +LLHTTPRegistrar::NodeFactory::~NodeFactory() { } + +void LLHTTPRegistrar::registerFactory( + const std::string& path, NodeFactory& factory) {} +void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root) {} + + diff --git a/indra/llmessage/tests/llmime_test.cpp b/indra/llmessage/tests/llmime_test.cpp deleted file mode 100644 index f8bf03bbcb..0000000000 --- a/indra/llmessage/tests/llmime_test.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/** - * @file llmime_test.cpp - * @author Phoenix - * @date 2006-12-24 - * @brief BRIEF_DESC of llmime_test.cpp - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llsdserialize.h" -#include "llhttpconstants.cpp" - -#include "../llmime.h" - -#include "../test/lltut.h" - -namespace tut -{ - struct mime_index - { - }; - typedef test_group mime_index_t; - typedef mime_index_t::object mime_index_object_t; - tut::mime_index_t tut_mime_index("LLMime"); - - template<> template<> - void mime_index_object_t::test<1>() - { - LLMimeIndex mime; - ensure("no headers", mime.headers().isUndefined()); - ensure_equals("invalid offset", mime.offset(), -1); - ensure_equals("invalid content length", mime.contentLength(), -1); - ensure("no content type", mime.contentType().empty()); - ensure("not multipart", !mime.isMultipart()); - ensure_equals("no attachments", mime.subPartCount(), 0); - } - - template<> template<> - void mime_index_object_t::test<2>() - { - const S32 CONTENT_LENGTH = 6000; - const S32 CONTENT_OFFSET = 100; - const std::string CONTENT_TYPE = std::string("image/j2c"); - LLSD headers; - headers["Content-Length"] = CONTENT_LENGTH; - headers["Content-Type"] = CONTENT_TYPE; - LLMimeIndex mime(headers, CONTENT_OFFSET); - ensure("headers are map", mime.headers().isMap()); - ensure_equals("offset", mime.offset(), CONTENT_OFFSET); - ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH); - ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE); - ensure("not multipart", !mime.isMultipart()); - ensure_equals("no attachments", mime.subPartCount(), 0); - } - - template<> template<> - void mime_index_object_t::test<3>() - { - const S32 MULTI_CONTENT_LENGTH = 8000; - const S32 MULTI_CONTENT_OFFSET = 100; - const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed"); - LLSD headers; - headers["Content-Length"] = MULTI_CONTENT_LENGTH; - headers["Content-Type"] = MULTI_CONTENT_TYPE; - LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET); - llinfos << "headers: " << LLSDOStreamer(headers) - << llendl; - - - const S32 META_CONTENT_LENGTH = 700; - const S32 META_CONTENT_OFFSET = 69; - const std::string META_CONTENT_TYPE = std::string( - "text/llsd+xml"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = META_CONTENT_LENGTH; - headers["Content-Type"] = META_CONTENT_TYPE; - LLMimeIndex meta(headers, META_CONTENT_OFFSET); - mime.attachSubPart(meta); - - const S32 IMAGE_CONTENT_LENGTH = 6000; - const S32 IMAGE_CONTENT_OFFSET = 200; - const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = IMAGE_CONTENT_LENGTH; - headers["Content-Type"] = IMAGE_CONTENT_TYPE; - LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET); - mime.attachSubPart(image); - - // make sure we have a valid multi-part - ensure("is multipart", mime.isMultipart()); - ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET); - ensure_equals( - "multi content length", - mime.contentLength(), - MULTI_CONTENT_LENGTH); - ensure_equals("two attachments", mime.subPartCount(), 2); - - // make sure ranged gets do the right thing with out of bounds - // sub-parts. - LLMimeIndex invalid_child(mime.subPart(-1)); - ensure("no headers", invalid_child.headers().isUndefined()); - ensure_equals("invalid offset", invalid_child.offset(), -1); - ensure_equals( - "invalid content length", invalid_child.contentLength(), -1); - ensure("no content type", invalid_child.contentType().empty()); - ensure("not multipart", !invalid_child.isMultipart()); - ensure_equals("no attachments", invalid_child.subPartCount(), 0); - - invalid_child = mime.subPart(2); - ensure("no headers", invalid_child.headers().isUndefined()); - ensure_equals("invalid offset", invalid_child.offset(), -1); - ensure_equals( - "invalid content length", invalid_child.contentLength(), -1); - ensure("no content type", invalid_child.contentType().empty()); - ensure("not multipart", !invalid_child.isMultipart()); - ensure_equals("no attachments", invalid_child.subPartCount(), 0); - } - - template<> template<> - void mime_index_object_t::test<4>() - { - const S32 MULTI_CONTENT_LENGTH = 8000; - const S32 MULTI_CONTENT_OFFSET = 100; - const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed"); - LLSD headers; - headers["Content-Length"] = MULTI_CONTENT_LENGTH; - headers["Content-Type"] = MULTI_CONTENT_TYPE; - LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET); - - const S32 META_CONTENT_LENGTH = 700; - const S32 META_CONTENT_OFFSET = 69; - const std::string META_CONTENT_TYPE = std::string( - "application/llsd+xml"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = META_CONTENT_LENGTH; - headers["Content-Type"] = META_CONTENT_TYPE; - LLMimeIndex meta(headers, META_CONTENT_OFFSET); - mime.attachSubPart(meta); - - const S32 IMAGE_CONTENT_LENGTH = 6000; - const S32 IMAGE_CONTENT_OFFSET = 200; - const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = IMAGE_CONTENT_LENGTH; - headers["Content-Type"] = IMAGE_CONTENT_TYPE; - LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET); - mime.attachSubPart(image); - - // check what we have - ensure("is multipart", mime.isMultipart()); - ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET); - ensure_equals( - "multi content length", - mime.contentLength(), - MULTI_CONTENT_LENGTH); - ensure_equals("two attachments", mime.subPartCount(), 2); - - LLMimeIndex actual_meta = mime.subPart(0); - ensure_equals( - "meta type", actual_meta.contentType(), META_CONTENT_TYPE); - ensure_equals( - "meta offset", actual_meta.offset(), META_CONTENT_OFFSET); - ensure_equals( - "meta content length", - actual_meta.contentLength(), - META_CONTENT_LENGTH); - - LLMimeIndex actual_image = mime.subPart(1); - ensure_equals( - "image type", actual_image.contentType(), IMAGE_CONTENT_TYPE); - ensure_equals( - "image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET); - ensure_equals( - "image content length", - actual_image.contentLength(), - IMAGE_CONTENT_LENGTH); - } - -/* - template<> template<> - void mime_index_object_t::test<5>() - { - } - template<> template<> - void mime_index_object_t::test<6>() - { - } - template<> template<> - void mime_index_object_t::test<7>() - { - } - template<> template<> - void mime_index_object_t::test<8>() - { - } - template<> template<> - void mime_index_object_t::test<>() - { - } -*/ -} - - -namespace tut -{ - struct mime_parse - { - }; - typedef test_group mime_parse_t; - typedef mime_parse_t::object mime_parse_object_t; - tut::mime_parse_t tut_mime_parse("LLMimeParse"); - - template<> template<> - void mime_parse_object_t::test<1>() - { - // parse one mime object - const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure_equals("content type", mime.contentType(), "text/plain"); - ensure_equals("content length", mime.contentLength(), 200); - ensure_equals("offset", mime.offset(), 49); - } - - template<> template<> - void mime_parse_object_t::test<2>() - { - // make sure we only parse one. - const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("not multipart.", !mime.isMultipart()); - ensure_equals("content type", mime.contentType(), "text/plain"); - ensure_equals("content length", mime.contentLength(), 200); - ensure_equals("offset", mime.offset(), 49); - } - - template<> template<> - void mime_parse_object_t::test<3>() - { - // test multi-part and lack of content length for some of it. - /* -Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrnrnrn - */ - const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 150); - ensure_equals("data offset for multipart", mime.offset(), 74); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length not known.", - mime_plain.contentLength(), - -1); - ensure_equals("first part offset", mime_plain.offset(), 113); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - ensure_equals("second part offset", mime_xml.offset(), 198); - } - - template<> template<> - void mime_parse_object_t::test<4>() - { - // test multi-part, unquoted separator, and premature eof conditions - /* -Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrnrnrn */ - const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 220); - ensure_equals("data offset for multipart", mime.offset(), 72); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length", - mime_plain.contentLength(), - 55); - ensure_equals("first part offset", mime_plain.offset(), 131); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - ensure_equals("second part offset", mime_xml.offset(), 262); - } - - template<> template<> - void mime_parse_object_t::test<5>() - { - // test multi-part with multiple params - const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 220); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length", - mime_plain.contentLength(), - 55); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - } - - template<> template<> - void mime_parse_object_t::test<6>() - { - // test multi-part with no specified boundary and eof -/* -Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrnrnrn -*/ - const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 500); - ensure_equals("data offset for multipart", mime.offset(), 56); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length", - mime_plain.contentLength(), - 55); - ensure_equals("first part offset", mime_plain.offset(), 108); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - ensure_equals("second part offset", mime_xml.offset(), 232); - } - -/* - template<> template<> - void mime_parse_object_t::test<>() - { - } - template<> template<> - void mime_parse_object_t::test<>() - { - } - template<> template<> - void mime_parse_object_t::test<>() - { - } - template<> template<> - void mime_parse_object_t::test<>() - { - } -*/ -} diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index b287a29841..55748ad27e 100644 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -32,6 +32,7 @@ #include "message.h" #include "llmessageconfig.h" +#include "llhttpnode_stub.cpp" LLMessageSystem* gMessageSystem = NULL; -- cgit v1.2.3 From 14ca6a1247e68805aae22cf573a39819383fe3d4 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 11 Apr 2013 11:18:16 -0400 Subject: SH-4061 WIP - moved retry policy to llmessage, added integration test --- indra/llmessage/CMakeLists.txt | 2 + indra/llmessage/llhttpretrypolicy.cpp | 71 ++++++++ indra/llmessage/llhttpretrypolicy.h | 76 ++++++++ indra/llmessage/tests/llhttpretrypolicy_test.cpp | 220 +++++++++++++++++++++++ 4 files changed, 369 insertions(+) mode change 100644 => 100755 indra/llmessage/CMakeLists.txt create mode 100755 indra/llmessage/llhttpretrypolicy.cpp create mode 100755 indra/llmessage/llhttpretrypolicy.h create mode 100755 indra/llmessage/tests/llhttpretrypolicy_test.cpp (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt old mode 100644 new mode 100755 index 6fa2669be6..6df724f960 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -67,6 +67,7 @@ set(llmessage_SOURCE_FILES llpartdata.cpp llproxy.cpp llpumpio.cpp + llhttpretrypolicy.cpp llsdappservices.cpp llsdhttpserver.cpp llsdmessage.cpp @@ -266,5 +267,6 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/llhttpretrypolicy.cpp b/indra/llmessage/llhttpretrypolicy.cpp new file mode 100755 index 0000000000..23d9e64c13 --- /dev/null +++ b/indra/llmessage/llhttpretrypolicy.cpp @@ -0,0 +1,71 @@ +/** + * @file llhttpretrypolicy.h + * @brief Header for a retry policy class intended for use with http responders. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llhttpretrypolicy.h" + +void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) +{ + if (mRetryCount > 0) + { + mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); + } + // Honor server Retry-After header. + // Status 503 may ask us to wait for a certain amount of time before retrying. + F32 wait_time = mDelay; + F32 retry_header_time; + if (headers.has(HTTP_IN_HEADER_RETRY_AFTER) + && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)) + { + wait_time = retry_header_time; + } + + if (mRetryCount>=mMaxRetries) + { + llinfos << "Too many retries " << mRetryCount << ", will not retry" << llendl; + mShouldRetry = false; + } + if (!isHttpServerErrorStatus(status)) + { + llinfos << "Non-server error " << status << ", will not retry" << llendl; + mShouldRetry = false; + } + if (mShouldRetry) + { + llinfos << "Retry count " << mRetryCount << " should retry after " << wait_time << llendl; + mRetryTimer.reset(); + mRetryTimer.setTimerExpirySec(wait_time); + } + mRetryCount++; +} + + +bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const +{ + llassert(mRetryCount>0); // have to call onFailure() before shouldRetry() + seconds_to_wait = mShouldRetry ? mRetryTimer.getRemainingTimeF32() : F32_MAX; + return mShouldRetry; +} diff --git a/indra/llmessage/llhttpretrypolicy.h b/indra/llmessage/llhttpretrypolicy.h new file mode 100755 index 0000000000..f2eba0965b --- /dev/null +++ b/indra/llmessage/llhttpretrypolicy.h @@ -0,0 +1,76 @@ +/** + * @file file llhttpretrypolicy.h + * @brief declarations for http retry policy class. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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_RETRYPOLICY_H +#define LL_RETRYPOLICY_H + +#include "lltimer.h" +#include "llthread.h" +#include "llhttpconstants.h" + +// This is intended for use with HTTP Clients/Responders, but is not +// specifically coupled with those classes. +class LLHTTPRetryPolicy: public LLThreadSafeRefCount +{ +public: + LLHTTPRetryPolicy() {} + virtual ~LLHTTPRetryPolicy() {} + // Call once after an HTTP failure to update state. + virtual void onFailure(S32 status, const LLSD& headers) = 0; + virtual bool shouldRetry(F32& seconds_to_wait) const = 0; +}; + +// Very general policy with geometric back-off after failures, +// up to a maximum delay, and maximum number of retries. +class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +{ +public: + LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): + mMinDelay(min_delay), + mMaxDelay(max_delay), + mBackoffFactor(backoff_factor), + mMaxRetries(max_retries), + mDelay(min_delay), + mRetryCount(0), + mShouldRetry(true) + { + } + + void onFailure(S32 status, const LLSD& headers); + bool shouldRetry(F32& seconds_to_wait) const; + +private: + F32 mMinDelay; // delay never less than this value + F32 mMaxDelay; // delay never exceeds this value + F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. + U32 mMaxRetries; // maximum number of times shouldRetry will return true. + F32 mDelay; // current default delay. + U32 mRetryCount; // number of times shouldRetry has been called. + LLTimer mRetryTimer; // time until next retry. + bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. +}; + +#endif diff --git a/indra/llmessage/tests/llhttpretrypolicy_test.cpp b/indra/llmessage/tests/llhttpretrypolicy_test.cpp new file mode 100755 index 0000000000..ebf626d9a8 --- /dev/null +++ b/indra/llmessage/tests/llhttpretrypolicy_test.cpp @@ -0,0 +1,220 @@ +/** + * @file llhttpretrypolicy_test.cpp + * @brief Header tests to exercise the LLHTTPRetryPolicy classes. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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 "llhttpretrypolicy.h" +#include "lltut.h" + +namespace tut +{ +struct TestData +{ +}; + +typedef test_group RetryPolicyTestGroup; +typedef RetryPolicyTestGroup::object RetryPolicyTestObject; +RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); + +template<> template<> +void RetryPolicyTestObject::test<1>() +{ + LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); + LLSD headers; + F32 wait_seconds; + + never_retry.onFailure(500,headers); + ensure("never retry", !never_retry.shouldRetry(wait_seconds)); +} + +template<> template<> +void RetryPolicyTestObject::test<2>() +{ + LLAdaptiveRetryPolicy retry404(1.0,2.0,3.0,10); + LLSD headers; + F32 wait_seconds; + + retry404.onFailure(404,headers); + ensure("no retry on 404", !retry404.shouldRetry(wait_seconds)); +} + +template<> template<> +void RetryPolicyTestObject::test<3>() +{ + // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. + LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); + LLSD headers; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + // Starting wait 1.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 1", should_retry); + ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 2", should_retry); + ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); + + // Hit max wait of 3.0 (4.0 clamped to max 3) + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 3", should_retry); + ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); + + // At max wait, should stay at 3.0 + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 4", should_retry); + ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); + + // Max retries, should fail now. + basic_retry.onFailure(500,headers); + should_retry = basic_retry.shouldRetry(wait_seconds); + ensure("basic_retry 5", !should_retry); +} + +// Retries should stop as soon as a non-5xx error is received. +template<> template<> +void RetryPolicyTestObject::test<4>() +{ + // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. + LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); + LLSD headers; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + // Starting wait 1.0 + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 1", should_retry); + ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); + + // Double wait to 2.0 + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 2", should_retry); + ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); + + // Should fail on non-5xx + killer404.onFailure(404,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 3", !should_retry); + + // After a non-5xx, should keep failing. + killer404.onFailure(500,headers); + should_retry = killer404.shouldRetry(wait_seconds); + ensure("killer404 4", !should_retry); +} + +// Test handling of "retry-after" header. If present, this header +// value overrides the computed delay, but does not affect the +// progression of delay values. For example, if the normal +// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls +// get a retry header of 33, the pattern would become 1,33,33,8... +template<> template<> +void RetryPolicyTestObject::test<5>() +{ + LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); + LLSD headers_with_retry; + headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666"; + LLSD headers_without_retry; + F32 wait_seconds; + bool should_retry; + U32 frac_bits = 6; + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 1", should_retry); + ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 2", should_retry); + ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 3", should_retry); + // 4.0 overrides by header -> 666.0 + ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 4", should_retry); + // 8.0 overrides by header -> 666.0 + ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 5", should_retry); + ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); + + policy.onFailure(500,headers_without_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 6", should_retry); + ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); + + policy.onFailure(500,headers_with_retry); + should_retry = policy.shouldRetry(wait_seconds); + ensure("retry header 7", !should_retry); +} + +// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), +// used by header parsing of the retry policy. +template<> template<> +void RetryPolicyTestObject::test<6>() +{ + F32 seconds_to_wait; + bool success; + + std::string str1("0"); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str1, seconds_to_wait); + ensure("parse 1", success); + ensure_equals("parse 1", seconds_to_wait, 0.0); + + std::string str2("999.9"); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str2, seconds_to_wait); + ensure("parse 2", success); + ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); + + time_t nowseconds; + time(&nowseconds); + std::string str3 = LLDate((F64)nowseconds).asRFC1123(); + seconds_to_wait = F32_MAX; + success = getSecondsUntilRetryAfter(str3, seconds_to_wait); + ensure("parse 3", success); + ensure_approximately_equals("parse 3", seconds_to_wait, 0.0F, 6); +} + +} + -- cgit v1.2.3 From e17920defbf1d39ecd9e88500ba268c59bb84008 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 11 Apr 2013 16:17:23 -0400 Subject: SH-4061 WIP - started adding retry to texture fetch, making retry policy compatible with old and new http libraries --- indra/llmessage/llhttpretrypolicy.cpp | 17 ++++++++++++++--- indra/llmessage/llhttpretrypolicy.h | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llhttpretrypolicy.cpp b/indra/llmessage/llhttpretrypolicy.cpp index 23d9e64c13..7e4dfc7250 100755 --- a/indra/llmessage/llhttpretrypolicy.cpp +++ b/indra/llmessage/llhttpretrypolicy.cpp @@ -27,7 +27,20 @@ #include "linden_common.h" #include "llhttpretrypolicy.h" +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, retry_header_time) +{ + return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) + && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); +} + void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) +{ + F32 retry_header_time; + bool has_retry_header_time = getRetryAfter(headers,retry_header_time); + onFailureCommon(status, has_retry_header_time, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) { if (mRetryCount > 0) { @@ -36,9 +49,7 @@ void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) // Honor server Retry-After header. // Status 503 may ask us to wait for a certain amount of time before retrying. F32 wait_time = mDelay; - F32 retry_header_time; - if (headers.has(HTTP_IN_HEADER_RETRY_AFTER) - && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)) + if (has_retry_header_time) { wait_time = retry_header_time; } diff --git a/indra/llmessage/llhttpretrypolicy.h b/indra/llmessage/llhttpretrypolicy.h index f2eba0965b..cf27bb3048 100755 --- a/indra/llmessage/llhttpretrypolicy.h +++ b/indra/llmessage/llhttpretrypolicy.h @@ -29,8 +29,13 @@ #include "lltimer.h" #include "llthread.h" + #include "llhttpconstants.h" +// For compatibility with new core http lib. +#include "httpresponse.h" +#include "httpheaders.h" + // This is intended for use with HTTP Clients/Responders, but is not // specifically coupled with those classes. class LLHTTPRetryPolicy: public LLThreadSafeRefCount @@ -40,6 +45,9 @@ public: virtual ~LLHTTPRetryPolicy() {} // Call once after an HTTP failure to update state. virtual void onFailure(S32 status, const LLSD& headers) = 0; + + virtual void onFailure(const HttpResponse *response, const HttpHeaders *headers) = 0; + virtual bool shouldRetry(F32& seconds_to_wait) const = 0; }; @@ -59,10 +67,19 @@ public: { } + // virtual void onFailure(S32 status, const LLSD& headers); + // virtual + void onFailure(const HttpResponse *response, const HttpHeaders *headers); + // virtual bool shouldRetry(F32& seconds_to_wait) const; +protected: + bool getRetryAfter(const LLSD& headers, retry_header_time) + void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); + private: + F32 mMinDelay; // delay never less than this value F32 mMaxDelay; // delay never exceeds this value F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. -- cgit v1.2.3 From a8cdcfc9a893b7debf7c006022b57c389b50bf0d Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 12 Apr 2013 09:16:25 -0400 Subject: SH-4061 WIP - moved retry policy to newview so it can work with either llmessage or CoreHttp libraries. Updated tests. --- indra/llmessage/CMakeLists.txt | 2 - indra/llmessage/llhttpretrypolicy.cpp | 82 --------- indra/llmessage/llhttpretrypolicy.h | 93 ---------- indra/llmessage/tests/llhttpretrypolicy_test.cpp | 220 ----------------------- 4 files changed, 397 deletions(-) delete mode 100755 indra/llmessage/llhttpretrypolicy.cpp delete mode 100755 indra/llmessage/llhttpretrypolicy.h delete mode 100755 indra/llmessage/tests/llhttpretrypolicy_test.cpp (limited to 'indra/llmessage') diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 6df724f960..6fa2669be6 100755 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -67,7 +67,6 @@ set(llmessage_SOURCE_FILES llpartdata.cpp llproxy.cpp llpumpio.cpp - llhttpretrypolicy.cpp llsdappservices.cpp llsdhttpserver.cpp llsdmessage.cpp @@ -267,6 +266,5 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "" "${test_libs}") endif (LL_TESTS) diff --git a/indra/llmessage/llhttpretrypolicy.cpp b/indra/llmessage/llhttpretrypolicy.cpp deleted file mode 100755 index 7e4dfc7250..0000000000 --- a/indra/llmessage/llhttpretrypolicy.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file llhttpretrypolicy.h - * @brief Header for a retry policy class intended for use with http responders. - * - * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2013, 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 "llhttpretrypolicy.h" - -bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, retry_header_time) -{ - return (headers.has(HTTP_IN_HEADER_RETRY_AFTER) - && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); -} - -void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) -{ - F32 retry_header_time; - bool has_retry_header_time = getRetryAfter(headers,retry_header_time); - onFailureCommon(status, has_retry_header_time, retry_header_time); -} - -void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) -{ - if (mRetryCount > 0) - { - mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); - } - // Honor server Retry-After header. - // Status 503 may ask us to wait for a certain amount of time before retrying. - F32 wait_time = mDelay; - if (has_retry_header_time) - { - wait_time = retry_header_time; - } - - if (mRetryCount>=mMaxRetries) - { - llinfos << "Too many retries " << mRetryCount << ", will not retry" << llendl; - mShouldRetry = false; - } - if (!isHttpServerErrorStatus(status)) - { - llinfos << "Non-server error " << status << ", will not retry" << llendl; - mShouldRetry = false; - } - if (mShouldRetry) - { - llinfos << "Retry count " << mRetryCount << " should retry after " << wait_time << llendl; - mRetryTimer.reset(); - mRetryTimer.setTimerExpirySec(wait_time); - } - mRetryCount++; -} - - -bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const -{ - llassert(mRetryCount>0); // have to call onFailure() before shouldRetry() - seconds_to_wait = mShouldRetry ? mRetryTimer.getRemainingTimeF32() : F32_MAX; - return mShouldRetry; -} diff --git a/indra/llmessage/llhttpretrypolicy.h b/indra/llmessage/llhttpretrypolicy.h deleted file mode 100755 index cf27bb3048..0000000000 --- a/indra/llmessage/llhttpretrypolicy.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file file llhttpretrypolicy.h - * @brief declarations for http retry policy class. - * - * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2013, 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_RETRYPOLICY_H -#define LL_RETRYPOLICY_H - -#include "lltimer.h" -#include "llthread.h" - -#include "llhttpconstants.h" - -// For compatibility with new core http lib. -#include "httpresponse.h" -#include "httpheaders.h" - -// This is intended for use with HTTP Clients/Responders, but is not -// specifically coupled with those classes. -class LLHTTPRetryPolicy: public LLThreadSafeRefCount -{ -public: - LLHTTPRetryPolicy() {} - virtual ~LLHTTPRetryPolicy() {} - // Call once after an HTTP failure to update state. - virtual void onFailure(S32 status, const LLSD& headers) = 0; - - virtual void onFailure(const HttpResponse *response, const HttpHeaders *headers) = 0; - - virtual bool shouldRetry(F32& seconds_to_wait) const = 0; -}; - -// Very general policy with geometric back-off after failures, -// up to a maximum delay, and maximum number of retries. -class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy -{ -public: - LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): - mMinDelay(min_delay), - mMaxDelay(max_delay), - mBackoffFactor(backoff_factor), - mMaxRetries(max_retries), - mDelay(min_delay), - mRetryCount(0), - mShouldRetry(true) - { - } - - // virtual - void onFailure(S32 status, const LLSD& headers); - // virtual - void onFailure(const HttpResponse *response, const HttpHeaders *headers); - // virtual - bool shouldRetry(F32& seconds_to_wait) const; - -protected: - bool getRetryAfter(const LLSD& headers, retry_header_time) - void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); - -private: - - F32 mMinDelay; // delay never less than this value - F32 mMaxDelay; // delay never exceeds this value - F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. - U32 mMaxRetries; // maximum number of times shouldRetry will return true. - F32 mDelay; // current default delay. - U32 mRetryCount; // number of times shouldRetry has been called. - LLTimer mRetryTimer; // time until next retry. - bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. -}; - -#endif diff --git a/indra/llmessage/tests/llhttpretrypolicy_test.cpp b/indra/llmessage/tests/llhttpretrypolicy_test.cpp deleted file mode 100755 index ebf626d9a8..0000000000 --- a/indra/llmessage/tests/llhttpretrypolicy_test.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file llhttpretrypolicy_test.cpp - * @brief Header tests to exercise the LLHTTPRetryPolicy classes. - * - * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2013, 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 "llhttpretrypolicy.h" -#include "lltut.h" - -namespace tut -{ -struct TestData -{ -}; - -typedef test_group RetryPolicyTestGroup; -typedef RetryPolicyTestGroup::object RetryPolicyTestObject; -RetryPolicyTestGroup retryPolicyTestGroup("retry_policy"); - -template<> template<> -void RetryPolicyTestObject::test<1>() -{ - LLAdaptiveRetryPolicy never_retry(1.0,1.0,1.0,0); - LLSD headers; - F32 wait_seconds; - - never_retry.onFailure(500,headers); - ensure("never retry", !never_retry.shouldRetry(wait_seconds)); -} - -template<> template<> -void RetryPolicyTestObject::test<2>() -{ - LLAdaptiveRetryPolicy retry404(1.0,2.0,3.0,10); - LLSD headers; - F32 wait_seconds; - - retry404.onFailure(404,headers); - ensure("no retry on 404", !retry404.shouldRetry(wait_seconds)); -} - -template<> template<> -void RetryPolicyTestObject::test<3>() -{ - // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. - LLAdaptiveRetryPolicy basic_retry(1.0,3.0,2.0,4); - LLSD headers; - F32 wait_seconds; - bool should_retry; - U32 frac_bits = 6; - - // Starting wait 1.0 - basic_retry.onFailure(500,headers); - should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 1", should_retry); - ensure_approximately_equals("basic_retry 1", wait_seconds, 1.0F, frac_bits); - - // Double wait to 2.0 - basic_retry.onFailure(500,headers); - should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 2", should_retry); - ensure_approximately_equals("basic_retry 2", wait_seconds, 2.0F, frac_bits); - - // Hit max wait of 3.0 (4.0 clamped to max 3) - basic_retry.onFailure(500,headers); - should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 3", should_retry); - ensure_approximately_equals("basic_retry 3", wait_seconds, 3.0F, frac_bits); - - // At max wait, should stay at 3.0 - basic_retry.onFailure(500,headers); - should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 4", should_retry); - ensure_approximately_equals("basic_retry 4", wait_seconds, 3.0F, frac_bits); - - // Max retries, should fail now. - basic_retry.onFailure(500,headers); - should_retry = basic_retry.shouldRetry(wait_seconds); - ensure("basic_retry 5", !should_retry); -} - -// Retries should stop as soon as a non-5xx error is received. -template<> template<> -void RetryPolicyTestObject::test<4>() -{ - // Should retry after 1.0, 2.0, 3.0, 3.0 seconds. - LLAdaptiveRetryPolicy killer404(1.0,3.0,2.0,4); - LLSD headers; - F32 wait_seconds; - bool should_retry; - U32 frac_bits = 6; - - // Starting wait 1.0 - killer404.onFailure(500,headers); - should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 1", should_retry); - ensure_approximately_equals("killer404 1", wait_seconds, 1.0F, frac_bits); - - // Double wait to 2.0 - killer404.onFailure(500,headers); - should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 2", should_retry); - ensure_approximately_equals("killer404 2", wait_seconds, 2.0F, frac_bits); - - // Should fail on non-5xx - killer404.onFailure(404,headers); - should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 3", !should_retry); - - // After a non-5xx, should keep failing. - killer404.onFailure(500,headers); - should_retry = killer404.shouldRetry(wait_seconds); - ensure("killer404 4", !should_retry); -} - -// Test handling of "retry-after" header. If present, this header -// value overrides the computed delay, but does not affect the -// progression of delay values. For example, if the normal -// progression of delays would be 1,2,4,8..., but the 2nd and 3rd calls -// get a retry header of 33, the pattern would become 1,33,33,8... -template<> template<> -void RetryPolicyTestObject::test<5>() -{ - LLAdaptiveRetryPolicy policy(1.0,25.0,2.0,6); - LLSD headers_with_retry; - headers_with_retry[HTTP_IN_HEADER_RETRY_AFTER] = "666"; - LLSD headers_without_retry; - F32 wait_seconds; - bool should_retry; - U32 frac_bits = 6; - - policy.onFailure(500,headers_without_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 1", should_retry); - ensure_approximately_equals("retry header 1", wait_seconds, 1.0F, frac_bits); - - policy.onFailure(500,headers_without_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 2", should_retry); - ensure_approximately_equals("retry header 2", wait_seconds, 2.0F, frac_bits); - - policy.onFailure(500,headers_with_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 3", should_retry); - // 4.0 overrides by header -> 666.0 - ensure_approximately_equals("retry header 3", wait_seconds, 666.0F, frac_bits); - - policy.onFailure(500,headers_with_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 4", should_retry); - // 8.0 overrides by header -> 666.0 - ensure_approximately_equals("retry header 4", wait_seconds, 666.0F, frac_bits); - - policy.onFailure(500,headers_without_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 5", should_retry); - ensure_approximately_equals("retry header 5", wait_seconds, 16.0F, frac_bits); - - policy.onFailure(500,headers_without_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 6", should_retry); - ensure_approximately_equals("retry header 6", wait_seconds, 25.0F, frac_bits); - - policy.onFailure(500,headers_with_retry); - should_retry = policy.shouldRetry(wait_seconds); - ensure("retry header 7", !should_retry); -} - -// Test getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait), -// used by header parsing of the retry policy. -template<> template<> -void RetryPolicyTestObject::test<6>() -{ - F32 seconds_to_wait; - bool success; - - std::string str1("0"); - seconds_to_wait = F32_MAX; - success = getSecondsUntilRetryAfter(str1, seconds_to_wait); - ensure("parse 1", success); - ensure_equals("parse 1", seconds_to_wait, 0.0); - - std::string str2("999.9"); - seconds_to_wait = F32_MAX; - success = getSecondsUntilRetryAfter(str2, seconds_to_wait); - ensure("parse 2", success); - ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); - - time_t nowseconds; - time(&nowseconds); - std::string str3 = LLDate((F64)nowseconds).asRFC1123(); - seconds_to_wait = F32_MAX; - success = getSecondsUntilRetryAfter(str3, seconds_to_wait); - ensure("parse 3", success); - ensure_approximately_equals("parse 3", seconds_to_wait, 0.0F, 6); -} - -} - -- cgit v1.2.3 From 24b9657597be6d0b7af472d5deda4b4828ead606 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 15 Apr 2013 20:35:26 -0400 Subject: SH-4061 WIP - improved retry policy test, turned up and fixed a bug in getSecondsUntilRetryAfter --- indra/llmessage/llhttpconstants.cpp | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) mode change 100644 => 100755 indra/llmessage/llhttpconstants.cpp (limited to 'indra/llmessage') diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp old mode 100644 new mode 100755 index 1995fad1e5..016f1f1970 --- a/indra/llmessage/llhttpconstants.cpp +++ b/indra/llmessage/llhttpconstants.cpp @@ -2,31 +2,28 @@ * @file llhttpconstants.cpp * @brief Implementation of the HTTP request / response constant lookups * - * $LicenseInfo:firstyear=2013&license=viewergpl$ + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ * * Copyright (c) 2013, Linden Research, Inc. * * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2013, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -220,7 +217,8 @@ bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_w time_t date = curl_getdate(retry_after.c_str(), NULL ); if (-1 == date) return false; - seconds_to_wait = (F32)date - (F32)LLTimer::getTotalSeconds(); + seconds_to_wait = (F64)date - LLTimer::getTotalSeconds(); + return true; } -- cgit v1.2.3 From 6c56c77ec575141963c5de8dfa228253fe175bc3 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 24 May 2013 08:53:21 -0400 Subject: SH-4027 WIP - initial implementation of item update via AIS. --- indra/llmessage/llhttpclient.cpp | 12 +++++++++++- indra/llmessage/llhttpclient.h | 8 ++++++++ indra/llmessage/llhttpconstants.h | 37 ++++++++++++++++--------------------- indra/llmessage/llurlrequest.cpp | 11 +++++++++++ 4 files changed, 46 insertions(+), 22 deletions(-) mode change 100644 => 100755 indra/llmessage/llhttpconstants.h (limited to 'indra/llmessage') diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 5830a5eca0..53cef54559 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -304,7 +304,7 @@ static void request( gMessageSystem->mPort)); } - if (method == HTTP_PUT || method == HTTP_POST) + if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH) { if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE)) { @@ -556,6 +556,16 @@ void LLHTTPClient::put( request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); } +void LLHTTPClient::patch( + const std::string& url, + const LLSD& body, + ResponderPtr responder, + const LLSD& headers, + const F32 timeout) +{ + request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers); +} + void LLHTTPClient::post( const std::string& url, const LLSD& body, diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index a7236ba169..4e7495495f 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -74,6 +74,14 @@ public: ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + + static void patch( + const std::string& url, + const LLSD& body, + ResponderPtr, + const LLSD& headers = LLSD(), + const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h old mode 100644 new mode 100755 index 8cc3459654..aa947af414 --- a/indra/llmessage/llhttpconstants.h +++ b/indra/llmessage/llhttpconstants.h @@ -2,31 +2,25 @@ * @file llhttpconstants.h * @brief Constants for HTTP requests and responses * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2013, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2001-2013, 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -117,6 +111,7 @@ enum EHTTPMethod HTTP_DELETE, HTTP_MOVE, // Caller will need to set 'Destination' header HTTP_OPTIONS, + HTTP_PATCH, HTTP_METHOD_COUNT }; diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 49cfef2771..cadff49cb8 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -487,6 +487,17 @@ bool LLURLRequest::configure() rv = true; break; + case HTTP_PATCH: + // Disable the expect http 1.1 extension. POST and PUT default + // to turning this on, and I am not too sure what it means. + addHeader(HTTP_OUT_HEADER_EXPECT); + + mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); + mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); + mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH"); + rv = true; + break; + case HTTP_POST: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. -- cgit v1.2.3 From a85fa3b10a406218cabfecc0d592e816f8dfdb53 Mon Sep 17 00:00:00 2001 From: Don Kjer Date: Thu, 11 Jul 2013 15:15:04 -0700 Subject: Adding support for COPY methods to httpclient. Implementing viewer-side use of AISv3 COPY library folder operation. (SH-4304) --- indra/llmessage/llhttpclient.cpp | 13 +++++++++++++ indra/llmessage/llhttpclient.h | 18 +++++++++++++++++- indra/llmessage/llhttpconstants.cpp | 6 +++++- indra/llmessage/llhttpconstants.h | 1 + indra/llmessage/llurlrequest.cpp | 10 ++++++++-- 5 files changed, 44 insertions(+), 4 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 53cef54559..70c890a8de 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -631,6 +631,19 @@ void LLHTTPClient::move( request(url, HTTP_MOVE, NULL, responder, timeout, headers); } +// static +void LLHTTPClient::copy( + const std::string& url, + const std::string& destination, + ResponderPtr responder, + const LLSD& hdrs, + const F32 timeout) +{ + LLSD headers = hdrs; + headers[HTTP_OUT_HEADER_DESTINATION] = destination; + request(url, HTTP_COPY, NULL, responder, timeout, headers); +} + void LLHTTPClient::setPump(LLPumpIO& pump) { diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 4e7495495f..5ace2d74c9 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -119,7 +119,7 @@ public: const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); ///< sends a DELETE method, but we can't call it delete in c++ - + /** * @brief Send a MOVE webdav method * @@ -136,6 +136,22 @@ public: const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + /** + * @brief Send a COPY webdav method + * + * @param url The complete serialized (and escaped) url to get. + * @param destination The complete serialized destination url. + * @param responder The responder that will handle the result. + * @param headers A map of key:value headers to pass to the request + * @param timeout The number of seconds to give the server to respond. + */ + static void copy( + const std::string& url, + const std::string& destination, + ResponderPtr responder, + const LLSD& headers = LLSD(), + const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + //@} /** diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp index 016f1f1970..01f4a080b0 100755 --- a/indra/llmessage/llhttpconstants.cpp +++ b/indra/llmessage/llhttpconstants.cpp @@ -133,6 +133,8 @@ const std::string HTTP_VERB_POST("POST"); const std::string HTTP_VERB_DELETE("DELETE"); const std::string HTTP_VERB_MOVE("MOVE"); const std::string HTTP_VERB_OPTIONS("OPTIONS"); +const std::string HTTP_VERB_PATCH("PATCH"); +const std::string HTTP_VERB_COPY("COPY"); const std::string& httpMethodAsVerb(EHTTPMethod method) { @@ -145,7 +147,9 @@ const std::string& httpMethodAsVerb(EHTTPMethod method) HTTP_VERB_POST, HTTP_VERB_DELETE, HTTP_VERB_MOVE, - HTTP_VERB_OPTIONS + HTTP_VERB_OPTIONS, + HTTP_VERB_PATCH, + HTTP_VERB_COPY }; if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT)) { diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h index aa947af414..4aa3cc6394 100755 --- a/indra/llmessage/llhttpconstants.h +++ b/indra/llmessage/llhttpconstants.h @@ -112,6 +112,7 @@ enum EHTTPMethod HTTP_MOVE, // Caller will need to set 'Destination' header HTTP_OPTIONS, HTTP_PATCH, + HTTP_COPY, HTTP_METHOD_COUNT }; diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index cadff49cb8..7bf930aeb0 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -516,13 +516,19 @@ bool LLURLRequest::configure() break; case HTTP_DELETE: - // Set the handle for an http post + // Set the handle for an http delete mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE"); rv = true; break; + case HTTP_COPY: + // Set the handle for an http copy + mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY"); + rv = true; + break; + case HTTP_MOVE: - // Set the handle for an http post + // Set the handle for an http move mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE"); // *NOTE: should we check for the Destination header? rv = true; -- cgit v1.2.3 From 9acc63001023c31d67e20d61d5ef2c67905a5c7c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 10 Dec 2013 16:25:37 -0500 Subject: fix for license wording --- indra/llmessage/tests/llhttpnode_stub.cpp | 33 +++++++++++++------------------ 1 file changed, 14 insertions(+), 19 deletions(-) mode change 100644 => 100755 indra/llmessage/tests/llhttpnode_stub.cpp (limited to 'indra/llmessage') diff --git a/indra/llmessage/tests/llhttpnode_stub.cpp b/indra/llmessage/tests/llhttpnode_stub.cpp old mode 100644 new mode 100755 index cc2108fed5..479a256bdd --- a/indra/llmessage/tests/llhttpnode_stub.cpp +++ b/indra/llmessage/tests/llhttpnode_stub.cpp @@ -2,31 +2,26 @@ * @file llhttpnode_stub.cpp * @brief STUB Implementation of classes for generic HTTP/LSL/REST handling. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * + * Second Life Viewer Source Code * Copyright (c) 2006-2009, Linden Research, Inc. * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -- cgit v1.2.3 From 5e225213f6bdb7b4ca97abfef99b2249a1f88638 Mon Sep 17 00:00:00 2001 From: Stinson Linden Date: Wed, 23 Apr 2014 17:57:23 +0100 Subject: MAINT-4009: Adding an ares cleanup call to free the allocated memory. --- indra/llmessage/llares.cpp | 9 +++++++++ indra/llmessage/llares.h | 1 + 2 files changed, 10 insertions(+) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 81e28121fd..9f90ae1544 100755 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -610,6 +610,15 @@ LLAres *ll_init_ares() return gAres; } +void ll_cleanup_ares() +{ + if (gAres != NULL) + { + delete gAres; + gAres = NULL; + } +} + LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name, unsigned ttl) : LLRefCount(), diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h index 800781ee88..0b5d49e322 100755 --- a/indra/llmessage/llares.h +++ b/indra/llmessage/llares.h @@ -578,5 +578,6 @@ extern LLAres *gAres; * thread safe. */ extern LLAres *ll_init_ares(); +extern void ll_cleanup_ares(); #endif // LL_LLARES_H -- cgit v1.2.3 From fd0e84296e1f20b90bc6e7c0ad4fbfcecf0aa6d9 Mon Sep 17 00:00:00 2001 From: Stinson Linden Date: Wed, 23 Apr 2014 19:36:08 +0100 Subject: MAINT-4009: Cleaning up the curl easy handle during shutdown. --- indra/llmessage/llcurl.cpp | 45 ++++++++++++++++++++++++++++++++++++--------- indra/llmessage/llcurl.h | 3 +++ 2 files changed, 39 insertions(+), 9 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 147940c983..161b7c1615 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -274,6 +274,36 @@ void LLCurl::Easy::releaseEasyHandle(CURL* handle) } } +//static +void LLCurl::Easy::deleteAllActiveHandles() +{ + LLMutexLock lock(sHandleMutexp) ; + LL_CHECK_MEMORY + for (std::set::iterator activeHandle = sActiveHandles.begin(); activeHandle != sActiveHandles.end(); ++activeHandle) + { + CURL* curlHandle = *activeHandle; + LLCurl::deleteEasyHandle(curlHandle); + LL_CHECK_MEMORY + } + + sFreeHandles.clear(); +} + +//static +void LLCurl::Easy::deleteAllFreeHandles() +{ + LLMutexLock lock(sHandleMutexp) ; + LL_CHECK_MEMORY + for (std::set::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle) + { + CURL* curlHandle = *freeHandle; + LLCurl::deleteEasyHandle(curlHandle); + LL_CHECK_MEMORY + } + + sFreeHandles.clear(); +} + LLCurl::Easy::Easy() : mHeaders(NULL), mCurlEasyHandle(NULL) @@ -1745,17 +1775,14 @@ void LLCurl::cleanupClass() #endif LL_CHECK_MEMORY - - for (std::set::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter) - { - CURL* curl = *iter; - LLCurl::deleteEasyHandle(curl); - } - + Easy::deleteAllFreeHandles(); + LL_CHECK_MEMORY + Easy::deleteAllActiveHandles(); LL_CHECK_MEMORY - Easy::sFreeHandles.clear(); - + // Free the template easy handle + curl_easy_cleanup(sCurlTemplateStandardHandle); + sCurlTemplateStandardHandle = NULL; LL_CHECK_MEMORY delete Easy::sHandleMutexp ; diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index fc9761ff9f..b033a3d4ab 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -269,6 +269,9 @@ private: static std::set sFreeHandles; static std::set sActiveHandles; static LLMutex* sHandleMutexp ; + + static void deleteAllActiveHandles(); + static void deleteAllFreeHandles(); }; class LLCurl::Multi -- cgit v1.2.3 From 582c10cc47f7a07b4de961e8ef954b5cc935cd16 Mon Sep 17 00:00:00 2001 From: Stinson Linden Date: Fri, 25 Apr 2014 23:30:53 +0100 Subject: MAINT-4009: Ensuring to delete array data with the array delete in the RawInjector destructor. --- indra/llmessage/llhttpclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 31a499b370..21d459b832 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -124,7 +124,7 @@ namespace { public: RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {} - virtual ~RawInjector() {delete mData;} + virtual ~RawInjector() {delete [] mData;} const char* contentType() { return "application/octet-stream"; } -- cgit v1.2.3 From 487ca1bad37883be0325b564ab557a8f77575388 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 14 May 2014 17:50:59 -0400 Subject: v-r -> s-e merge WIP --- indra/llmessage/llcurl.cpp | 8 ++++---- indra/llmessage/lliohttpserver.cpp | 2 +- indra/llmessage/llsdappservices.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 5f8581b4fd..a80d5a570e 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -261,8 +261,8 @@ void LLCurl::Responder::completedRaw( // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE))) { - llwarns << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] " - << "(" << mReason << ") body: " << debug_body << llendl; + LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] " + << "(" << mReason << ") body: " << debug_body << LL_ENDL; } httpCompleted(); @@ -543,7 +543,7 @@ void LLCurl::Easy::slist_append(const char* str) mHeaders = curl_slist_append(mHeaders, str); if (!mHeaders) { - llwarns << "curl_slist_append() call returned NULL appending " << str << llendl; + LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL; } } } @@ -934,7 +934,7 @@ S32 LLCurl::Multi::process() else { response = HTTP_INTERNAL_ERROR; - //*TODO: change to llwarns + //*TODO: change to LL_WARNS() LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL; } if (response >= 400) diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index cdd8d25f16..d9042fa8b0 100755 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -352,7 +352,7 @@ void LLHTTPPipe::Response::extendedResult(S32 code, const LLSD& r, const LLSD& h { if(! mPipe) { - llwarns << "LLHTTPPipe::Response::extendedResult: NULL pipe" << llendl; + LL_WARNS() << "LLHTTPPipe::Response::extendedResult: NULL pipe" << LL_ENDL; return; } diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index 577429a941..4ca45267bd 100755 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -120,7 +120,7 @@ public: virtual bool validate(const std::string& name, LLSD& context) const { //LL_INFOS() << "validate: " << name << ", " - // << LLSDOStreamer(context) << llendl; + // << LLSDOStreamer(context) << LL_ENDL; if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty()) { return true; -- cgit v1.2.3 From 7f3e1b73137d51e27075c6a71c25c4eafd6cb21c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 16 May 2014 13:28:22 -0400 Subject: merge fix --- indra/llmessage/llsdrpcclient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llmessage') diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index 84cd7fb851..c4e0333ca3 100755 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -240,7 +240,7 @@ public: virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const { LL_DEBUGS() << "LLSDRPCClientFactory::build" << LL_ENDL; - LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); + LLURLRequest* http(new LLURLRequest(HTTP_POST)); if(!http->isValid()) { LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ; -- cgit v1.2.3