diff options
author | Aaron Brashears <aaronb@lindenlab.com> | 2009-05-18 23:38:35 +0000 |
---|---|---|
committer | Aaron Brashears <aaronb@lindenlab.com> | 2009-05-18 23:38:35 +0000 |
commit | 6df2755ba6b24d0cefd52ce175b0212dd46c9b10 (patch) | |
tree | 833bc29e7bd5438eb89f34119ae157efe6258b2c /indra/llmessage | |
parent | 0257214763203708e8e29d09346e777b95cdfce6 (diff) |
Result of svn merge -r119432:120464 svn+ssh://svn/svn/linden/branches/http_database/merge-03 into trunk. QAR-1462
Diffstat (limited to 'indra/llmessage')
-rw-r--r-- | indra/llmessage/llhttpclient.cpp | 140 | ||||
-rw-r--r-- | indra/llmessage/llhttpclient.h | 8 | ||||
-rw-r--r-- | indra/llmessage/llmessageconfig.cpp | 7 | ||||
-rw-r--r-- | indra/llmessage/llurlrequest.cpp | 20 | ||||
-rw-r--r-- | indra/llmessage/llurlrequest.h | 5 | ||||
-rw-r--r-- | indra/llmessage/message.h | 16 |
6 files changed, 159 insertions, 37 deletions
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 307d9b92fa..8b90a4c5ca 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -224,6 +224,10 @@ static void request( LLURLRequest* req = new LLURLRequest(method, url); req->checkRootCertificate(true); + + lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " + << headers << llendl; + // Insert custom headers is the caller sent any if (headers.isMap()) { @@ -375,72 +379,140 @@ private: std::string mBuffer; }; -// *TODO: Deprecate (only used by dataserver) -// This call is blocking! This is probably usually bad. :( -LLSD LLHTTPClient::blockingGet(const std::string& url) +// These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome. + +/** + @brief does a blocking request on the url, returning the data or bad status. + + @param url URI to verb on. + @param method the verb to hit the URI with. + @param body the body of the call (if needed - for instance not used for GET and DELETE, but is for POST and PUT) + @param headers HTTP headers to use for the request. + @param timeout Curl timeout to use. Defaults to 5. Rationale: + Without this timeout, blockingGet() calls have been observed to take + up to 90 seconds to complete. Users of blockingGet() already must + check the HTTP return code for validity, so this will not introduce + new errors. A 5 second timeout will succeed > 95% of the time (and + probably > 99% of the time) based on my statistics. JC + + @returns an LLSD map: {status: integer, body: map} + */ +static LLSD blocking_request( + const std::string& url, + LLURLRequest::ERequestAction method, + const LLSD& body, + const LLSD& headers = LLSD(), + const F32 timeout = 5 +) { - llinfos << "blockingGet of " << url << llendl; - - // Returns an LLSD map: {status: integer, body: map} - char curl_error_buffer[CURL_ERROR_SIZE]; + lldebugs << "blockingRequest of " << url << llendl; + char curl_error_buffer[CURL_ERROR_SIZE] = "\0"; CURL* curlp = curl_easy_init(); - LLHTTPBuffer http_buffer; - - // Without this timeout, blockingGet() calls have been observed to take - // up to 90 seconds to complete. Users of blockingGet() already must - // check the HTTP return code for validity, so this will not introduce - // new errors. A 5 second timeout will succeed > 95% of the time (and - // probably > 99% of the time) based on my statistics. JC + std::string body_str; + + // other request method checks root cert first, we skip? + //req->checkRootCertificate(true); + + // * Set curl handle options curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts - curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 5); // seconds - + curl_easy_setopt(curlp, CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function. curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, LLHTTPBuffer::curl_write); curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer); curl_easy_setopt(curlp, CURLOPT_URL, url.c_str()); curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer); - curl_easy_setopt(curlp, CURLOPT_FAILONERROR, 1); - - struct curl_slist *header_list = NULL; - header_list = curl_slist_append(header_list, "Accept: application/llsd+xml"); - CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, header_list); + + // * Setup headers (don't forget to free them after the call!) + curl_slist* headers_list = NULL; + if (headers.isMap()) + { + LLSD::map_const_iterator iter = headers.beginMap(); + LLSD::map_const_iterator end = headers.endMap(); + for (; iter != end; ++iter) + { + std::ostringstream header; + header << iter->first << ": " << iter->second.asString() ; + lldebugs << "header = " << header.str() << llendl; + headers_list = curl_slist_append(headers_list, header.str().c_str()); + } + } + + // * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy) + if (method == LLURLRequest::HTTP_GET) + { + curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1); + } + else if (method == LLURLRequest::HTTP_POST) + { + curl_easy_setopt(curlp, CURLOPT_POST, 1); + //serialize to ostr then copy to str - need to because ostr ptr is unstable :( + std::ostringstream ostr; + LLSDSerialize::toXML(body, ostr); + 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"); + + // 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:"); + } + + // * Do the action using curl, handle results + lldebugs << "HTTP body: " << body_str << llendl; + headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml"); + CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list); if ( curl_result != CURLE_OK ) { - llinfos << "Curl is hosed - can't add Accept header for llsd+xml" << llendl; + llinfos << "Curl is hosed - can't add headers" << llendl; } LLSD response = LLSD::emptyMap(); - S32 curl_success = curl_easy_perform(curlp); - S32 http_status = 499; - curl_easy_getinfo(curlp,CURLINFO_RESPONSE_CODE, &http_status); - + curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status); response["status"] = http_status; - - if (curl_success != 0 - && http_status != 404) // We expect 404s, don't spam for them. + // 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) ) { + // We expect 404s, don't spam for them. + llwarns << "CURL REQ URL: " << url << llendl; + llwarns << "CURL REQ METHOD TYPE: " << method << llendl; + llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl; + llwarns << "CURL REQ BODY: " << body_str << llendl; + llwarns << "CURL HTTP_STATUS: " << http_status << llendl; llwarns << "CURL ERROR: " << curl_error_buffer << llendl; - + llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl; response["body"] = http_buffer.asString(); } else { response["body"] = http_buffer.asLLSD(); + lldebugs << "CURL response: " << http_buffer.asString() << llendl; } - if(header_list) + if(headers_list) { // free the header list - curl_slist_free_all(header_list); - header_list = NULL; + curl_slist_free_all(headers_list); } + // * Cleanup curl_easy_cleanup(curlp); - return response; } +LLSD LLHTTPClient::blockingGet(const std::string& url) +{ + return blocking_request(url, LLURLRequest::HTTP_GET, LLSD()); +} + +LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) +{ + return blocking_request(url, LLURLRequest::HTTP_POST, body); +} + void LLHTTPClient::put( const std::string& url, const LLSD& body, diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index a0c9fac77f..3d0646e5fe 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -142,6 +142,14 @@ public: */ static LLSD blockingGet(const std::string& url); + /** + * @brief Blocking HTTP POST that returns an LLSD map of status and body. + * + * @param url the complete serialized (and escaped) url to get + * @param body the LLSD post body + * @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) } + */ + static LLSD blockingPost(const std::string& url, const LLSD& body); static void setPump(LLPumpIO& pump); diff --git a/indra/llmessage/llmessageconfig.cpp b/indra/llmessage/llmessageconfig.cpp index d4279354b6..dff0a3844c 100644 --- a/indra/llmessage/llmessageconfig.cpp +++ b/indra/llmessage/llmessageconfig.cpp @@ -66,7 +66,7 @@ public: static LLMessageConfigFile& instance(); // return the singleton configuration file - /* virtual */ void loadFile(); + /* virtual */ bool loadFile(); void loadServerDefaults(const LLSD& data); void loadMaxQueuedEvents(const LLSD& data); void loadMessages(const LLSD& data); @@ -98,7 +98,7 @@ LLMessageConfigFile& LLMessageConfigFile::instance() } // virtual -void LLMessageConfigFile::loadFile() +bool LLMessageConfigFile::loadFile() { LLSD data; { @@ -115,7 +115,7 @@ void LLMessageConfigFile::loadFile() LL_INFOS("AppInit") << "LLMessageConfigFile::loadFile: file missing," " ill-formed, or simply undefined; not changing the" " file" << LL_ENDL; - return; + return false; } } loadServerDefaults(data); @@ -123,6 +123,7 @@ void LLMessageConfigFile::loadFile() loadMessages(data); loadCapBans(data); loadMessageBans(data); + return true; } void LLMessageConfigFile::loadServerDefaults(const LLSD& data) diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 46e976fe35..3ab8057abb 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -98,6 +98,26 @@ LLURLRequestDetail::~LLURLRequestDetail() * 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) : mAction(action) { diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index d1facbff0f..86ef71f085 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -81,6 +81,11 @@ public: REQUEST_ACTION_COUNT }; + /** + * @brief Turn the requst action into an http verb. + */ + static std::string actionAsVerb(ERequestAction action); + /** * @brief Constructor. * diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index b25b27eb0f..0f3576732d 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -509,6 +509,22 @@ private: public: // BOOL decodeData(const U8 *buffer, const LLHost &host); + /** + gets binary data from the current message. + + @param blockname the name of the block in the message (from the message template) + + @param varname + + @param datap + + @param size expected size - set to zero to get any amount of data up to max_size. + Make sure max_size is set in that case! + + @param blocknum + + @param max_size the max number of bytes to read + */ void getBinaryDataFast(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX); void getBinaryData(const char *blockname, const char *varname, void *datap, S32 size, S32 blocknum = 0, S32 max_size = S32_MAX); void getBOOLFast( const char *block, const char *var, BOOL &data, S32 blocknum = 0); |