summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/_httpoprequest.cpp
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2024-05-16 13:52:40 +0800
committerErik Kundiman <erik@megapahit.org>2024-05-16 13:52:40 +0800
commit6d51e91895a7f2435c46a876410ccc6c63fe8c82 (patch)
treef2b48ebd99cb414227bf365f47665b8d4baa752b /indra/llcorehttp/_httpoprequest.cpp
parentd1b5917bb9c92e4e47eba19b43781e4d1328b1ca (diff)
parent094dcc07f8c1d90ae723dbe60eddacb90a09eae8 (diff)
Merge tag '7.1.7-release'
source for viewer 7.1.7.8974243247
Diffstat (limited to 'indra/llcorehttp/_httpoprequest.cpp')
-rw-r--r--indra/llcorehttp/_httpoprequest.cpp1676
1 files changed, 838 insertions, 838 deletions
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index 4083075043..6b46f5c59c 100644
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -69,22 +69,22 @@ namespace
// have verified that the header tag is present. The 'buffer' argument
// will be processed by strtok_r calls which will modify the buffer.
//
-// @return -1 if invalid and response should be dropped, 0 if valid an
-// correct, 1 if couldn't be parsed. If 0, the first, last,
-// and length arguments are also written. 'length' may be
-// 0 if the length wasn't available to the server.
+// @return -1 if invalid and response should be dropped, 0 if valid an
+// correct, 1 if couldn't be parsed. If 0, the first, last,
+// and length arguments are also written. 'length' may be
+// 0 if the length wasn't available to the server.
//
int parse_content_range_header(char * buffer,
- unsigned int * first,
- unsigned int * last,
- unsigned int * length);
+ unsigned int * first,
+ unsigned int * last,
+ unsigned int * length);
// Similar for Retry-After headers. Only parses the delta form
// of the header, HTTP time formats aren't interesting for client
// purposes.
//
-// @return 0 if successfully parsed and seconds time delta
-// returned in time argument.
+// @return 0 if successfully parsed and seconds time delta
+// returned in time argument.
//
int parse_retry_after_header(char * buffer, int * time);
@@ -95,7 +95,7 @@ int parse_retry_after_header(char * buffer, int * time);
// non-printing or non-ascii characters are replaced with spaces
// otherwise a %XX form of escaping is used.
void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub,
- std::string & safe_line);
+ std::string & safe_line);
// OS-neutral string comparisons of various types.
@@ -127,73 +127,73 @@ namespace LLCore
HttpOpRequest::HttpOpRequest()
- : HttpOperation(),
- mProcFlags(0U),
- mReqMethod(HOR_GET),
- mReqBody(NULL),
- mReqOffset(0),
- mReqLength(0),
- mReqHeaders(),
- mReqOptions(),
- mCurlActive(false),
- mCurlHandle(NULL),
- mCurlService(NULL),
- mCurlHeaders(NULL),
- mCurlBodyPos(0),
- mCurlTemp(NULL),
- mCurlTempLen(0),
- mReplyBody(NULL),
- mReplyOffset(0),
- mReplyLength(0),
- mReplyFullLength(0),
- mReplyHeaders(),
- mPolicyRetries(0),
- mPolicy503Retries(0),
- mPolicyRetryAt(HttpTime(0)),
- mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT),
- mPolicyMinRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MIN_DEFAULT)),
- mPolicyMaxRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MAX_DEFAULT)),
- mCallbackSSLVerify(NULL)
+ : HttpOperation(),
+ mProcFlags(0U),
+ mReqMethod(HOR_GET),
+ mReqBody(NULL),
+ mReqOffset(0),
+ mReqLength(0),
+ mReqHeaders(),
+ mReqOptions(),
+ mCurlActive(false),
+ mCurlHandle(NULL),
+ mCurlService(NULL),
+ mCurlHeaders(NULL),
+ mCurlBodyPos(0),
+ mCurlTemp(NULL),
+ mCurlTempLen(0),
+ mReplyBody(NULL),
+ mReplyOffset(0),
+ mReplyLength(0),
+ mReplyFullLength(0),
+ mReplyHeaders(),
+ mPolicyRetries(0),
+ mPolicy503Retries(0),
+ mPolicyRetryAt(HttpTime(0)),
+ mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT),
+ mPolicyMinRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MIN_DEFAULT)),
+ mPolicyMaxRetryBackoff(HttpTime(HTTP_RETRY_BACKOFF_MAX_DEFAULT)),
+ mCallbackSSLVerify(NULL)
{
- // *NOTE: As members are added, retry initialization/cleanup
- // may need to be extended in @see prepareRequest().
+ // *NOTE: As members are added, retry initialization/cleanup
+ // may need to be extended in @see prepareRequest().
}
HttpOpRequest::~HttpOpRequest()
{
- if (mReqBody)
- {
- mReqBody->release();
- mReqBody = NULL;
- }
-
- if (mCurlHandle)
- {
- // Uncertain of thread context so free using
- // safest method.
- curl_easy_cleanup(mCurlHandle);
- mCurlHandle = NULL;
- }
-
- mCurlService = NULL;
-
- if (mCurlHeaders)
- {
- curl_slist_free_all(mCurlHeaders);
- mCurlHeaders = NULL;
- }
-
- delete [] mCurlTemp;
- mCurlTemp = NULL;
- mCurlTempLen = 0;
-
- if (mReplyBody)
- {
- mReplyBody->release();
- mReplyBody = NULL;
- }
+ if (mReqBody)
+ {
+ mReqBody->release();
+ mReqBody = NULL;
+ }
+
+ if (mCurlHandle)
+ {
+ // Uncertain of thread context so free using
+ // safest method.
+ curl_easy_cleanup(mCurlHandle);
+ mCurlHandle = NULL;
+ }
+
+ mCurlService = NULL;
+
+ if (mCurlHeaders)
+ {
+ curl_slist_free_all(mCurlHeaders);
+ mCurlHeaders = NULL;
+ }
+
+ delete [] mCurlTemp;
+ mCurlTemp = NULL;
+ mCurlTempLen = 0;
+
+ if (mReplyBody)
+ {
+ mReplyBody->release();
+ mReplyBody = NULL;
+ }
}
@@ -202,7 +202,7 @@ void HttpOpRequest::stageFromRequest(HttpService * service)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
HttpOpRequest::ptr_t self(std::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
- service->getPolicy().addOp(self); // transfers refcount
+ service->getPolicy().addOp(self); // transfers refcount
}
@@ -210,86 +210,86 @@ void HttpOpRequest::stageFromReady(HttpService * service)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
HttpOpRequest::ptr_t self(std::dynamic_pointer_cast<HttpOpRequest>(shared_from_this()));
- service->getTransport().addOp(self); // transfers refcount
+ service->getTransport().addOp(self); // transfers refcount
}
void HttpOpRequest::stageFromActive(HttpService * service)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- if (mReplyLength)
- {
- // If non-zero, we received and processed a Content-Range
- // header with the response. If there is received data
- // (and there may not be due to protocol violations,
- // HEAD requests, etc., see BUG-2295) Verify that what it
- // says is consistent with the received data.
- if (mReplyBody && mReplyBody->size() && mReplyLength != mReplyBody->size())
- {
- // Not as expected, fail the request
- mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
- }
- }
-
- if (mCurlHeaders)
- {
- // We take these headers out of the request now as they were
- // allocated originally in this thread and the notifier doesn't
- // need them. This eliminates one source of heap moving across
- // threads.
-
- curl_slist_free_all(mCurlHeaders);
- mCurlHeaders = NULL;
- }
-
- // Also not needed on the other side
- delete [] mCurlTemp;
- mCurlTemp = NULL;
- mCurlTempLen = 0;
-
- addAsReply();
+ if (mReplyLength)
+ {
+ // If non-zero, we received and processed a Content-Range
+ // header with the response. If there is received data
+ // (and there may not be due to protocol violations,
+ // HEAD requests, etc., see BUG-2295) Verify that what it
+ // says is consistent with the received data.
+ if (mReplyBody && mReplyBody->size() && mReplyLength != mReplyBody->size())
+ {
+ // Not as expected, fail the request
+ mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
+ }
+ }
+
+ if (mCurlHeaders)
+ {
+ // We take these headers out of the request now as they were
+ // allocated originally in this thread and the notifier doesn't
+ // need them. This eliminates one source of heap moving across
+ // threads.
+
+ curl_slist_free_all(mCurlHeaders);
+ mCurlHeaders = NULL;
+ }
+
+ // Also not needed on the other side
+ delete [] mCurlTemp;
+ mCurlTemp = NULL;
+ mCurlTempLen = 0;
+
+ addAsReply();
}
void HttpOpRequest::visitNotifier(HttpRequest * request)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- if (mUserHandler)
- {
- HttpResponse * response = new HttpResponse();
- response->setStatus(mStatus);
- response->setBody(mReplyBody);
- response->setHeaders(mReplyHeaders);
+ if (mUserHandler)
+ {
+ HttpResponse * response = new HttpResponse();
+ response->setStatus(mStatus);
+ response->setBody(mReplyBody);
+ response->setHeaders(mReplyHeaders);
response->setRequestURL(mReqURL);
response->setRequestMethod(methodToString(mReqMethod));
if (mReplyOffset || mReplyLength)
- {
- // Got an explicit offset/length in response
- response->setRange(mReplyOffset, mReplyLength, mReplyFullLength);
- }
- response->setContentType(mReplyConType);
- response->setRetries(mPolicyRetries, mPolicy503Retries);
-
- HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
+ {
+ // Got an explicit offset/length in response
+ response->setRange(mReplyOffset, mReplyLength, mReplyFullLength);
+ }
+ response->setContentType(mReplyConType);
+ response->setRetries(mPolicyRetries, mPolicy503Retries);
- 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);
+ HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
- response->setTransferStats(stats);
+ 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);
- mUserHandler->onCompleted(this->getHandle(), response);
+ response->setTransferStats(stats);
- response->release();
- }
+ mUserHandler->onCompleted(this->getHandle(), response);
+
+ response->release();
+ }
}
// /*static*/
// HttpOpRequest::ptr_t HttpOpRequest::fromHandle(HttpHandle handle)
// {
-//
+//
// return std::dynamic_pointer_cast<HttpOpRequest>((static_cast<HttpOpRequest *>(handle))->shared_from_this());
// }
@@ -297,73 +297,73 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
HttpStatus HttpOpRequest::cancel()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED);
+ mStatus = HttpStatus(HttpStatus::LLCORE, HE_OP_CANCELED);
- addAsReply();
+ addAsReply();
- return HttpStatus();
+ return HttpStatus();
}
HttpStatus HttpOpRequest::setupGet(HttpRequest::policy_t policy_id,
- const std::string & url,
+ const std::string & url,
const HttpOptions::ptr_t & options,
- const HttpHeaders::ptr_t & headers)
+ const HttpHeaders::ptr_t & headers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- setupCommon(policy_id, url, NULL, options, headers);
- mReqMethod = HOR_GET;
-
- return HttpStatus();
+ setupCommon(policy_id, url, NULL, options, headers);
+ mReqMethod = HOR_GET;
+
+ return HttpStatus();
}
HttpStatus HttpOpRequest::setupGetByteRange(HttpRequest::policy_t policy_id,
- const std::string & url,
- size_t offset,
- size_t len,
+ const std::string & url,
+ size_t offset,
+ size_t len,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- setupCommon(policy_id, url, NULL, options, headers);
- mReqMethod = HOR_GET;
- mReqOffset = offset;
- mReqLength = len;
- if (offset || len)
- {
- mProcFlags |= PF_SCAN_RANGE_HEADER;
- }
-
- return HttpStatus();
+ setupCommon(policy_id, url, NULL, options, headers);
+ mReqMethod = HOR_GET;
+ mReqOffset = offset;
+ mReqLength = len;
+ if (offset || len)
+ {
+ mProcFlags |= PF_SCAN_RANGE_HEADER;
+ }
+
+ return HttpStatus();
}
HttpStatus HttpOpRequest::setupPost(HttpRequest::policy_t policy_id,
- const std::string & url,
- BufferArray * body,
+ const std::string & url,
+ BufferArray * body,
const HttpOptions::ptr_t & options,
const HttpHeaders::ptr_t & headers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- setupCommon(policy_id, url, body, options, headers);
- mReqMethod = HOR_POST;
-
- return HttpStatus();
+ setupCommon(policy_id, url, body, options, headers);
+ mReqMethod = HOR_POST;
+
+ return HttpStatus();
}
HttpStatus HttpOpRequest::setupPut(HttpRequest::policy_t policy_id,
- const std::string & url,
- BufferArray * body,
+ const std::string & url,
+ BufferArray * body,
const HttpOptions::ptr_t & options,
- const HttpHeaders::ptr_t & headers)
+ const HttpHeaders::ptr_t & headers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- setupCommon(policy_id, url, body, options, headers);
- mReqMethod = HOR_PUT;
-
- return HttpStatus();
+ setupCommon(policy_id, url, body, options, headers);
+ mReqMethod = HOR_PUT;
+
+ return HttpStatus();
}
@@ -421,42 +421,42 @@ HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
- const std::string & url,
- BufferArray * body,
+ const std::string & url,
+ BufferArray * body,
const HttpOptions::ptr_t & options,
- const HttpHeaders::ptr_t & headers)
+ const HttpHeaders::ptr_t & headers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- mProcFlags = 0U;
- mReqPolicy = policy_id;
- mReqURL = url;
- if (body)
- {
- body->addRef();
- mReqBody = body;
- }
- if (headers && ! mReqHeaders)
- {
- mReqHeaders = headers;
- }
- if (options && !mReqOptions)
- {
- mReqOptions = options;
- if (options->getWantHeaders())
- {
- mProcFlags |= PF_SAVE_HEADERS;
- }
- if (options->getUseRetryAfter())
- {
- mProcFlags |= PF_USE_RETRY_AFTER;
- }
- mPolicyRetryLimit = options->getRetries();
- mPolicyRetryLimit = llclamp(mPolicyRetryLimit, HTTP_RETRY_COUNT_MIN, HTTP_RETRY_COUNT_MAX);
- mTracing = (std::max)(mTracing, llclamp(options->getTrace(), HTTP_TRACE_MIN, HTTP_TRACE_MAX));
-
- mPolicyMinRetryBackoff = llclamp(options->getMinBackoff(), HttpTime(0), HTTP_RETRY_BACKOFF_MAX);
- mPolicyMaxRetryBackoff = llclamp(options->getMaxBackoff(), mPolicyMinRetryBackoff, HTTP_RETRY_BACKOFF_MAX);
- }
+ mProcFlags = 0U;
+ mReqPolicy = policy_id;
+ mReqURL = url;
+ if (body)
+ {
+ body->addRef();
+ mReqBody = body;
+ }
+ if (headers && ! mReqHeaders)
+ {
+ mReqHeaders = headers;
+ }
+ if (options && !mReqOptions)
+ {
+ mReqOptions = options;
+ if (options->getWantHeaders())
+ {
+ mProcFlags |= PF_SAVE_HEADERS;
+ }
+ if (options->getUseRetryAfter())
+ {
+ mProcFlags |= PF_USE_RETRY_AFTER;
+ }
+ mPolicyRetryLimit = options->getRetries();
+ mPolicyRetryLimit = llclamp(mPolicyRetryLimit, HTTP_RETRY_COUNT_MIN, HTTP_RETRY_COUNT_MAX);
+ mTracing = (std::max)(mTracing, llclamp(options->getTrace(), HTTP_TRACE_MIN, HTTP_TRACE_MAX));
+
+ mPolicyMinRetryBackoff = llclamp(options->getMinBackoff(), HttpTime(0), HTTP_RETRY_BACKOFF_MAX);
+ mPolicyMaxRetryBackoff = llclamp(options->getMaxBackoff(), mPolicyMinRetryBackoff, HTTP_RETRY_BACKOFF_MAX);
+ }
}
// Sets all libcurl options and data for a request.
@@ -470,167 +470,167 @@ void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- // Scrub transport and result data for retried op case
- mCurlActive = false;
- mCurlHandle = NULL;
- mCurlService = NULL;
- if (mCurlHeaders)
- {
- curl_slist_free_all(mCurlHeaders);
- mCurlHeaders = NULL;
- }
- mCurlBodyPos = 0;
-
- if (mReplyBody)
- {
- mReplyBody->release();
- mReplyBody = NULL;
- }
- mReplyOffset = 0;
- mReplyLength = 0;
- mReplyFullLength = 0;
+ // Scrub transport and result data for retried op case
+ mCurlActive = false;
+ mCurlHandle = NULL;
+ mCurlService = NULL;
+ if (mCurlHeaders)
+ {
+ curl_slist_free_all(mCurlHeaders);
+ mCurlHeaders = NULL;
+ }
+ mCurlBodyPos = 0;
+
+ if (mReplyBody)
+ {
+ mReplyBody->release();
+ mReplyBody = NULL;
+ }
+ mReplyOffset = 0;
+ mReplyLength = 0;
+ mReplyFullLength = 0;
mReplyHeaders.reset();
- mReplyConType.clear();
-
- // *FIXME: better error handling later
- HttpStatus status;
-
- // Get global and class policy options
- HttpPolicyGlobal & gpolicy(service->getPolicy().getGlobalOptions());
- HttpPolicyClass & cpolicy(service->getPolicy().getClassOptions(mReqPolicy));
-
- mCurlHandle = service->getTransport().getHandle();
- if (! mCurlHandle)
- {
- // We're in trouble. We'll continue but it won't go well.
- LL_WARNS(LOG_CORE) << "Failed to allocate libcurl easy handle. Continuing."
- << LL_ENDL;
- return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC);
- }
-
- check_curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str());
- check_curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle());
- //check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
-
- check_curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
+ mReplyConType.clear();
+
+ // *FIXME: better error handling later
+ HttpStatus status;
+
+ // Get global and class policy options
+ HttpPolicyGlobal & gpolicy(service->getPolicy().getGlobalOptions());
+ HttpPolicyClass & cpolicy(service->getPolicy().getClassOptions(mReqPolicy));
+
+ mCurlHandle = service->getTransport().getHandle();
+ if (! mCurlHandle)
+ {
+ // We're in trouble. We'll continue but it won't go well.
+ LL_WARNS(LOG_CORE) << "Failed to allocate libcurl easy handle. Continuing."
+ << LL_ENDL;
+ return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC);
+ }
+
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str());
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle());
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
+
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, getHandle());
- check_curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, getHandle());
check_curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, getHandle());
- check_curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
- if (gpolicy.mSslCtxCallback)
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
+ if (gpolicy.mSslCtxCallback)
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, getHandle());
- mCallbackSSLVerify = gpolicy.mSslCtxCallback;
- }
+ mCallbackSSLVerify = gpolicy.mSslCtxCallback;
+ }
- long follow_redirect(1L);
- long sslPeerV(0L);
- long sslHostV(0L);
+ long follow_redirect(1L);
+ long sslPeerV(0L);
+ long sslHostV(0L);
long dnsCacheTimeout(-1L);
long nobody(0L);
- if (mReqOptions)
- {
- follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L;
- sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L;
- sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L;
- dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
+ if (mReqOptions)
+ {
+ follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L;
+ sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L;
+ sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L;
+ dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
nobody = mReqOptions->getHeadersOnly() ? 1L : 0L;
- }
- check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
+ }
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
check_curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody);
- // 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.
- //
- // -1 stores forever
- // 0 never stores
- // any other positive number specifies seconds
- // supposedly curl 7.62.0 can use TTL by default, otherwise default is 60 seconds
- check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
-
- if (gpolicy.mUseLLProxy)
- {
- // Use the viewer-based thread-safe API which has a
- // fast/safe check for proxy enable. Would like to
- // encapsulate this someway...
- // Make sure proxy won't be getInstance() from here,
- // it is not thread safe
- LLProxy::applyProxySettings(mCurlHandle);
-
- }
- else if (gpolicy.mHttpProxy.size())
- {
- // *TODO: This is fine for now but get fuller socks5/
- // authentication thing going later....
- check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, gpolicy.mHttpProxy.c_str());
- check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
- }
- if (gpolicy.mCAPath.size())
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, gpolicy.mCAPath.c_str());
- }
- if (gpolicy.mCAFile.size())
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, gpolicy.mCAFile.c_str());
- }
-
- switch (mReqMethod)
- {
- case HOR_GET:
+ // 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.
+ //
+ // -1 stores forever
+ // 0 never stores
+ // any other positive number specifies seconds
+ // supposedly curl 7.62.0 can use TTL by default, otherwise default is 60 seconds
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
+
+ if (gpolicy.mUseLLProxy)
+ {
+ // Use the viewer-based thread-safe API which has a
+ // fast/safe check for proxy enable. Would like to
+ // encapsulate this someway...
+ // Make sure proxy won't be getInstance() from here,
+ // it is not thread safe
+ LLProxy::applyProxySettings(mCurlHandle);
+
+ }
+ else if (gpolicy.mHttpProxy.size())
+ {
+ // *TODO: This is fine for now but get fuller socks5/
+ // authentication thing going later....
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, gpolicy.mHttpProxy.c_str());
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ }
+ if (gpolicy.mCAPath.size())
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, gpolicy.mCAPath.c_str());
+ }
+ if (gpolicy.mCAFile.size())
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, gpolicy.mCAFile.c_str());
+ }
+
+ switch (mReqMethod)
+ {
+ case HOR_GET:
if (nobody == 0)
check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);
- break;
-
- case HOR_POST:
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1);
- //check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
- long data_size(0);
- if (mReqBody)
- {
- data_size = mReqBody->size();
- }
- check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL));
- check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
- }
- break;
-
+ break;
+
+ case HOR_POST:
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1);
+ //check_curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
+ long data_size(0);
+ if (mReqBody)
+ {
+ data_size = mReqBody->size();
+ }
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL));
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
+ }
+ break;
+
case HOR_PATCH:
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH");
// fall through. The rest is the same as PUT
case HOR_PUT:
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);
- long data_size(0);
- if (mReqBody)
- {
- data_size = mReqBody->size();
- }
- check_curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
- }
- break;
-
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);
+ long data_size(0);
+ if (mReqBody)
+ {
+ data_size = mReqBody->size();
+ }
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
+ }
+ break;
+
case HOR_DELETE:
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
@@ -643,136 +643,136 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE");
break;
- default:
- LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: "
- << int(mReqMethod) << ". Can't recover."
- << LL_ENDL;
- break;
- }
+ default:
+ LL_ERRS(LOG_CORE) << "Invalid HTTP method in request: "
+ << int(mReqMethod) << ". Can't recover."
+ << LL_ENDL;
+ break;
+ }
// *TODO: Should this be 'Keep-Alive' ?
mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");
mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");
- // Tracing
- if (mTracing >= HTTP_TRACE_CURL_HEADERS)
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback);
- }
-
- // There's a CURLOPT for this now...
- if ((mReqOffset || mReqLength) && HOR_GET == mReqMethod)
- {
- static const char * const fmt1("Range: bytes=%lu-%lu");
- static const char * const fmt2("Range: bytes=%lu-");
-
- char range_line[64];
+ // Tracing
+ if (mTracing >= HTTP_TRACE_CURL_HEADERS)
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback);
+ }
+
+ // There's a CURLOPT for this now...
+ if ((mReqOffset || mReqLength) && HOR_GET == mReqMethod)
+ {
+ static const char * const fmt1("Range: bytes=%lu-%lu");
+ static const char * const fmt2("Range: bytes=%lu-");
+
+ char range_line[64];
#if LL_WINDOWS
- _snprintf_s(range_line, sizeof(range_line), sizeof(range_line) - 1,
- (mReqLength ? fmt1 : fmt2),
- (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1));
+ _snprintf_s(range_line, sizeof(range_line), sizeof(range_line) - 1,
+ (mReqLength ? fmt1 : fmt2),
+ (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1));
#else
- if ( mReqLength )
- {
- snprintf(range_line, sizeof(range_line),
- fmt1,
- (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1));
- }
- else
- {
- snprintf(range_line, sizeof(range_line),
- fmt2,
- (unsigned long) mReqOffset);
- }
+ if ( mReqLength )
+ {
+ snprintf(range_line, sizeof(range_line),
+ fmt1,
+ (unsigned long) mReqOffset, (unsigned long) (mReqOffset + mReqLength - 1));
+ }
+ else
+ {
+ snprintf(range_line, sizeof(range_line),
+ fmt2,
+ (unsigned long) mReqOffset);
+ }
#endif // LL_WINDOWS
- range_line[sizeof(range_line) - 1] = '\0';
- mCurlHeaders = curl_slist_append(mCurlHeaders, range_line);
- }
-
- mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:");
-
- // Request options
- long timeout(HTTP_REQUEST_TIMEOUT_DEFAULT);
- long xfer_timeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT);
- if (mReqOptions)
- {
- timeout = mReqOptions->getTimeout();
- timeout = llclamp(timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX);
- xfer_timeout = mReqOptions->getTransferTimeout();
- xfer_timeout = llclamp(xfer_timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX);
- }
- if (xfer_timeout == 0L)
- {
- xfer_timeout = timeout;
- }
- if (cpolicy.mPipelining > 1L)
- {
- // Pipelining affects both connection and transfer timeout values.
- // Requests that are added to a pipeling immediately have completed
- // their connection so the connection delay tends to be less than
- // the non-pipelined value. Transfers are the opposite. Transfer
- // timeout starts once the connection is established and completion
- // can be delayed due to the pipelined requests ahead. So, it's
- // a handwave but bump the transfer timeout up by the pipelining
- // depth to give some room.
- //
- // BUG-7698, BUG-7688, BUG-7694 (others). Scylla and Charybdis
- // situation. Operating against a CDN having service issues may
- // lead to requests stalling for an arbitrarily long time with only
- // the CURLOPT_TIMEOUT value leading to a closed connection. Sadly
- // for pipelining, libcurl (7.39.0 and earlier, at minimum) starts
- // the clock on this value as soon as a request is started down
- // the wire. We want a short value to recover and retry from the
- // CDN. We need a long value to safely deal with a succession of
- // piled-up pipelined requests.
- //
- // *TODO: Find a better scheme than timeouts to guarantee liveness.
- // Progress on the connection is what we really want, not timeouts.
- // But we don't have access to that and the request progress indicators
- // (various libcurl callbacks) have the same problem TIMEOUT does.
- //
- // xfer_timeout *= cpolicy.mPipelining;
- xfer_timeout *= 2L;
-
- // Also try requesting HTTP/2.
+ range_line[sizeof(range_line) - 1] = '\0';
+ mCurlHeaders = curl_slist_append(mCurlHeaders, range_line);
+ }
+
+ mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:");
+
+ // Request options
+ long timeout(HTTP_REQUEST_TIMEOUT_DEFAULT);
+ long xfer_timeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT);
+ if (mReqOptions)
+ {
+ timeout = mReqOptions->getTimeout();
+ timeout = llclamp(timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX);
+ xfer_timeout = mReqOptions->getTransferTimeout();
+ xfer_timeout = llclamp(xfer_timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX);
+ }
+ if (xfer_timeout == 0L)
+ {
+ xfer_timeout = timeout;
+ }
+ if (cpolicy.mPipelining > 1L)
+ {
+ // Pipelining affects both connection and transfer timeout values.
+ // Requests that are added to a pipeling immediately have completed
+ // their connection so the connection delay tends to be less than
+ // the non-pipelined value. Transfers are the opposite. Transfer
+ // timeout starts once the connection is established and completion
+ // can be delayed due to the pipelined requests ahead. So, it's
+ // a handwave but bump the transfer timeout up by the pipelining
+ // depth to give some room.
+ //
+ // BUG-7698, BUG-7688, BUG-7694 (others). Scylla and Charybdis
+ // situation. Operating against a CDN having service issues may
+ // lead to requests stalling for an arbitrarily long time with only
+ // the CURLOPT_TIMEOUT value leading to a closed connection. Sadly
+ // for pipelining, libcurl (7.39.0 and earlier, at minimum) starts
+ // the clock on this value as soon as a request is started down
+ // the wire. We want a short value to recover and retry from the
+ // CDN. We need a long value to safely deal with a succession of
+ // piled-up pipelined requests.
+ //
+ // *TODO: Find a better scheme than timeouts to guarantee liveness.
+ // Progress on the connection is what we really want, not timeouts.
+ // But we don't have access to that and the request progress indicators
+ // (various libcurl callbacks) have the same problem TIMEOUT does.
+ //
+ // xfer_timeout *= cpolicy.mPipelining;
+ xfer_timeout *= 2L;
+
+ // Also try requesting HTTP/2.
/******************************/
- // but for test purposes, only if overriding VIEWERASSET
- if (getenv("VIEWERASSET"))
+ // but for test purposes, only if overriding VIEWERASSET
+ if (getenv("VIEWERASSET"))
/******************************/
- check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
- }
- // *DEBUG: Enable following override for timeout handling and "[curl:bugs] #1420" tests
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
+ }
+ // *DEBUG: Enable following override for timeout handling and "[curl:bugs] #1420" tests
//if (cpolicy.mPipelining)
//{
// xfer_timeout = 1L;
// timeout = 1L;
//}
- check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout);
-
- // Request headers
- if (mReqHeaders)
- {
- // Caller's headers last to override
- mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders);
- }
- check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
-
- if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER))
- {
- check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback);
- check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this);
- }
-
- if (status)
- {
- mCurlService = service;
- }
- return status;
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout);
+
+ // Request headers
+ if (mReqHeaders)
+ {
+ // Caller's headers last to override
+ mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders);
+ }
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
+
+ if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER))
+ {
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback);
+ check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this);
+ }
+
+ if (status)
+ {
+ mCurlService = service;
+ }
+ return status;
}
@@ -781,46 +781,46 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
- if (! op->mReplyBody)
- {
- op->mReplyBody = new BufferArray();
- }
- const size_t req_size(size * nmemb);
- const size_t write_size(op->mReplyBody->append(static_cast<char *>(data), req_size));
+ if (! op->mReplyBody)
+ {
+ op->mReplyBody = new BufferArray();
+ }
+ const size_t req_size(size * nmemb);
+ const size_t write_size(op->mReplyBody->append(static_cast<char *>(data), req_size));
HTTPStats::instance().recordDataDown(write_size);
- return write_size;
+ return write_size;
}
-
+
size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void * userdata)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
- if (! op->mReqBody)
- {
- return 0;
- }
- const size_t req_size(size * nmemb);
- const size_t body_size(op->mReqBody->size());
- if (body_size <= op->mCurlBodyPos)
- {
- if (body_size < op->mCurlBodyPos)
- {
- // Warn but continue if the read position moves beyond end-of-body
- // for some reason.
- LL_WARNS(LOG_CORE) << "Request body position beyond body size. Truncating request body."
- << LL_ENDL;
- }
- return 0;
- }
-
- const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos));
- const size_t read_size(op->mReqBody->read(op->mCurlBodyPos, static_cast<char *>(data), do_size));
+ if (! op->mReqBody)
+ {
+ return 0;
+ }
+ const size_t req_size(size * nmemb);
+ const size_t body_size(op->mReqBody->size());
+ if (body_size <= op->mCurlBodyPos)
+ {
+ if (body_size < op->mCurlBodyPos)
+ {
+ // Warn but continue if the read position moves beyond end-of-body
+ // for some reason.
+ LL_WARNS(LOG_CORE) << "Request body position beyond body size. Truncating request body."
+ << LL_ENDL;
+ }
+ return 0;
+ }
+
+ const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos));
+ const size_t read_size(op->mReqBody->read(op->mCurlBodyPos, static_cast<char *>(data), do_size));
// FIXME: singleton's instance() is Thread unsafe! Even if stats accumulators inside are.
HTTPStats::instance().recordDataUp(read_size);
op->mCurlBodyPos += read_size;
- return read_size;
+ return read_size;
}
@@ -855,154 +855,154 @@ int HttpOpRequest::seekCallback(void *userdata, curl_off_t offset, int origin)
return 0;
}
-
+
size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, void * userdata)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
- static const char status_line[] = "HTTP/";
- static const size_t status_line_len = sizeof(status_line) - 1;
- static const char con_ran_line[] = "content-range";
- static const char con_retry_line[] = "retry-after";
-
+ static const char status_line[] = "HTTP/";
+ static const size_t status_line_len = sizeof(status_line) - 1;
+ static const char con_ran_line[] = "content-range";
+ static const char con_retry_line[] = "retry-after";
+
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
- const size_t hdr_size(size * nmemb);
- const char * hdr_data(static_cast<const char *>(data)); // Not null terminated
- bool is_header(true);
-
- if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len))
- {
- // One of possibly several status lines. Reset what we know and start over
- // taking results from the last header stanza we receive.
- op->mReplyOffset = 0;
- op->mReplyLength = 0;
- op->mReplyFullLength = 0;
- op->mReplyRetryAfter = 0;
- op->mStatus = HttpStatus();
- if (op->mReplyHeaders)
- {
- op->mReplyHeaders->clear();
- }
- is_header = false;
- }
-
- // Nothing in here wants a final CR/LF combination. Remove
- // it as much as possible.
- size_t wanted_hdr_size(hdr_size);
- if (wanted_hdr_size && '\n' == hdr_data[wanted_hdr_size - 1])
- {
- if (--wanted_hdr_size && '\r' == hdr_data[wanted_hdr_size - 1])
- {
- --wanted_hdr_size;
- }
- }
-
- // Copy and normalize header fragments for the following
- // stages. Would like to modify the data in-place but that
- // may not be allowed and we need one byte extra for NUL.
- // At the end of this we will have:
- //
- // If ':' present in header:
- // 1. name points to text to left of colon which
- // will be ascii lower-cased and left and right
- // trimmed of whitespace.
- // 2. value points to text to right of colon which
- // will be left trimmed of whitespace.
- // Otherwise:
- // 1. name points to header which will be left
- // trimmed of whitespace.
- // 2. value is NULL
- // Any non-NULL pointer may point to a zero-length string.
- //
- if (wanted_hdr_size >= op->mCurlTempLen)
- {
- delete [] op->mCurlTemp;
- op->mCurlTempLen = 2 * wanted_hdr_size + 1;
- op->mCurlTemp = new char [op->mCurlTempLen];
- }
- memcpy(op->mCurlTemp, hdr_data, wanted_hdr_size);
- op->mCurlTemp[wanted_hdr_size] = '\0';
- char * name(op->mCurlTemp);
- char * value(strchr(name, ':'));
- if (value)
- {
- *value++ = '\0';
- os_strlower(name);
- name = os_strtrim(name);
- value = os_strltrim(value);
- }
- else
- {
- // Doesn't look well-formed, do minimal normalization on it
- name = os_strltrim(name);
- }
-
- // Normalized, now reject headers with empty names.
- if (! *name)
- {
- // No use continuing
- return hdr_size;
- }
-
- // Save header if caller wants them in the response
- if (is_header && op->mProcFlags & PF_SAVE_HEADERS)
- {
- // Save headers in response
- if (! op->mReplyHeaders)
- {
- op->mReplyHeaders = HttpHeaders::ptr_t(new HttpHeaders);
- }
- op->mReplyHeaders->append(name, value ? value : "");
- }
-
- // From this point, header-specific processors are free to
- // modify the header value.
-
- // Detect and parse 'Content-Range' headers
- if (is_header
- && op->mProcFlags & PF_SCAN_RANGE_HEADER
- && value && *value
- && ! strcmp(name, con_ran_line))
- {
- unsigned int first(0), last(0), length(0);
- int status;
-
- if (! (status = parse_content_range_header(value, &first, &last, &length)))
- {
- // Success, record the fragment position
- op->mReplyOffset = first;
- op->mReplyLength = last - first + 1;
- op->mReplyFullLength = length;
- }
- else if (-1 == status)
- {
- // Response is badly formed and shouldn't be accepted
- op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
- }
- else
- {
- // Ignore the unparsable.
- LL_INFOS_ONCE(LOG_CORE) << "Problem parsing odd Content-Range header: '"
- << std::string(hdr_data, wanted_hdr_size)
- << "'. Ignoring."
- << LL_ENDL;
- }
- }
-
- // Detect and parse 'Retry-After' headers
- if (is_header
- && op->mProcFlags & PF_USE_RETRY_AFTER
- && value && *value
- && ! strcmp(name, con_retry_line))
- {
- int time(0);
- if (! parse_retry_after_header(value, &time))
- {
- op->mReplyRetryAfter = time;
- }
- }
-
- return hdr_size;
+ const size_t hdr_size(size * nmemb);
+ const char * hdr_data(static_cast<const char *>(data)); // Not null terminated
+ bool is_header(true);
+
+ if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len))
+ {
+ // One of possibly several status lines. Reset what we know and start over
+ // taking results from the last header stanza we receive.
+ op->mReplyOffset = 0;
+ op->mReplyLength = 0;
+ op->mReplyFullLength = 0;
+ op->mReplyRetryAfter = 0;
+ op->mStatus = HttpStatus();
+ if (op->mReplyHeaders)
+ {
+ op->mReplyHeaders->clear();
+ }
+ is_header = false;
+ }
+
+ // Nothing in here wants a final CR/LF combination. Remove
+ // it as much as possible.
+ size_t wanted_hdr_size(hdr_size);
+ if (wanted_hdr_size && '\n' == hdr_data[wanted_hdr_size - 1])
+ {
+ if (--wanted_hdr_size && '\r' == hdr_data[wanted_hdr_size - 1])
+ {
+ --wanted_hdr_size;
+ }
+ }
+
+ // Copy and normalize header fragments for the following
+ // stages. Would like to modify the data in-place but that
+ // may not be allowed and we need one byte extra for NUL.
+ // At the end of this we will have:
+ //
+ // If ':' present in header:
+ // 1. name points to text to left of colon which
+ // will be ascii lower-cased and left and right
+ // trimmed of whitespace.
+ // 2. value points to text to right of colon which
+ // will be left trimmed of whitespace.
+ // Otherwise:
+ // 1. name points to header which will be left
+ // trimmed of whitespace.
+ // 2. value is NULL
+ // Any non-NULL pointer may point to a zero-length string.
+ //
+ if (wanted_hdr_size >= op->mCurlTempLen)
+ {
+ delete [] op->mCurlTemp;
+ op->mCurlTempLen = 2 * wanted_hdr_size + 1;
+ op->mCurlTemp = new char [op->mCurlTempLen];
+ }
+ memcpy(op->mCurlTemp, hdr_data, wanted_hdr_size);
+ op->mCurlTemp[wanted_hdr_size] = '\0';
+ char * name(op->mCurlTemp);
+ char * value(strchr(name, ':'));
+ if (value)
+ {
+ *value++ = '\0';
+ os_strlower(name);
+ name = os_strtrim(name);
+ value = os_strltrim(value);
+ }
+ else
+ {
+ // Doesn't look well-formed, do minimal normalization on it
+ name = os_strltrim(name);
+ }
+
+ // Normalized, now reject headers with empty names.
+ if (! *name)
+ {
+ // No use continuing
+ return hdr_size;
+ }
+
+ // Save header if caller wants them in the response
+ if (is_header && op->mProcFlags & PF_SAVE_HEADERS)
+ {
+ // Save headers in response
+ if (! op->mReplyHeaders)
+ {
+ op->mReplyHeaders = HttpHeaders::ptr_t(new HttpHeaders);
+ }
+ op->mReplyHeaders->append(name, value ? value : "");
+ }
+
+ // From this point, header-specific processors are free to
+ // modify the header value.
+
+ // Detect and parse 'Content-Range' headers
+ if (is_header
+ && op->mProcFlags & PF_SCAN_RANGE_HEADER
+ && value && *value
+ && ! strcmp(name, con_ran_line))
+ {
+ unsigned int first(0), last(0), length(0);
+ int status;
+
+ if (! (status = parse_content_range_header(value, &first, &last, &length)))
+ {
+ // Success, record the fragment position
+ op->mReplyOffset = first;
+ op->mReplyLength = last - first + 1;
+ op->mReplyFullLength = length;
+ }
+ else if (-1 == status)
+ {
+ // Response is badly formed and shouldn't be accepted
+ op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
+ }
+ else
+ {
+ // Ignore the unparsable.
+ LL_INFOS_ONCE(LOG_CORE) << "Problem parsing odd Content-Range header: '"
+ << std::string(hdr_data, wanted_hdr_size)
+ << "'. Ignoring."
+ << LL_ENDL;
+ }
+ }
+
+ // Detect and parse 'Retry-After' headers
+ if (is_header
+ && op->mProcFlags & PF_USE_RETRY_AFTER
+ && value && *value
+ && ! strcmp(name, con_retry_line))
+ {
+ int time(0);
+ if (! parse_retry_after_header(value, &time))
+ {
+ op->mReplyRetryAfter = time;
+ }
+ }
+
+ return hdr_size;
}
@@ -1025,12 +1025,12 @@ CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userd
// Ex: setting urls (assume non-SL) for parcel media in LLFloaterURLEntry
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
- }
+ // set the verification callback.
+ SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata);
+ // the calls are void
+ }
- return CURLE_OK;
+ return CURLE_OK;
}
int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
@@ -1038,12 +1038,12 @@ int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(param));
- if (op->mCallbackSSLVerify)
- {
- op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx);
- }
+ if (op->mCallbackSSLVerify)
+ {
+ op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx);
+ }
- return (op->mStatus) ? 1 : 0;
+ return (op->mStatus) ? 1 : 0;
}
int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
@@ -1051,91 +1051,91 @@ int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffe
LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
HttpOpRequest::ptr_t op(HttpOpRequest::fromHandle<HttpOpRequest>(userdata));
- std::string safe_line;
- std::string tag;
- bool logit(false);
- const size_t log_len((std::min)(len, size_t(256))); // Keep things reasonable in all cases
-
- switch (info)
- {
- case CURLINFO_TEXT:
- if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
- {
- tag = "TEXT";
- escape_libcurl_debug_data(buffer, log_len, true, safe_line);
- logit = true;
- }
- break;
-
- case CURLINFO_HEADER_IN:
- if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
- {
- tag = "HEADERIN";
- escape_libcurl_debug_data(buffer, log_len, true, safe_line);
- logit = true;
- }
- break;
-
- case CURLINFO_HEADER_OUT:
- if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
- {
- tag = "HEADEROUT";
- escape_libcurl_debug_data(buffer, log_len, true, safe_line); // Goes out as one line unlike header_in
- logit = true;
- }
- break;
-
- case CURLINFO_DATA_IN:
- if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
- {
- tag = "DATAIN";
- logit = true;
- if (op->mTracing >= HTTP_TRACE_CURL_BODIES)
- {
- escape_libcurl_debug_data(buffer, log_len, false, safe_line);
- }
- else
- {
- std::ostringstream out;
- out << len << " Bytes";
- safe_line = out.str();
- }
- }
- break;
-
- case CURLINFO_DATA_OUT:
- if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
- {
- tag = "DATAOUT";
- logit = true;
- if (op->mTracing >= HTTP_TRACE_CURL_BODIES)
- {
- escape_libcurl_debug_data(buffer, log_len, false, safe_line);
- }
- else
- {
- std::ostringstream out;
- out << len << " Bytes";
- safe_line = out.str();
- }
- }
- break;
-
- default:
- logit = false;
- break;
- }
-
- if (logit)
- {
- LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle: "
- << op->getHandle()
- << ", Type: " << tag
- << ", Data: " << safe_line
- << LL_ENDL;
- }
-
- return 0;
+ std::string safe_line;
+ std::string tag;
+ bool logit(false);
+ const size_t log_len((std::min)(len, size_t(256))); // Keep things reasonable in all cases
+
+ switch (info)
+ {
+ case CURLINFO_TEXT:
+ if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
+ {
+ tag = "TEXT";
+ escape_libcurl_debug_data(buffer, log_len, true, safe_line);
+ logit = true;
+ }
+ break;
+
+ case CURLINFO_HEADER_IN:
+ if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
+ {
+ tag = "HEADERIN";
+ escape_libcurl_debug_data(buffer, log_len, true, safe_line);
+ logit = true;
+ }
+ break;
+
+ case CURLINFO_HEADER_OUT:
+ if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
+ {
+ tag = "HEADEROUT";
+ escape_libcurl_debug_data(buffer, log_len, true, safe_line); // Goes out as one line unlike header_in
+ logit = true;
+ }
+ break;
+
+ case CURLINFO_DATA_IN:
+ if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
+ {
+ tag = "DATAIN";
+ logit = true;
+ if (op->mTracing >= HTTP_TRACE_CURL_BODIES)
+ {
+ escape_libcurl_debug_data(buffer, log_len, false, safe_line);
+ }
+ else
+ {
+ std::ostringstream out;
+ out << len << " Bytes";
+ safe_line = out.str();
+ }
+ }
+ break;
+
+ case CURLINFO_DATA_OUT:
+ if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
+ {
+ tag = "DATAOUT";
+ logit = true;
+ if (op->mTracing >= HTTP_TRACE_CURL_BODIES)
+ {
+ escape_libcurl_debug_data(buffer, log_len, false, safe_line);
+ }
+ else
+ {
+ std::ostringstream out;
+ out << len << " Bytes";
+ safe_line = out.str();
+ }
+ }
+ break;
+
+ default:
+ logit = false;
+ break;
+ }
+
+ if (logit)
+ {
+ LL_INFOS(LOG_CORE) << "TRACE, LibcurlDebug, Handle: "
+ << op->getHandle()
+ << ", Type: " << tag
+ << ", Data: " << safe_line
+ << LL_ENDL;
+ }
+
+ return 0;
}
std::string HttpOpRequest::methodToString(const HttpOpRequest::EMethod &e)
@@ -1169,110 +1169,110 @@ namespace
{
int parse_content_range_header(char * buffer,
- unsigned int * first,
- unsigned int * last,
- unsigned int * length)
+ unsigned int * first,
+ unsigned int * last,
+ unsigned int * length)
{
- static const char * const hdr_whitespace(" \t");
-
- char * tok_state(NULL), * tok(NULL);
- bool match(true);
-
- if (! (tok = os_strtok_r(buffer, hdr_whitespace, &tok_state)))
- match = false;
- else
- match = (0 == os_strcasecmp("bytes", tok));
- if (match && ! (tok = os_strtok_r(NULL, hdr_whitespace, &tok_state)))
- match = false;
- if (match)
- {
- unsigned int lcl_first(0), lcl_last(0), lcl_len(0);
+ static const char * const hdr_whitespace(" \t");
+
+ char * tok_state(NULL), * tok(NULL);
+ bool match(true);
+
+ if (! (tok = os_strtok_r(buffer, hdr_whitespace, &tok_state)))
+ match = false;
+ else
+ match = (0 == os_strcasecmp("bytes", tok));
+ if (match && ! (tok = os_strtok_r(NULL, hdr_whitespace, &tok_state)))
+ match = false;
+ if (match)
+ {
+ unsigned int lcl_first(0), lcl_last(0), lcl_len(0);
#if LL_WINDOWS
- if (3 == sscanf_s(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len))
+ if (3 == sscanf_s(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len))
#else
- if (3 == sscanf(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len))
+ if (3 == sscanf(tok, "%u-%u/%u", &lcl_first, &lcl_last, &lcl_len))
#endif // LL_WINDOWS
- {
- if (lcl_first > lcl_last || lcl_last >= lcl_len)
- return -1;
- *first = lcl_first;
- *last = lcl_last;
- *length = lcl_len;
- return 0;
- }
+ {
+ if (lcl_first > lcl_last || lcl_last >= lcl_len)
+ return -1;
+ *first = lcl_first;
+ *last = lcl_last;
+ *length = lcl_len;
+ return 0;
+ }
#if LL_WINDOWS
- if (2 == sscanf_s(tok, "%u-%u/*", &lcl_first, &lcl_last))
+ if (2 == sscanf_s(tok, "%u-%u/*", &lcl_first, &lcl_last))
#else
- if (2 == sscanf(tok, "%u-%u/*", &lcl_first, &lcl_last))
-#endif // LL_WINDOWS
- {
- if (lcl_first > lcl_last)
- return -1;
- *first = lcl_first;
- *last = lcl_last;
- *length = 0;
- return 0;
- }
- }
-
- // Header is there but badly/unexpectedly formed, try to ignore it.
- return 1;
+ if (2 == sscanf(tok, "%u-%u/*", &lcl_first, &lcl_last))
+#endif // LL_WINDOWS
+ {
+ if (lcl_first > lcl_last)
+ return -1;
+ *first = lcl_first;
+ *last = lcl_last;
+ *length = 0;
+ return 0;
+ }
+ }
+
+ // Header is there but badly/unexpectedly formed, try to ignore it.
+ return 1;
}
int parse_retry_after_header(char * buffer, int * time)
{
- char * endptr(buffer);
- long lcl_time(strtol(buffer, &endptr, 10));
- if (*endptr == '\0' && endptr != buffer && lcl_time > 0)
- {
- *time = lcl_time;
- return 0;
- }
-
- // Could attempt to parse HTTP time here but we're not really
- // interested in it. Scheduling based on wallclock time on
- // user hardware will lead to tears.
-
- // Header is there but badly/unexpectedly formed, try to ignore it.
- return 1;
+ char * endptr(buffer);
+ long lcl_time(strtol(buffer, &endptr, 10));
+ if (*endptr == '\0' && endptr != buffer && lcl_time > 0)
+ {
+ *time = lcl_time;
+ return 0;
+ }
+
+ // Could attempt to parse HTTP time here but we're not really
+ // interested in it. Scheduling based on wallclock time on
+ // user hardware will lead to tears.
+
+ // Header is there but badly/unexpectedly formed, try to ignore it.
+ return 1;
}
void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, std::string & safe_line)
{
- std::string out;
- len = (std::min)(len, size_t(200));
- out.reserve(3 * len);
- for (int i(0); i < len; ++i)
- {
- unsigned char uc(static_cast<unsigned char>(buffer[i]));
-
- if (uc < 32 || uc > 126)
- {
- if (scrub)
- {
- out.append(1, ' ');
- }
- else
- {
- static const char hex[] = "0123456789ABCDEF";
- char convert[4];
-
- convert[0] = '%';
- convert[1] = hex[(uc >> 4) % 16];
- convert[2] = hex[uc % 16];
- convert[3] = '\0';
- out.append(convert);
- }
- }
- else
- {
- out.append(1, buffer[i]);
- }
- }
- safe_line.swap(out);
+ std::string out;
+ len = (std::min)(len, size_t(200));
+ out.reserve(3 * len);
+ for (int i(0); i < len; ++i)
+ {
+ unsigned char uc(static_cast<unsigned char>(buffer[i]));
+
+ if (uc < 32 || uc > 126)
+ {
+ if (scrub)
+ {
+ out.append(1, ' ');
+ }
+ else
+ {
+ static const char hex[] = "0123456789ABCDEF";
+ char convert[4];
+
+ convert[0] = '%';
+ convert[1] = hex[(uc >> 4) % 16];
+ convert[2] = hex[uc % 16];
+ convert[3] = '\0';
+ out.append(convert);
+ }
+ }
+ else
+ {
+ out.append(1, buffer[i]);
+ }
+ }
+ safe_line.swap(out);
}
@@ -1280,9 +1280,9 @@ void escape_libcurl_debug_data(char * buffer, size_t len, bool scrub, std::strin
int os_strcasecmp(const char *s1, const char *s2)
{
#if LL_WINDOWS
- return _stricmp(s1, s2);
+ return _stricmp(s1, s2);
#else
- return strcasecmp(s1, s2);
+ return strcasecmp(s1, s2);
#endif // LL_WINDOWS
}
@@ -1290,66 +1290,66 @@ int os_strcasecmp(const char *s1, const char *s2)
char * os_strtok_r(char *str, const char *delim, char ** savestate)
{
#if LL_WINDOWS
- return strtok_s(str, delim, savestate);
+ return strtok_s(str, delim, savestate);
#else
- return strtok_r(str, delim, savestate);
+ return strtok_r(str, delim, savestate);
#endif
}
void os_strlower(char * str)
{
- for (char c(0); (c = *str); ++str)
- {
- *str = tolower(c);
- }
+ for (char c(0); (c = *str); ++str)
+ {
+ *str = tolower(c);
+ }
}
char * os_strtrim(char * lstr)
{
- while (' ' == *lstr || '\t' == *lstr)
- {
- ++lstr;
- }
- if (*lstr)
- {
- char * rstr(lstr + strlen(lstr));
- while (lstr < rstr && *--rstr)
- {
- if (' ' == *rstr || '\t' == *rstr)
- {
- *rstr = '\0';
- }
- }
- llassert(lstr <= rstr);
- }
- return lstr;
+ while (' ' == *lstr || '\t' == *lstr)
+ {
+ ++lstr;
+ }
+ if (*lstr)
+ {
+ char * rstr(lstr + strlen(lstr));
+ while (lstr < rstr && *--rstr)
+ {
+ if (' ' == *rstr || '\t' == *rstr)
+ {
+ *rstr = '\0';
+ }
+ }
+ llassert(lstr <= rstr);
+ }
+ return lstr;
}
char * os_strltrim(char * lstr)
{
- while (' ' == *lstr || '\t' == *lstr)
- {
- ++lstr;
- }
- return lstr;
+ while (' ' == *lstr || '\t' == *lstr)
+ {
+ ++lstr;
+ }
+ return lstr;
}
void check_curl_easy_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(LOG_CORE) << "libcurl error detected: " << curl_easy_strerror(code)
- << ", curl_easy_setopt option: " << curl_setopt_option
- << LL_ENDL;
- }
+ 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(LOG_CORE) << "libcurl error detected: " << curl_easy_strerror(code)
+ << ", curl_easy_setopt option: " << curl_setopt_option
+ << LL_ENDL;
+ }
}
} // end anonymous namespace