MAINT-5507: Remove llcurl, move constant values and untilities to llcorehttp lib

master
Rider Linden 2015-09-15 17:01:26 -07:00
parent 5f7985f6a7
commit 907efc9cc9
29 changed files with 276 additions and 678 deletions

View File

@ -26,6 +26,7 @@ set(llcorehttp_SOURCE_FILES
bufferarray.cpp
bufferstream.cpp
httpcommon.cpp
llhttpconstants.cpp
httpheaders.cpp
httpoptions.cpp
httprequest.cpp
@ -51,6 +52,7 @@ set(llcorehttp_HEADER_FILES
bufferarray.h
bufferstream.h
httpcommon.h
llhttpconstants.h
httphandler.h
httpheaders.h
httpoptions.h

View File

@ -23,12 +23,24 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if LL_WINDOWS
#define SAFE_SSL 1
#elif LL_DARWIN
#define SAFE_SSL 1
#else
#define SAFE_SSL 1
#endif
#include "linden_common.h" // Modifies curl/curl.h interfaces
#include "httpcommon.h"
#include "llmutex.h"
#include "llthread.h"
#include <curl/curl.h>
#include <string>
#include <sstream>
#if SAFE_SSL
#include <openssl/crypto.h>
#endif
namespace LLCore
@ -263,5 +275,151 @@ bool HttpStatus::isRetryable() const
*this == inv_cont_range); // Short data read disagrees with content-range
}
} // end namespace LLCore
namespace LLHttp
{
namespace
{
typedef boost::shared_ptr<LLMutex> LLMutex_ptr;
std::vector<LLMutex_ptr> sSSLMutex;
CURL *getCurlTemplateHandle()
{
static CURL *curlpTemplateHandle = NULL;
if (curlpTemplateHandle == NULL)
{ // Late creation of the template curl handle
curlpTemplateHandle = curl_easy_init();
if (curlpTemplateHandle == NULL)
{
LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL;
}
else
{
CURLcode result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
check_curl_code(result, CURLOPT_IPRESOLVE);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOSIGNAL, 1);
check_curl_code(result, CURLOPT_NOSIGNAL);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_NOPROGRESS, 1);
check_curl_code(result, CURLOPT_NOPROGRESS);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_ENCODING, "");
check_curl_code(result, CURLOPT_ENCODING);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_AUTOREFERER, 1);
check_curl_code(result, CURLOPT_AUTOREFERER);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_FOLLOWLOCATION, 1);
check_curl_code(result, CURLOPT_FOLLOWLOCATION);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYPEER, 1);
check_curl_code(result, CURLOPT_SSL_VERIFYPEER);
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_SSL_VERIFYHOST, 0);
check_curl_code(result, CURLOPT_SSL_VERIFYHOST);
// The Linksys WRT54G V5 router has an issue with frequent
// DNS lookups from LAN machines. If they happen too often,
// like for every HTTP request, the router gets annoyed after
// about 700 or so requests and starts issuing TCP RSTs to
// new connections. Reuse the DNS lookups for even a few
// seconds and no RSTs.
result = curl_easy_setopt(curlpTemplateHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
check_curl_code(result, CURLOPT_DNS_CACHE_TIMEOUT);
}
}
return curlpTemplateHandle;
}
LLMutex *getCurlMutex()
{
static LLMutex* sHandleMutexp = NULL;
if (!sHandleMutexp)
{
sHandleMutexp = new LLMutex(NULL);
}
return sHandleMutexp;
}
void deallocateEasyCurl(CURL *curlp)
{
LLMutexLock lock(getCurlMutex());
curl_easy_cleanup(curlp);
}
#if SAFE_SSL
//static
void ssl_locking_callback(int mode, int type, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
{
sSSLMutex[type]->lock();
}
else
{
sSSLMutex[type]->unlock();
}
}
//static
unsigned long ssl_thread_id(void)
{
return LLThread::currentID();
}
#endif
}
void initialize()
{
// Do not change this "unless you are familiar with and mean to control
// internal operations of libcurl"
// - http://curl.haxx.se/libcurl/c/curl_global_init.html
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
check_curl_code(code, CURL_GLOBAL_ALL);
#if SAFE_SSL
S32 mutex_count = CRYPTO_num_locks();
for (S32 i = 0; i < mutex_count; i++)
{
sSSLMutex.push_back(LLMutex_ptr(new LLMutex(NULL)));
}
CRYPTO_set_id_callback(&ssl_thread_id);
CRYPTO_set_locking_callback(&ssl_locking_callback);
#endif
}
CURL_ptr createEasyHandle()
{
LLMutexLock lock(getCurlMutex());
CURL* handle = curl_easy_duphandle(getCurlTemplateHandle());
return CURL_ptr(handle, &deallocateEasyCurl);
}
std::string getCURLVersion()
{
return std::string(curl_version());
}
void check_curl_code(CURLcode code, int curl_setopt_option)
{
if (CURLE_OK != code)
{
// Comment from old llcurl code which may no longer apply:
//
// linux appears to throw a curl error once per session for a bad initialization
// at a pretty random time (when enabling cookies).
LL_WARNS() << "libcurl error detected: " << curl_easy_strerror(code)
<< ", curl_easy_setopt option: " << curl_setopt_option
<< LL_ENDL;
}
}
}
} // end namespace LLCore

View File

@ -193,6 +193,7 @@
#include "boost/weak_ptr.hpp"
#include "boost/function.hpp"
#include <string>
#include <curl/curl.h>
namespace LLCore
{
@ -490,6 +491,19 @@ private:
}; // end struct HttpStatus
/// A namespace for several free methods and low level utilities.
namespace LLHttp
{
typedef boost::shared_ptr<CURL> CURL_ptr;
void initialize();
CURL_ptr createEasyHandle();
std::string getCURLVersion();
void check_curl_code(CURLcode code, int curl_setopt_option);
}
} // end namespace LLCore
#endif // _LLCORE_HTTP_COMMON_H_

View File

@ -133,94 +133,3 @@ 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)
{
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,
HTTP_VERB_PATCH,
HTTP_VERB_COPY
};
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 = (F64)date - LLTimer::getTotalSeconds();
return true;
}

View File

@ -116,13 +116,6 @@ enum EHTTPMethod
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);

View File

@ -214,11 +214,13 @@ void LLCrashLogger::gatherFiles()
mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
if(mDebugLog.has("CAFilename"))
{
LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
LLCore::HttpRequest::GLOBAL_POLICY_ID, mDebugLog["CAFilename"].asString(), NULL);
}
else
{
LLCurl::setCAFile(gDirUtilp->getCAFile());
LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
}
LL_INFOS() << "Using log file from debug log " << mFileMap["SecondLifeLog"] << LL_ENDL;
@ -227,7 +229,8 @@ void LLCrashLogger::gatherFiles()
else
{
// Figure out the filename of the second life log
LLCurl::setCAFile(gDirUtilp->getCAFile());
LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_CA_FILE,
LLCore::HttpRequest::GLOBAL_POLICY_ID, gDirUtilp->getCAFile(), NULL);
mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_DUMP,"SecondLife.log");
mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
@ -531,7 +534,7 @@ void LLCrashLogger::updateApplication(const std::string& message)
bool LLCrashLogger::init()
{
LLCurl::initClass(false);
LLCore::LLHttp::initialize();
// We assume that all the logs we're looking for reside on the current drive
gDirUtilp->initAppDirs("SecondLife");

View File

@ -42,13 +42,11 @@ set(llmessage_SOURCE_FILES
llclassifiedflags.cpp
llcoproceduremanager.cpp
llcorehttputil.cpp
llcurl.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
llhttpconstants.cpp
llhttpnode.cpp
llhttpsdhandler.cpp
llinstantmessage.cpp
@ -126,7 +124,6 @@ set(llmessage_HEADER_FILES
llclassifiedflags.h
llcoproceduremanager.h
llcorehttputil.h
llcurl.h
lldatapacker.h
lldbstrings.h
lldispatcher.h
@ -136,7 +133,6 @@ set(llmessage_HEADER_FILES
llfiltersd2xmlrpc.h
llfollowcamparams.h
llhost.h
llhttpconstants.h
llhttpnode.h
llhttpnodeadapter.h
llhttpsdhandler.h

View File

@ -1,360 +0,0 @@
/**
* @file llcurl.cpp
* @author Zero / Donovan
* @date 2006-10-15
* @brief Implementation of wrapper around libcurl.
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010-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$
*/
#if LL_WINDOWS
#define SAFE_SSL 1
#elif LL_DARWIN
#define SAFE_SSL 1
#else
#define SAFE_SSL 1
#endif
#include "linden_common.h"
#include "llcurl.h"
#include <algorithm>
#include <iomanip>
#include <curl/curl.h>
#if SAFE_SSL
#include <openssl/crypto.h>
#endif
#include "llbufferstream.h"
#include "llproxy.h"
#include "llsdserialize.h"
#include "llstl.h"
#include "llstring.h"
#include "llthread.h"
#include "lltimer.h"
//////////////////////////////////////////////////////////////////////////////
/*
The trick to getting curl to do keep-alives is to reuse the
same easy handle for the requests. It appears that curl
keeps a pool of connections alive for each easy handle, but
doesn't share them between easy handles. Therefore it is
important to keep a pool of easy handles and reuse them,
rather than create and destroy them with each request. This
code does this.
Furthermore, it would behoove us to keep track of which
hosts an easy handle was used for and pick an easy handle
that matches the next request. This code does not current
do this.
*/
// *TODO: TSN remove the commented code from this file
//////////////////////////////////////////////////////////////////////////////
//static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
// DEBUG //
S32 gCurlEasyCount = 0;
S32 gCurlMultiCount = 0;
//////////////////////////////////////////////////////////////////////////////
//static
std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
//LLCurlThread* LLCurl::sCurlThread = NULL ;
LLMutex* LLCurl::sHandleMutexp = NULL ;
S32 LLCurl::sTotalHandles = 0 ;
bool LLCurl::sNotQuitting = true;
F32 LLCurl::sCurlRequestTimeOut = 120.f; //seonds
S32 LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined).
CURL* LLCurl::sCurlTemplateStandardHandle = NULL;
void check_curl_code(CURLcode code)
{
if (code != CURLE_OK)
{
// linux appears to throw a curl error once per session for a bad initialization
// at a pretty random time (when enabling cookies).
LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;
}
}
void check_curl_multi_code(CURLMcode code)
{
if (code != CURLM_OK)
{
// linux appears to throw a curl error once per session for a bad initialization
// at a pretty random time (when enabling cookies).
LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;
}
}
//static
void LLCurl::setCAPath(const std::string& path)
{
sCAPath = path;
}
//static
void LLCurl::setCAFile(const std::string& file)
{
sCAFile = file;
}
//static
std::string LLCurl::getVersionString()
{
return std::string(curl_version());
}
//static
std::string LLCurl::strerror(CURLcode errorcode)
{
return std::string(curl_easy_strerror(errorcode));
}
////////////////////////////////////////////////////////////////////////////
#if SAFE_SSL
//static
void LLCurl::ssl_locking_callback(int mode, int type, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
{
LLCurl::sSSLMutex[type]->lock();
}
else
{
LLCurl::sSSLMutex[type]->unlock();
}
}
//static
unsigned long LLCurl::ssl_thread_id(void)
{
return LLThread::currentID();
}
#endif
void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool multi_threaded)
{
sCurlRequestTimeOut = curl_reuest_timeout ; //seconds
sMaxHandles = max_number_handles ; //max number of handles, (multi handles and easy handles combined).
// Do not change this "unless you are familiar with and mean to control
// internal operations of libcurl"
// - http://curl.haxx.se/libcurl/c/curl_global_init.html
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
check_curl_code(code);
#if SAFE_SSL
S32 mutex_count = CRYPTO_num_locks();
for (S32 i=0; i<mutex_count; i++)
{
sSSLMutex.push_back(new LLMutex(NULL));
}
CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
#endif
// sCurlThread = new LLCurlThread(multi_threaded) ;
if(multi_threaded)
{
sHandleMutexp = new LLMutex(NULL) ;
// Easy::sHandleMutexp = new LLMutex(NULL) ;
}
}
void LLCurl::cleanupClass()
{
sNotQuitting = false; //set quitting
//shut down curl thread
// while(1)
// {
// if(!sCurlThread->update(1)) //finish all tasks
// {
// break ;
// }
// }
LL_CHECK_MEMORY
// sCurlThread->shutdown() ;
LL_CHECK_MEMORY
// delete sCurlThread ;
// sCurlThread = NULL ;
LL_CHECK_MEMORY
#if SAFE_SSL
CRYPTO_set_locking_callback(NULL);
for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
sSSLMutex.clear();
#endif
LL_CHECK_MEMORY
// Free the template easy handle
curl_easy_cleanup(sCurlTemplateStandardHandle);
sCurlTemplateStandardHandle = NULL;
LL_CHECK_MEMORY
delete sHandleMutexp ;
sHandleMutexp = NULL ;
LL_CHECK_MEMORY
// removed as per https://jira.secondlife.com/browse/SH-3115
//llassert(Easy::sActiveHandles.empty());
}
//static
CURLM* LLCurl::newMultiHandle()
{
llassert(sNotQuitting);
LLMutexLock lock(sHandleMutexp) ;
if(sTotalHandles + 1 > sMaxHandles)
{
LL_WARNS() << "no more handles available." << LL_ENDL ;
return NULL ; //failed
}
sTotalHandles++;
CURLM* ret = curl_multi_init() ;
if(!ret)
{
LL_WARNS() << "curl_multi_init failed." << LL_ENDL ;
}
return ret ;
}
//static
CURLMcode LLCurl::deleteMultiHandle(CURLM* handle)
{
if(handle)
{
LLMutexLock lock(sHandleMutexp) ;
sTotalHandles-- ;
return curl_multi_cleanup(handle) ;
}
return CURLM_OK ;
}
//static
CURL* LLCurl::newEasyHandle()
{
llassert(sNotQuitting);
LLMutexLock lock(sHandleMutexp) ;
if(sTotalHandles + 1 > sMaxHandles)
{
LL_WARNS() << "no more handles available." << LL_ENDL ;
return NULL ; //failed
}
sTotalHandles++;
CURL* ret = createStandardCurlHandle();
if(!ret)
{
LL_WARNS() << "failed to create curl handle." << LL_ENDL ;
}
return ret ;
}
//static
void LLCurl::deleteEasyHandle(CURL* handle)
{
if(handle)
{
LLMutexLock lock(sHandleMutexp) ;
LL_CHECK_MEMORY
curl_easy_cleanup(handle) ;
LL_CHECK_MEMORY
sTotalHandles-- ;
}
}
const unsigned int LLCurl::MAX_REDIRECTS = 5;
// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
void LLCurlFF::check_easy_code(CURLcode code)
{
check_curl_code(code);
}
// void LLCurlFF::check_multi_code(CURLMcode code)
// {
// check_curl_multi_code(code);
// }
// Static
CURL* LLCurl::createStandardCurlHandle()
{
if (sCurlTemplateStandardHandle == NULL)
{ // Late creation of the template curl handle
sCurlTemplateStandardHandle = curl_easy_init();
if (sCurlTemplateStandardHandle == NULL)
{
LL_WARNS() << "curl error calling curl_easy_init()" << LL_ENDL;
}
else
{
CURLcode result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_NOSIGNAL, 1);
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_NOPROGRESS, 1);
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_ENCODING, "");
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_AUTOREFERER, 1);
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_FOLLOWLOCATION, 1);
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_SSL_VERIFYPEER, 1);
check_curl_code(result);
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_SSL_VERIFYHOST, 0);
check_curl_code(result);
// The Linksys WRT54G V5 router has an issue with frequent
// DNS lookups from LAN machines. If they happen too often,
// like for every HTTP request, the router gets annoyed after
// about 700 or so requests and starts issuing TCP RSTs to
// new connections. Reuse the DNS lookups for even a few
// seconds and no RSTs.
result = curl_easy_setopt(sCurlTemplateStandardHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
check_curl_code(result);
}
}
return curl_easy_duphandle(sCurlTemplateStandardHandle);
}

View File

@ -1,142 +0,0 @@
/**
* @file llcurl.h
* @author Zero / Donovan
* @date 2006-10-15
* @brief A wrapper around libcurl.
*
* $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_LLCURL_H
#define LL_LLCURL_H
#include "linden_common.h"
#include <sstream>
#include <string>
#include <vector>
#include <boost/intrusive_ptr.hpp>
#include <curl/curl.h> // TODO: remove dependency
#include "llbuffer.h"
#include "llhttpconstants.h"
#include "lliopipe.h"
#include "llsd.h"
#include "llqueuedthread.h"
#include "llframetimer.h"
#include "llpointer.h"
#include "llsingleton.h"
class LLMutex;
//class LLCurlThread;
// For whatever reason, this is not typedef'd in curl.h
typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
class LLCurl
{
LOG_CLASS(LLCurl);
public:
/**
* @ brief Set certificate authority file used to verify HTTPS certs.
*/
static void setCAFile(const std::string& file);
/**
* @ brief Set certificate authority path used to verify HTTPS certs.
*/
static void setCAPath(const std::string& path);
/**
* @ brief Return human-readable string describing libcurl version.
*/
static std::string getVersionString();
/**
* @ brief Get certificate authority file used to verify HTTPS certs.
*/
static const std::string& getCAFile() { return sCAFile; }
/**
* @ brief Get certificate authority path used to verify HTTPS certs.
*/
static const std::string& getCAPath() { return sCAPath; }
/**
* @ brief Initialize LLCurl class
*/
static void initClass(F32 curl_reuest_timeout = 120.f, S32 max_number_handles = 256, bool multi_threaded = false);
/**
* @ brief Cleanup LLCurl class
*/
static void cleanupClass();
/**
* @ brief curl error code -> string
*/
static std::string strerror(CURLcode errorcode);
// For OpenSSL callbacks
static std::vector<LLMutex*> sSSLMutex;
// OpenSSL callbacks
static void ssl_locking_callback(int mode, int type, const char *file, int line);
static unsigned long ssl_thread_id(void);
// static LLCurlThread* getCurlThread() { return sCurlThread ;}
static CURLM* newMultiHandle() ;
static CURLMcode deleteMultiHandle(CURLM* handle) ;
static CURL* newEasyHandle() ;
static void deleteEasyHandle(CURL* handle) ;
static CURL* createStandardCurlHandle();
private:
static std::string sCAPath;
static std::string sCAFile;
static const unsigned int MAX_REDIRECTS;
// static LLCurlThread* sCurlThread;
// static LLCurlThread* sCurlThread;
static LLMutex* sHandleMutexp ;
static S32 sTotalHandles ;
static S32 sMaxHandles;
static CURL* sCurlTemplateStandardHandle;
public:
static bool sNotQuitting;
static F32 sCurlRequestTimeOut;
};
// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
namespace LLCurlFF
{
void check_easy_code(CURLcode code);
//void check_multi_code(CURLMcode code);
}
#endif // LL_LLCURL_H

View File

@ -30,9 +30,8 @@
#include <string>
#include <curl/curl.h>
#include "httpcommon.h"
#include "llapr.h"
#include "llcurl.h"
#include "llhost.h"
// Static class variable instances
@ -429,21 +428,21 @@ void LLProxy::applyProxySettings(CURL* handle)
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
if (mHTTPProxyEnabled)
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()), CURLOPT_PROXY);
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()), CURLOPT_PROXYPORT);
if (mProxyType == LLPROXY_SOCKS)
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5), CURLOPT_PROXYTYPE);
if (mAuthMethodSelected == METHOD_PASSWORD)
{
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()), CURLOPT_PROXYUSERPWD);
}
}
else
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
LLCore::LLHttp::check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP), CURLOPT_PROXYTYPE);
}
}
}

View File

@ -27,12 +27,12 @@
#ifndef LL_PROXY_H
#define LL_PROXY_H
#include "llcurl.h"
#include "llhost.h"
#include "lliosocket.h"
#include "llmemory.h"
#include "llsingleton.h"
#include "llthread.h"
#include <curl/curl.h>
#include <string>
// SOCKS error codes returned from the StartProxy method

View File

@ -30,6 +30,7 @@
#include "llhost.h"
#include "llmessageconfig.h"
#include "message.h"
#include "llhttpconstants.h"
bool LLTrustedMessageService::validate(const std::string& name, LLSD& context)

View File

@ -50,7 +50,6 @@
#include "lltimer.h"
#include "llpacketring.h"
#include "llhost.h"
#include "llcurl.h"
#include "llhttpnode.h"
//#include "llpacketack.h"
#include "llsingleton.h"

View File

@ -31,7 +31,6 @@
#include <map>
#include <set>
#include <string>
#include "llcurl.h"
#include "llhttpretrypolicy.h"
#include "llviewerinventory.h"
#include "llcorehttputil.h"

View File

@ -138,6 +138,9 @@ LLAppCoreHttp::~LLAppCoreHttp()
void LLAppCoreHttp::init()
{
LLCore::LLHttp::initialize();
LLCore::HttpStatus status = LLCore::HttpRequest::createService();
if (! status)
{

View File

@ -58,7 +58,6 @@
#include "llviewerjoystick.h"
#include "llallocator.h"
#include "llares.h"
#include "llcurl.h"
#include "llcalc.h"
#include "llconversationlog.h"
#include "lldxhardware.h"
@ -828,12 +827,7 @@ bool LLAppViewer::init()
// before consumers (LLTextureFetch).
mAppCoreHttp.init();
// *NOTE:Mani - LLCurl::initClass is not thread safe.
// Called before threads are created.
LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"),
gSavedSettings.getS32("CurlMaximumNumberOfHandles"),
gSavedSettings.getBOOL("CurlUseMultipleThreads"));
LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;
LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ;
LLMachineID::init();
@ -903,7 +897,7 @@ bool LLAppViewer::init()
// the libs involved in getting to a full login screen.
//
LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL;
/////////////////////////////////////////////////
// OS-specific login dialogs
@ -1313,7 +1307,6 @@ bool LLAppViewer::mainLoop()
// Create IO Pump to use for HTTP Requests.
gServicePump = new LLPumpIO(gAPRPoolp);
LLCurl::setCAFile(gDirUtilp->getCAFile());
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
@ -3348,7 +3341,7 @@ LLSD LLAppViewer::getViewerInfo() const
#endif
info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
info["LIBCURL_VERSION"] = LLCurl::getVersionString();
info["LIBCURL_VERSION"] = LLCore::LLHttp::getCURLVersion();
info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
bool want_fullname = true;
info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD();

View File

@ -48,7 +48,6 @@
// Linden library includes
#include "llaudioengine.h"
#include "llbutton.h"
#include "llcurl.h"
#include "llglheaders.h"
#include "llfloater.h"
#include "llfloaterreg.h"

View File

@ -25,9 +25,23 @@
*/
#include "llviewerprecompiledheaders.h"
#include "llhttpretrypolicy.h"
namespace
{
// Moved from httpconstants.h... only used in this file.
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));
}
}
LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx):
mMinDelay(min_delay),
mMaxDelay(max_delay),
@ -140,3 +154,34 @@ bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const
seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX;
return mShouldRetry;
}
// Moved from httpconstants. Only used by this file.
// Parses 'Retry-After' header contents and returns seconds until retry should occur.
/*static*/
bool LLAdaptiveRetryPolicy::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 = (F64)date - LLTimer::getTotalSeconds();
return true;
}

View File

@ -76,6 +76,8 @@ public:
// virtual
bool shouldRetry(F32& seconds_to_wait) const;
static bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait);
protected:
void init();
bool getRetryAfter(const LLSD& headers, F32& retry_header_time);

View File

@ -35,7 +35,6 @@
#include "llassettype.h"
#include "llfoldertype.h"
#include "llframetimer.h"
#include "llcurl.h"
#include "lluuid.h"
#include "llpermissionsflags.h"
#include "llviewerinventory.h"

View File

@ -631,14 +631,8 @@ void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCo
if (status == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE))
{
F32 retry_timeout;
#if 0
// *TODO: Honor server Retry-After header.
if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER)
|| !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout))
#endif
{
retry_timeout = mRequest->getRetryTimerDelay();
}
retry_timeout = mRequest->getRetryTimerDelay();
mRequest->incRetryCount();

View File

@ -36,7 +36,6 @@
#include "llappviewer.h"
#include "llbufferstream.h"
#include "llcallbacklist.h"
#include "llcurl.h"
#include "lldatapacker.h"
#include "lldeadmantimer.h"
#include "llfloatermodelpreview.h"

View File

@ -40,7 +40,6 @@
#include "llcheckboxctrl.h"
#include "llcommandhandler.h" // for secondlife:///app/login/
#include "llcombobox.h"
#include "llcurl.h"
#include "llviewercontrol.h"
#include "llfloaterpreference.h"
#include "llfocusmgr.h"

View File

@ -37,7 +37,6 @@
#include "lltextureinfo.h"
#include "llapr.h"
#include "llimageworker.h"
#include "llcurl.h"
#include "httprequest.h"
#include "httpoptions.h"
#include "httpheaders.h"

View File

@ -34,8 +34,8 @@
#include "llxmlrpctransaction.h"
#include "llxmlrpclistener.h"
#include "llcurl.h"
#include "httpcommon.h"
#include "llhttpconstants.h"
#include "httprequest.h"
#include "httpoptions.h"
#include "httpheaders.h"

View File

@ -105,7 +105,6 @@
#include "llspatialpartition.h"
#include "llmutelist.h"
#include "lltoolpie.h"
#include "llcurl.h"
#include "llnotifications.h"
#include "llpathinglib.h"
#include "llfloaterpathfindingconsole.h"

View File

@ -234,13 +234,13 @@ void RetryPolicyTestObject::test<6>()
std::string str1("0");
seconds_to_wait = F32_MAX;
success = getSecondsUntilRetryAfter(str1, seconds_to_wait);
success = LLAdaptiveRetryPolicy::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);
success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str2, seconds_to_wait);
ensure("parse 2", success);
ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8);
@ -248,7 +248,7 @@ void RetryPolicyTestObject::test<6>()
time(&nowseconds);
std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123();
seconds_to_wait = F32_MAX;
success = getSecondsUntilRetryAfter(str3, seconds_to_wait);
success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str3, seconds_to_wait);
std::cerr << " str3 [" << str3 << "]" << std::endl;
ensure("parse 3", success);
ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F);

View File

@ -28,7 +28,7 @@
#include <tut/tut.hpp>
#include "linden_common.h"
#include "lltut.h"
#include "llhttpconstants.h"
#include "llapr.h"
#include "llmessageconfig.h"
#include "llsdserialize.h"

View File

@ -26,7 +26,7 @@
#include "linden_common.h"
#include "llupdatedownloader.h"
#include "httpcommon.h"
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
@ -39,7 +39,6 @@
#include "llsdserialize.h"
#include "llthread.h"
#include "llupdaterservice.h"
#include "llcurl.h"
class LLUpdateDownloader::Implementation:
public LLThread
@ -65,7 +64,7 @@ private:
curl_off_t mBandwidthLimit;
bool mCancelled;
LLUpdateDownloader::Client & mClient;
CURL * mCurl;
LLCore::LLHttp::CURL_ptr mCurl;
LLSD mDownloadData;
llofstream mDownloadStream;
unsigned char mDownloadPercent;
@ -192,7 +191,7 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client &
mBandwidthLimit(0),
mCancelled(false),
mClient(client),
mCurl(0),
mCurl(),
mDownloadPercent(0),
mHeaderList(0)
{
@ -212,10 +211,7 @@ LLUpdateDownloader::Implementation::~Implementation()
{
; // No op.
}
if(mCurl)
{
LLCurl::deleteEasyHandle(mCurl);
}
mCurl.reset();
}
@ -331,9 +327,9 @@ void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond)
{
if((mBandwidthLimit != bytesPerSecond) && isDownloading() && !mDownloadData["required"].asBoolean())
{
llassert(mCurl != 0);
llassert(static_cast<bool>(mCurl));
mBandwidthLimit = bytesPerSecond;
CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
CURLcode code = curl_easy_setopt(mCurl.get(), CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit);
if(code != CURLE_OK)
{
LL_WARNS("UpdaterService") << "unable to change dowload bandwidth" << LL_ENDL;
@ -416,7 +412,7 @@ int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double b
void LLUpdateDownloader::Implementation::run(void)
{
CURLcode code = curl_easy_perform(mCurl);
CURLcode code = curl_easy_perform(mCurl.get());
mDownloadStream.close();
if(code == CURLE_OK)
{
@ -460,36 +456,36 @@ void LLUpdateDownloader::Implementation::run(void)
void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)
{
if(mCurl == 0)
if(!mCurl)
{
mCurl = LLCurl::newEasyHandle();
mCurl = LLCore::LLHttp::createEasyHandle();
}
else
{
curl_easy_reset(mCurl);
curl_easy_reset(mCurl.get());
}
if(mCurl == 0)
if(!mCurl)
{
throw DownloadError("failed to initialize curl");
}
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOSIGNAL, true));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_FOLLOWLOCATION, true));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_WRITEFUNCTION, &write_function));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_WRITEDATA, this));
if(processHeader)
{
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HEADERFUNCTION, &header_function));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HEADERDATA, this));
}
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &progress_callback));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, this));
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, false));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPGET, true));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_URL, url.c_str()));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_PROGRESSFUNCTION, &progress_callback));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_PROGRESSDATA, this));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_NOPROGRESS, false));
// if it's a required update set the bandwidth limit to 0 (unlimited)
curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit;
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_MAX_RECV_SPEED_LARGE, limit));
mDownloadPercent = 0;
}
@ -511,7 +507,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
{
throw DownloadError("cannot add Range header");
}
throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList));
throwOnCurlError(curl_easy_setopt(mCurl.get(), CURLOPT_HTTPHEADER, mHeaderList));
mDownloadStream.open(mDownloadData["path"].asString().c_str(),
std::ios_base::out | std::ios_base::binary | std::ios_base::app);