diff options
Diffstat (limited to 'indra/llmessage/llcurl.cpp')
-rwxr-xr-x | indra/llmessage/llcurl.cpp | 255 |
1 files changed, 197 insertions, 58 deletions
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 147940c983..73df47b933 100755 --- 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" @@ -100,7 +101,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). - LL_INFOS() << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL; + LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL; } } @@ -110,7 +111,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). - LL_INFOS() << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL; + LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL; } } @@ -135,6 +136,7 @@ std::string LLCurl::getVersionString() ////////////////////////////////////////////////////////////////////////////// LLCurl::Responder::Responder() + : mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR) { } @@ -144,22 +146,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 { - LL_INFOS() << mURL << " [" << status << "]: " << reason << LL_ENDL; + std::ostringstream s; + s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] " + << "[status:" << mStatus << "] " + << "[reason:" << mReason << "] "; + + if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) + { + s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] "; + } + + s << "[content:" << mContent << "]"; + + return s.str(); } // virtual -void LLCurl::Responder::result(const LLSD& content) +void LLCurl::Responder::httpSuccess() { } @@ -168,44 +178,109 @@ 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) const +{ + if (mResponseHeaders.has(header)) + { + return mResponseHeaders[header].asStringRef(); + } + static const std::string empty; + return empty; +} + +bool LLCurl::Responder::hasResponseHeader(const std::string& header) const +{ + if (mResponseHeaders.has(header)) return true; + 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 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))) { - LL_INFOS() << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << LL_ENDL; - content["reason"] = reason; + LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] " + << "(" << mReason << ") body: " << debug_body << LL_ENDL; } - 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<CURL*> LLCurl::Easy::sFreeHandles; @@ -274,6 +349,36 @@ void LLCurl::Easy::releaseEasyHandle(CURL* handle) } } +//static +void LLCurl::Easy::deleteAllActiveHandles() +{ + LLMutexLock lock(sHandleMutexp) ; + LL_CHECK_MEMORY + for (std::set<CURL*>::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<CURL*>::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) @@ -289,7 +394,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) - LL_WARNS() << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; + LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: " + << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; delete easy; return NULL; } @@ -317,10 +423,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; @@ -384,9 +494,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) @@ -396,14 +506,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; } @@ -440,9 +551,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) + { + LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL; + } + } } size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) @@ -530,8 +663,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_OUT_HEADER_CONNECTION, "keep-alive"); + slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300"); // Accept and other headers for (std::vector<std::string>::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) @@ -810,7 +944,7 @@ S32 LLCurl::Multi::process() ++processed; if (msg->msg == CURLMSG_DONE) { - U32 response = 0; + S32 response = 0; Easy* easy = NULL ; { @@ -829,7 +963,7 @@ S32 LLCurl::Multi::process() } else { - response = 499; + response = HTTP_INTERNAL_ERROR; //*TODO: change to LL_WARNS() LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL; } @@ -1128,13 +1262,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_OUT_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_OUT_HEADER_RANGE, range); } easy->setHeaders(); bool res = addEasy(easy); @@ -1161,7 +1295,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_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); easy->setHeaders(); LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; @@ -1189,7 +1323,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_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM); easy->setHeaders(); LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; @@ -1561,6 +1695,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) @@ -1745,17 +1887,14 @@ void LLCurl::cleanupClass() #endif LL_CHECK_MEMORY - - for (std::set<CURL*>::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 ; |