summaryrefslogtreecommitdiff
path: root/indra/llcorehttp
diff options
context:
space:
mode:
authorRider Linden <none@none>2015-03-16 17:14:34 -0700
committerRider Linden <none@none>2015-03-16 17:14:34 -0700
commit6f4d36634e980bb989b9a8b762c3c622804c43dd (patch)
treeefa71ac14bdef46b9796688d4a445d60fdd5b1c3 /indra/llcorehttp
parentd4a2e9fd9a0e7001a6c824ddd6cf37039a632b9d (diff)
Removal of RPCXML dep on LLCurl switching to LLCore::Html
Diffstat (limited to 'indra/llcorehttp')
-rwxr-xr-xindra/llcorehttp/_httpoprequest.cpp95
-rwxr-xr-xindra/llcorehttp/_httpoprequest.h11
-rwxr-xr-xindra/llcorehttp/_httppolicyglobal.cpp30
-rwxr-xr-xindra/llcorehttp/_httppolicyglobal.h3
-rwxr-xr-xindra/llcorehttp/_httpservice.cpp80
-rwxr-xr-xindra/llcorehttp/_httpservice.h9
-rwxr-xr-xindra/llcorehttp/_refcounted.h11
-rwxr-xr-xindra/llcorehttp/bufferarray.h2
-rwxr-xr-xindra/llcorehttp/httpcommon.cpp24
-rwxr-xr-xindra/llcorehttp/httpcommon.h116
-rwxr-xr-xindra/llcorehttp/httphandler.h4
-rwxr-xr-xindra/llcorehttp/httpheaders.h1
-rwxr-xr-xindra/llcorehttp/httpoptions.cpp39
-rwxr-xr-xindra/llcorehttp/httpoptions.h31
-rwxr-xr-xindra/llcorehttp/httprequest.cpp17
-rwxr-xr-xindra/llcorehttp/httprequest.h17
-rwxr-xr-xindra/llcorehttp/httpresponse.h25
17 files changed, 435 insertions, 80 deletions
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index b9632a7921..48e22468cd 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -115,8 +115,9 @@ namespace LLCore
{
-HttpOpRequest::HttpOpRequest()
+HttpOpRequest::HttpOpRequest(HttpRequest const * const request)
: HttpOperation(),
+ mRequest(request),
mProcFlags(0U),
mReqMethod(HOR_GET),
mReqBody(NULL),
@@ -139,7 +140,8 @@ HttpOpRequest::HttpOpRequest()
mPolicyRetries(0),
mPolicy503Retries(0),
mPolicyRetryAt(HttpTime(0)),
- mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT)
+ mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT),
+ mCallbackSSLVerify(NULL)
{
// *NOTE: As members are added, retry initialization/cleanup
// may need to be extended in @see prepareRequest().
@@ -267,6 +269,14 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setContentType(mReplyConType);
response->setRetries(mPolicyRetries, mPolicy503Retries);
+ HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
+
+ curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload);
+ curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime);
+ curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload);
+
+ response->setTransferStats(stats);
+
mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
response->release();
@@ -452,18 +462,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
check_curl_easy_code(code, CURLOPT_ENCODING);
- // 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.
- code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
- check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
check_curl_easy_code(code, CURLOPT_AUTOREFERER);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1);
- check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
check_curl_easy_code(code, CURLOPT_MAXREDIRS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
@@ -474,11 +474,49 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_code(code, CURLOPT_READFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this);
check_curl_easy_code(code, CURLOPT_READDATA);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
+
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
+ check_curl_easy_code(code, CURLOPT_COOKIEFILE);
+
+ if (gpolicy.mSslCtxCallback)
+ {
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
+ check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, this);
+ check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA);
+ mCallbackSSLVerify = gpolicy.mSslCtxCallback;
+ }
+
+ long follow_redirect(1L);
+ long sslPeerV(0L);
+ long sslHostV(0L);
+ long dnsCacheTimeout(15L);
+
+ if (mReqOptions)
+ {
+ follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L;
+ sslPeerV = mReqOptions->getSSLVerifyHost() ? 0L : 1L;
+ sslHostV = mReqOptions->getSSLVerifyHost();
+ dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
+ }
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
+ check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
+
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER);
- code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
check_curl_easy_code(code, 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.
+ code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
+ check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
+
+
if (gpolicy.mUseLLProxy)
{
// Use the viewer-based thread-safe API which has a
@@ -873,6 +911,35 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
}
+CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+
+ if (op->mCallbackSSLVerify)
+ {
+ SSL_CTX * ctx = (SSL_CTX *)sslctx;
+ // disable any default verification for server certs
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ // set the verification callback.
+ SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata);
+ // the calls are void
+ }
+
+ return CURLE_OK;
+}
+
+int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+{
+ HttpOpRequest * op(static_cast<HttpOpRequest *>(param));
+
+ if (op->mCallbackSSLVerify)
+ {
+ op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx);
+ }
+
+ return (op->mStatus) ? 1 : 0;
+}
+
int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
{
HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 2f628b5aba..7a4b7c189e 100755
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -33,6 +33,9 @@
#include <string>
#include <curl/curl.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+
#include "httpcommon.h"
#include "httprequest.h"
#include "_httpoperation.h"
@@ -63,7 +66,7 @@ class HttpOptions;
class HttpOpRequest : public HttpOperation
{
public:
- HttpOpRequest();
+ HttpOpRequest(HttpRequest const * const request);
protected:
virtual ~HttpOpRequest(); // Use release()
@@ -151,6 +154,9 @@ protected:
static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata);
static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata);
static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata);
+ static CURLcode curlSslCtxCallback(CURL *curl, void *ssl_ctx, void *userptr);
+ static int sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
+
static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata);
protected:
@@ -159,8 +165,11 @@ protected:
static const unsigned int PF_SAVE_HEADERS = 0x00000002U;
static const unsigned int PF_USE_RETRY_AFTER = 0x00000004U;
+ HttpRequest::policyCallback mCallbackSSLVerify;
+
public:
// Request data
+ HttpRequest const * const mRequest;
EMethod mReqMethod;
std::string mReqURL;
BufferArray * mReqBody;
diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp
index 1dc95f3dce..c4ef38a815 100755
--- a/indra/llcorehttp/_httppolicyglobal.cpp
+++ b/indra/llcorehttp/_httppolicyglobal.cpp
@@ -106,6 +106,20 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::stri
return HttpStatus();
}
+HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback value)
+{
+ switch (opt)
+ {
+ case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+ mSslCtxCallback = value;
+ break;
+
+ default:
+ return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+ }
+
+ return HttpStatus();
+}
HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const
{
@@ -154,4 +168,20 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * v
return HttpStatus();
}
+
+HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback * value) const
+{
+ switch (opt)
+ {
+ case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+ *value = mSslCtxCallback;
+ break;
+
+ default:
+ return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+ }
+
+ return HttpStatus();
+}
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h
index 67c4ba9481..1696238814 100755
--- a/indra/llcorehttp/_httppolicyglobal.h
+++ b/indra/llcorehttp/_httppolicyglobal.h
@@ -60,8 +60,10 @@ private:
public:
HttpStatus set(HttpRequest::EPolicyOption opt, long value);
HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value);
+ HttpStatus set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback value);
HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const;
+ HttpStatus get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback * value) const;
public:
long mConnectionLimit;
@@ -70,6 +72,7 @@ public:
std::string mHttpProxy;
long mTrace;
long mUseLLProxy;
+ HttpRequest::policyCallback mSslCtxCallback;
}; // end class HttpPolicyGlobal
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index c673e1be1d..7b8aac35a8 100755
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -53,15 +53,16 @@ namespace LLCore
const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
{ // isLong isDynamic isGlobal isClass
- { true, true, true, true }, // PO_CONNECTION_LIMIT
- { true, true, false, true }, // PO_PER_HOST_CONNECTION_LIMIT
- { false, false, true, false }, // PO_CA_PATH
- { false, false, true, false }, // PO_CA_FILE
- { false, true, true, false }, // PO_HTTP_PROXY
- { true, true, true, false }, // PO_LLPROXY
- { true, true, true, false }, // PO_TRACE
- { true, true, false, true }, // PO_ENABLE_PIPELINING
- { true, true, false, true } // PO_THROTTLE_RATE
+ { true, true, true, true, false }, // PO_CONNECTION_LIMIT
+ { true, true, false, true, false }, // PO_PER_HOST_CONNECTION_LIMIT
+ { false, false, true, false, false }, // PO_CA_PATH
+ { false, false, true, false, false }, // PO_CA_FILE
+ { false, true, true, false, false }, // PO_HTTP_PROXY
+ { true, true, true, false, false }, // PO_LLPROXY
+ { true, true, true, false, false }, // PO_TRACE
+ { true, true, false, true, false }, // PO_ENABLE_PIPELINING
+ { true, true, false, true, false }, // PO_THROTTLE_RATE
+ { false, false, true, false, true } // PO_SSL_VERIFY_CALLBACK
};
HttpService * HttpService::sInstance(NULL);
volatile HttpService::EState HttpService::sState(NOT_INITIALIZED);
@@ -413,6 +414,34 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
return status;
}
+HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+ HttpRequest::policyCallback * ret_value)
+{
+ HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+ if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
+ || opt >= HttpRequest::PO_LAST // ditto
+ || (sOptionDesc[opt].mIsLong) // datatype is string
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range
+ || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass)) // class setting permitted
+ // can always get, no dynamic check
+ {
+ return status;
+ }
+
+ // Only global has callback values
+ if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+ {
+ HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+ status = opts.get(opt, ret_value);
+ }
+
+ return status;
+}
+
+
HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
long value, long * ret_value)
@@ -489,6 +518,37 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
return status;
}
-
+
+HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+ HttpRequest::policyCallback value, HttpRequest::policyCallback * ret_value)
+{
+ HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+ if (opt < HttpRequest::PO_CONNECTION_LIMIT // option must be in range
+ || opt >= HttpRequest::PO_LAST // ditto
+ || (sOptionDesc[opt].mIsLong) // datatype is string
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy) // pclass in valid range
+ || (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal) // global setting permitted
+ || (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass) // class setting permitted
+ || (RUNNING == sState && !sOptionDesc[opt].mIsDynamic)) // dynamic setting permitted
+ {
+ return status;
+ }
+
+ // Callbacks values are always global (at this time).
+ if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+ {
+ HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+ status = opts.set(opt, value);
+ if (status && ret_value)
+ {
+ status = opts.get(opt, ret_value);
+ }
+ }
+
+ return status;
+}
+
} // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index cf23f3ab61..699a8eaa4f 100755
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -201,17 +201,24 @@ protected:
bool mIsDynamic;
bool mIsGlobal;
bool mIsClass;
+ bool mIsCallback;
};
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
long * ret_value);
HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
std::string * ret_value);
+ HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+ HttpRequest::policyCallback * ret_value);
+
HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
long value, long * ret_value);
HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
const std::string & value, std::string * ret_value);
-
+ HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+ HttpRequest::policyCallback value,
+ HttpRequest::policyCallback * ret_value);
+
protected:
static const OptionDescriptor sOptionDesc[HttpRequest::PO_LAST];
static HttpService * sInstance;
diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h
index 402e725152..cd16e2e2b4 100755
--- a/indra/llcorehttp/_refcounted.h
+++ b/indra/llcorehttp/_refcounted.h
@@ -120,7 +120,18 @@ inline void RefCounted::destroySelf()
delete this;
}
+inline void intrusive_ptr_add_ref(RefCounted* p)
+{
+ p->addRef();
+}
+
+inline void intrusive_ptr_release(RefCounted* p)
+{
+ p->release();
+}
+
} // end namespace LLCoreInt
+
#endif // LLCOREINT__REFCOUNTED_H_
diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h
index 1094a435b4..9c2b991de6 100755
--- a/indra/llcorehttp/bufferarray.h
+++ b/indra/llcorehttp/bufferarray.h
@@ -73,6 +73,8 @@ public:
BufferArray();
+ typedef boost::intrusive_ptr<BufferArray> ptr_t;
+
protected:
virtual ~BufferArray(); // Use release()
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 7907e958a4..1aece696e3 100755
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -42,7 +42,7 @@ HttpStatus::operator unsigned long() const
{
static const int shift(sizeof(unsigned long) * 4);
- unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus);
+ unsigned long result(((unsigned long)mDetails->mType) << shift | (unsigned long)(int)mDetails->mStatus);
return result;
}
@@ -131,18 +131,18 @@ std::string HttpStatus::toString() const
{
return std::string("");
}
- switch (mType)
+ switch (mDetails->mType)
{
case EXT_CURL_EASY:
- return std::string(curl_easy_strerror(CURLcode(mStatus)));
+ return std::string(curl_easy_strerror(CURLcode(mDetails->mStatus)));
case EXT_CURL_MULTI:
- return std::string(curl_multi_strerror(CURLMcode(mStatus)));
+ return std::string(curl_multi_strerror(CURLMcode(mDetails->mStatus)));
case LLCORE:
- if (mStatus >= 0 && mStatus < llcore_errors_count)
+ if (mDetails->mStatus >= 0 && mDetails->mStatus < llcore_errors_count)
{
- return std::string(llcore_errors[mStatus]);
+ return std::string(llcore_errors[mDetails->mStatus]);
}
break;
@@ -154,7 +154,7 @@ std::string HttpStatus::toString() const
while (true)
{
int at((bottom + top) / 2);
- if (mType == http_errors[at].mCode)
+ if (mDetails->mType == http_errors[at].mCode)
{
return std::string(http_errors[at].mText);
}
@@ -162,7 +162,7 @@ std::string HttpStatus::toString() const
{
break;
}
- else if (mType < http_errors[at].mCode)
+ else if (mDetails->mType < http_errors[at].mCode)
{
top = at;
}
@@ -182,9 +182,9 @@ std::string HttpStatus::toTerseString() const
{
std::ostringstream result;
- unsigned int error_value((unsigned short) mStatus);
+ unsigned int error_value((unsigned short)mDetails->mStatus);
- switch (mType)
+ switch (mDetails->mType)
{
case EXT_CURL_EASY:
result << "Easy_";
@@ -202,7 +202,7 @@ std::string HttpStatus::toTerseString() const
if (isHttpStatus())
{
result << "Http_";
- error_value = mType;
+ error_value = mDetails->mType;
}
else
{
@@ -244,7 +244,7 @@ bool HttpStatus::isRetryable() const
// Disable the '*this == inv_status' test and look for 'Core_9'
// failures in log files.
- return ((isHttpStatus() && mType >= 499 && mType <= 599) || // Include special 499 in retryables
+ return ((isHttpStatus() && mDetails->mType >= 499 && mDetails->mType <= 599) || // Include special 499 in retryables
*this == cant_connect || // Connection reset/endpoint problems
*this == cant_res_proxy || // DNS problems
*this == cant_res_host || // DNS problems
diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index 9601f94125..0244755272 100755
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -191,7 +191,6 @@
#include <string>
-
namespace LLCore
{
@@ -292,35 +291,35 @@ struct HttpStatus
typedef unsigned short type_enum_t;
HttpStatus()
- : mType(LLCORE),
- mStatus(HE_SUCCESS)
- {}
+ {
+ mDetails = std::unique_ptr<Details>(new Details(LLCORE, HE_SUCCESS));
+ }
HttpStatus(type_enum_t type, short status)
- : mType(type),
- mStatus(status)
- {}
+ {
+ mDetails = std::unique_ptr<Details>(new Details(type, status));
+ }
HttpStatus(int http_status)
- : mType(http_status),
- mStatus(http_status >= 200 && http_status <= 299
- ? HE_SUCCESS
- : HE_REPLY_ERROR)
{
+ mDetails = std::unique_ptr<Details>(new Details(http_status,
+ (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR));
llassert(http_status >= 100 && http_status <= 999);
}
HttpStatus(const HttpStatus & rhs)
- : mType(rhs.mType),
- mStatus(rhs.mStatus)
- {}
+ {
+ mDetails = std::unique_ptr<Details>(new Details(*rhs.mDetails));
+ }
HttpStatus & operator=(const HttpStatus & rhs)
{
// Don't care if lhs & rhs are the same object
+ mDetails->mType = rhs.mDetails->mType;
+ mDetails->mStatus = rhs.mDetails->mStatus;
+ mDetails->mMessage = rhs.mDetails->mMessage;
+ mDetails->mErrorData = rhs.mDetails->mErrorData;
- mType = rhs.mType;
- mStatus = rhs.mStatus;
return *this;
}
@@ -328,10 +327,6 @@ struct HttpStatus
static const type_enum_t EXT_CURL_MULTI = 1; ///< mStatus is an error from a curl_multi_*() call
static const type_enum_t LLCORE = 2; ///< mStatus is an HE_* error code
///< 100-999 directly represent HTTP status codes
-
- type_enum_t mType;
- short mStatus;
-
/// Test for successful status in the code regardless
/// of error source (internal, libcurl).
///
@@ -339,7 +334,7 @@ struct HttpStatus
///
operator bool() const
{
- return 0 == mStatus;
+ return 0 == mDetails->mStatus;
}
/// Inverse of previous operator.
@@ -347,14 +342,15 @@ struct HttpStatus
/// @return 'true' on any error condition
bool operator !() const
{
- return 0 != mStatus;
+ return 0 != mDetails->mStatus;
}
/// Equality and inequality tests to bypass bool conversion
/// which will do the wrong thing in conditional expressions.
bool operator==(const HttpStatus & rhs) const
{
- return mType == rhs.mType && mStatus == rhs.mStatus;
+ return (mDetails->mType == rhs.mDetails->mType) &&
+ (mDetails->mStatus == rhs.mDetails->mStatus);
}
bool operator!=(const HttpStatus & rhs) const
@@ -395,7 +391,7 @@ struct HttpStatus
/// HTTP response status (100 - 999).
bool isHttpStatus() const
{
- return mType >= type_enum_t(100) && mType <= type_enum_t(999);
+ return mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999);
}
/// Returns true if the status is one that will be retried
@@ -403,7 +399,77 @@ struct HttpStatus
/// where that logic needs to be replicated. Only applies
/// to failed statuses, successful statuses will return false.
bool isRetryable() const;
-
+
+ /// Returns the currently set status code as a raw number
+ ///
+ short getStatus() const
+ {
+ return mDetails->mStatus;
+ }
+
+ /// Returns the currently set status type
+ ///
+ type_enum_t getType() const
+ {
+ return mDetails->mType;
+ }
+
+ // TODO: There must be a better way to do this. Don't want to set these
+ // values here since they increase the size of a structure that is already
+ // being passed on the stack. Consider my options
+ /// Returns an optional error message if one has been set.
+ ///
+ std::string getMessage() const
+ {
+ return mDetails->mMessage;
+ }
+
+ /// Sets an optional error message
+ ///
+ void setMessage(const std::string &message)
+ {
+ mDetails->mMessage = message;
+ }
+
+ /// Retrieves an optionally recorded SSL certificate.
+ void * getErrorData() const
+ {
+ return mDetails->mErrorData;
+ }
+
+ /// Optionally sets an SSL certificate on this status.
+ void setErrorData(void *data)
+ {
+ mDetails->mErrorData = data;
+ }
+
+private:
+
+ struct Details
+ {
+ Details(type_enum_t type, short status):
+ mType(type),
+ mStatus(status),
+ mMessage(),
+ mErrorData(NULL)
+ {}
+
+ Details(const Details &rhs) :
+ mType(rhs.mType),
+ mStatus(rhs.mStatus),
+ mMessage(rhs.mMessage),
+ mErrorData(rhs.mErrorData)
+ {}
+
+
+ type_enum_t mType;
+ short mStatus;
+ std::string mMessage;
+ void * mErrorData;
+ };
+
+ std::unique_ptr<Details> mDetails;
+
}; // end struct HttpStatus
} // end namespace LLCore
diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h
index 9171e4e7b9..740e986dec 100755
--- a/indra/llcorehttp/httphandler.h
+++ b/indra/llcorehttp/httphandler.h
@@ -45,7 +45,7 @@ class HttpResponse;
/// be shared by any number of requests and across instances
/// of HttpRequest running in the same thread.
///
-/// Threading: HttpHandler itself is pure interface and is
+/// Threading: HttpHandler itself is interface and is
/// tread-compatible. Most derivations, however, will have
/// different constraints.
///
@@ -58,7 +58,7 @@ class HttpHandler
{
public:
virtual ~HttpHandler()
- {}
+ { }
/// Method invoked during calls to @see update(). Each invocation
/// represents the completion of some requested operation. Caller
diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h
index f70cd898f3..c89d6af222 100755
--- a/indra/llcorehttp/httpheaders.h
+++ b/indra/llcorehttp/httpheaders.h
@@ -92,6 +92,7 @@ public:
/// the instance.
HttpHeaders();
+ typedef boost::intrusive_ptr<HttpHeaders> ptr_t;
protected:
virtual ~HttpHeaders(); // Use release()
diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp
index 5bf1ecb4a5..28c2c25e92 100755
--- a/indra/llcorehttp/httpoptions.cpp
+++ b/indra/llcorehttp/httpoptions.cpp
@@ -25,7 +25,7 @@
*/
#include "httpoptions.h"
-
+#include "lldefs.h"
#include "_httpinternal.h"
@@ -33,14 +33,17 @@ namespace LLCore
{
-HttpOptions::HttpOptions()
- : RefCounted(true),
- mWantHeaders(false),
- mTracing(HTTP_TRACE_OFF),
- mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
- mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
- mRetries(HTTP_RETRY_COUNT_DEFAULT),
- mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT)
+HttpOptions::HttpOptions() : RefCounted(true),
+ mWantHeaders(false),
+ mTracing(HTTP_TRACE_OFF),
+ mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
+ mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
+ mRetries(HTTP_RETRY_COUNT_DEFAULT),
+ mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT),
+ mFollowRedirects(false),
+ mVerifyPeer(false),
+ mVerifyHost(0),
+ mDNSCacheTimeout(15)
{}
@@ -82,5 +85,23 @@ void HttpOptions::setUseRetryAfter(bool use_retry)
mUseRetryAfter = use_retry;
}
+void HttpOptions::setFollowRedirects(bool follow_redirect)
+{
+ mFollowRedirects = follow_redirect;
+}
+
+void HttpOptions::setSSLVerifyPeer(bool verify)
+{
+ mVerifyPeer = verify;
+}
+void HttpOptions::setSSLVerifyHost(unsigned int type)
+{
+ mVerifyHost = llclamp<unsigned int>(type, 0, 2);
+}
+
+void HttpOptions::setDNSCacheTimeout(int timeout)
+{
+ mDNSCacheTimeout = timeout;
+}
} // end namespace LLCore
diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h
index 4ab5ff18c4..d6d892213d 100755
--- a/indra/llcorehttp/httpoptions.h
+++ b/indra/llcorehttp/httpoptions.h
@@ -61,6 +61,8 @@ class HttpOptions : public LLCoreInt::RefCounted
public:
HttpOptions();
+ typedef boost::intrusive_ptr<HttpOptions> ptr_t;
+
protected:
virtual ~HttpOptions(); // Use release()
@@ -109,6 +111,31 @@ public:
{
return mUseRetryAfter;
}
+
+ // Default: false
+ void setFollowRedirects(bool follow_redirect);
+ bool getFollowRedirects() const
+ {
+ return mFollowRedirects;
+ }
+
+ void setSSLVerifyPeer(bool verify);
+ bool getSSLVerifyPeer() const
+ {
+ return mVerifyPeer;
+ }
+
+ void setSSLVerifyHost(unsigned int type);
+ unsigned int getSSLVerifyHost() const
+ {
+ return mVerifyHost;
+ }
+
+ void setDNSCacheTimeout(int timeout);
+ int getDNSCacheTimeout() const
+ {
+ return mDNSCacheTimeout;
+ }
protected:
bool mWantHeaders;
@@ -117,6 +144,10 @@ protected:
unsigned int mTransferTimeout;
unsigned int mRetries;
bool mUseRetryAfter;
+ bool mFollowRedirects;
+ bool mVerifyPeer;
+ unsigned int mVerifyHost;
+ int mDNSCacheTimeout;
}; // end class HttpOptions
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 7b1888e3eb..5f1ed3d43b 100755
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -117,6 +117,15 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass
return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
}
+HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback value, policyCallback * ret_value)
+{
+ if (HttpService::RUNNING == HttpService::instanceOf()->getState())
+ {
+ return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
+ }
+
+ return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
+}
HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
long value, HttpHandler * handler)
@@ -195,7 +204,7 @@ HttpHandle HttpRequest::requestGet(policy_t policy_id,
HttpStatus status;
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest * op = new HttpOpRequest(this);
if (! (status = op->setupGet(policy_id, priority, url, options, headers)))
{
op->release();
@@ -229,7 +238,7 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
HttpStatus status;
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest * op = new HttpOpRequest(this);
if (! (status = op->setupGetByteRange(policy_id, priority, url, offset, len, options, headers)))
{
op->release();
@@ -262,7 +271,7 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
HttpStatus status;
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest * op = new HttpOpRequest(this);
if (! (status = op->setupPost(policy_id, priority, url, body, options, headers)))
{
op->release();
@@ -295,7 +304,7 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
HttpStatus status;
HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
- HttpOpRequest * op = new HttpOpRequest();
+ HttpOpRequest * op = new HttpOpRequest(this);
if (! (status = op->setupPut(policy_id, priority, url, body, options, headers)))
{
op->release();
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 7f23723b0b..c90e056d62 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -97,6 +97,7 @@ public:
typedef unsigned int policy_t;
typedef unsigned int priority_t;
+ typedef std::shared_ptr<HttpRequest> ptr_t;
public:
/// @name PolicyMethods
/// @{
@@ -163,7 +164,7 @@ public:
/// Long value that if non-zero enables the use of the
/// traditional LLProxy code for http/socks5 support. If
- // enabled, has priority over GP_HTTP_PROXY.
+ /// enabled, has priority over GP_HTTP_PROXY.
///
/// Global only
PO_LLPROXY,
@@ -219,15 +220,25 @@ public:
/// Controls whether client-side throttling should be
/// performed on this policy class. Positive values
/// enable throttling and specify the request rate
- /// (requests per second) that should be targetted.
+ /// (requests per second) that should be targeted.
/// A value of zero, the default, specifies no throttling.
///
/// Per-class only
PO_THROTTLE_RATE,
+ /// Controls the callback function used to control SSL CTX
+ /// certificate verification.
+ ///
+ /// Global only
+ PO_SSL_VERIFY_CALLBACK,
+
PO_LAST // Always at end
};
+ /// Prototype for policy based callbacks. The callback methods will be executed
+ /// on the worker thread so no modifications should be made to the HttpHandler object.
+ typedef HttpStatus(*policyCallback)(const std::string &, HttpHandler const * const, void *);
+
/// Set a policy option for a global or class parameter at
/// startup time (prior to thread start).
///
@@ -243,6 +254,8 @@ public:
long value, long * ret_value);
static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
const std::string & value, std::string * ret_value);
+ static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
+ policyCallback value, policyCallback * ret_value);;
/// Set a parameter on a class-based policy option. Calls
/// made after the start of the servicing thread are
diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h
index aee64e2878..01e9dd2bc6 100755
--- a/indra/llcorehttp/httpresponse.h
+++ b/indra/llcorehttp/httpresponse.h
@@ -69,6 +69,18 @@ protected:
void operator=(const HttpResponse &); // Not defined
public:
+ /// Statistics for the HTTP
+ struct TransferStats
+ {
+ typedef std::shared_ptr<TransferStats> ptr_t;
+
+ TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
+ F64 mSizeDownload;
+ F64 mTotalTime;
+ F64 mSpeedDownload;
+ };
+
+
/// Returns the final status of the requested operation.
///
HttpStatus getStatus() const
@@ -168,6 +180,17 @@ public:
m503Retries = retries_503;
}
+ void setTransferStats(TransferStats::ptr_t &stats)
+ {
+ mStats = stats;
+ }
+
+ TransferStats::ptr_t getTransferStats()
+ {
+ return mStats;
+ }
+
+
protected:
// Response data here
HttpStatus mStatus;
@@ -179,6 +202,8 @@ protected:
std::string mContentType;
unsigned int mRetries;
unsigned int m503Retries;
+
+ TransferStats::ptr_t mStats;
};