diff options
Diffstat (limited to 'indra/llmessage/llcurl.cpp')
-rw-r--r-- | indra/llmessage/llcurl.cpp | 173 |
1 files changed, 105 insertions, 68 deletions
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 8b9a45ff3f..a485fa0160 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -4,30 +4,25 @@ * @date 2006-10-15 * @brief Implementation of wrapper around libcurl. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&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://secondlife.com/developers/opensource/gplv2 + * 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. * - * 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://secondlife.com/developers/opensource/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$ */ @@ -73,7 +68,7 @@ ////////////////////////////////////////////////////////////////////////////// -static const S32 EASY_HANDLE_POOL_SIZE = 5; +static const U32 EASY_HANDLE_POOL_SIZE = 5; static const S32 MULTI_PERFORM_CALL_REPEAT = 5; static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; @@ -101,6 +96,12 @@ void LLCurl::setCAFile(const std::string& file) sCAFile = file; } +//static +std::string LLCurl::getVersionString() +{ + return std::string(curl_version()); +} + ////////////////////////////////////////////////////////////////////////////// LLCurl::Responder::Responder() @@ -113,50 +114,45 @@ LLCurl::Responder::~Responder() } // virtual +void LLCurl::Responder::errorWithContent( + U32 status, + const std::string& reason, + const LLSD&) +{ + error(status, reason); +} + +// virtual void LLCurl::Responder::error(U32 status, const std::string& reason) { - llinfos << status << ": " << reason << llendl; + llinfos << mURL << " [" << status << "]: " << reason << llendl; } // virtual void LLCurl::Responder::result(const LLSD& content) { - llwarns << "Virtual Function not implemented" << llendl; } -// virtual -void LLCurl::Responder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLCurl::Responder::setURL(const std::string& url) { - if (isGoodStatus(status)) - { - LLSD content; - LLBufferStream istr(channels, buffer.get()); - LLSDSerialize::fromXML(content, istr); -/* - const S32 parseError = -1; - if(LLSDSerialize::fromXML(content, istr) == parseError) - { - mStatus = 498; - mReason = "Client Parse Error"; - } -*/ - completed(status, reason, content); - } - else if (status == 400) - { - // Get reason from buffer - char tbuf[4096]; - S32 len = 4096; - buffer->readAfter(channels.in(), NULL, (U8*)tbuf, len); - tbuf[len] = 0; - completed(status, std::string(tbuf), LLSD()); - } - else + mURL = url; +} + +// 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()); + if (!LLSDSerialize::fromXML(content, istr)) { - completed(status, reason, LLSD()); + llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; } + + completed(status, reason, content); } // virtual @@ -168,7 +164,7 @@ void LLCurl::Responder::completed(U32 status, const std::string& reason, const L } else { - error(status, reason); + errorWithContent(status, reason, content); } } @@ -227,7 +223,7 @@ public: U32 report(CURLcode); void getTransferInfo(LLCurl::TransferInfo* info); - void prepRequest(const std::string& url, ResponderPtr, bool post = false); + void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, bool post = false); const char* getErrorBuffer(); @@ -273,6 +269,10 @@ LLCurl::Easy* LLCurl::Easy::getEasy() delete easy; return NULL; } + + // set no DMS caching as default for all easy handles. This prevents them adopting a + // multi handles cache if they are added to one. + curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0); ++gCurlEasyCount; return easy; } @@ -282,7 +282,7 @@ LLCurl::Easy::~Easy() curl_easy_cleanup(mCurlEasyHandle); --gCurlEasyCount; curl_slist_free_all(mHeaders); - for_each(mStrings.begin(), mStrings.end(), DeletePointer()); + for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); } void LLCurl::Easy::resetState() @@ -358,7 +358,7 @@ U32 LLCurl::Easy::report(CURLcode code) responseCode = 499; responseReason = strerror(code) + " : " + mErrorBuffer; } - + if (mResponder) { mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput); @@ -435,7 +435,9 @@ size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data return n; } -void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, bool post) +void LLCurl::Easy::prepRequest(const std::string& url, + const std::vector<std::string>& headers, + ResponderPtr responder, bool post) { resetState(); @@ -454,6 +456,13 @@ void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, b setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback); setopt(CURLOPT_HEADERDATA, (void*)this); + // Allow up to five redirects + if(responder && responder->followRedir()) + { + setopt(CURLOPT_FOLLOWLOCATION, 1); + setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS); + } + setErrorBuffer(); setCA(); @@ -468,8 +477,13 @@ void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, b { slist_append("Connection: keep-alive"); slist_append("Keep-alive: 300"); + // Accept and other headers + for (std::vector<std::string>::const_iterator iter = headers.begin(); + iter != headers.end(); ++iter) + { + slist_append((*iter).c_str()); + } } - // *FIX: should have ACCEPT headers } //////////////////////////////////////////////////////////////////////////// @@ -675,18 +689,22 @@ std::string LLCurl::strerror(CURLcode errorcode) // For generating a simple request for data // using one multi and one easy per request -LLCurlRequest::LLCurlRequest() - : mActiveMulti(NULL) +LLCurlRequest::LLCurlRequest() : + mActiveMulti(NULL), + mActiveRequestCount(0) { + mThreadID = LLThread::currentID(); } LLCurlRequest::~LLCurlRequest() { + llassert_always(mThreadID == LLThread::currentID()); for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer()); } void LLCurlRequest::addMulti() { + llassert_always(mThreadID == LLThread::currentID()); LLCurl::Multi* multi = new LLCurl::Multi(); mMultiSet.insert(multi); mActiveMulti = multi; @@ -716,17 +734,20 @@ bool LLCurlRequest::addEasy(LLCurl::Easy* easy) void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder) { - getByteRange(url, 0, -1, responder); + getByteRange(url, headers_t(), 0, -1, responder); } -bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length, LLCurl::ResponderPtr responder) +bool LLCurlRequest::getByteRange(const std::string& url, + const headers_t& headers, + S32 offset, S32 length, + LLCurl::ResponderPtr responder) { LLCurl::Easy* easy = allocEasy(); if (!easy) { return false; } - easy->prepRequest(url, responder); + easy->prepRequest(url, headers, responder); easy->setopt(CURLOPT_HTTPGET, 1); if (length > 0) { @@ -738,14 +759,17 @@ bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length, return res; } -bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::ResponderPtr responder) +bool LLCurlRequest::post(const std::string& url, + const headers_t& headers, + const LLSD& data, + LLCurl::ResponderPtr responder) { LLCurl::Easy* easy = allocEasy(); if (!easy) { return false; } - easy->prepRequest(url, responder); + easy->prepRequest(url, headers, responder); LLSDSerialize::toXML(data, easy->getInput()); S32 bytes = easy->getInput().str().length(); @@ -754,7 +778,7 @@ bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::Respo easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL); easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); - easy->slist_append("Content-Type: application/xml"); + easy->slist_append("Content-Type: application/llsd+xml"); easy->setHeaders(); lldebugs << "POSTING: " << bytes << " bytes." << llendl; @@ -765,6 +789,7 @@ bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::Respo // Note: call once per frame S32 LLCurlRequest::process() { + llassert_always(mThreadID == LLThread::currentID()); S32 res = 0; for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ) @@ -784,6 +809,7 @@ S32 LLCurlRequest::process() S32 LLCurlRequest::getQueued() { + llassert_always(mThreadID == LLThread::currentID()); S32 queued = 0; for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ) @@ -870,6 +896,15 @@ void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userd } } +void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata) +{ + if (mEasy) + { + mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback); + mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata); + } +} + void LLCurlEasyRequest::slist_append(const char* str) { if (mEasy) @@ -882,6 +917,7 @@ void LLCurlEasyRequest::sendRequest(const std::string& url) { llassert_always(!mRequestSent); mRequestSent = true; + lldebugs << url << llendl; if (mEasy) { mEasy->setHeaders(); @@ -1003,7 +1039,7 @@ void LLCurl::initClass() S32 mutex_count = CRYPTO_num_locks(); for (S32 i=0; i<mutex_count; i++) { - sSSLMutex.push_back(new LLMutex(gAPRPoolp)); + sSSLMutex.push_back(new LLMutex(NULL)); } CRYPTO_set_id_callback(&LLCurl::ssl_thread_id); CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback); @@ -1019,3 +1055,4 @@ void LLCurl::cleanupClass() curl_global_cleanup(); } +const unsigned int LLCurl::MAX_REDIRECTS = 5; |