MAINT-7081: Try requesting HTTP/2 when a request wants pipelining.

meow-7.2.2
Nat Goodspeed 2017-09-29 17:06:42 -04:00
parent ee2a1902a5
commit 586d697475
2 changed files with 74 additions and 105 deletions

View File

@ -40,6 +40,15 @@ namespace
void check_curl_multi_code(CURLMcode code);
void check_curl_multi_code(CURLMcode code, int curl_setopt_option);
// This is a template because different 'option' values require different
// types for 'ARG'. Just pass them through unchanged (by value).
template <typename ARG>
void check_curl_multi_setopt(CURLM* handle, CURLMoption option, ARG argument)
{
CURLMcode code = curl_multi_setopt(handle, option, argument);
check_curl_multi_code(code, option);
}
static const char * const LOG_CORE("CoreHttp");
} // end anonymous namespace
@ -466,41 +475,34 @@ void HttpLibcurl::policyUpdated(int policy_class)
// Enable policy if stalled
policy.stallPolicy(policy_class, false);
mDirtyPolicy[policy_class] = false;
if (options.mPipelining > 1)
{
// We'll try to do pipelining on this multihandle
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_PIPELINING,
1L);
check_curl_multi_code(code, CURLMOPT_PIPELINING);
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_MAX_PIPELINE_LENGTH,
long(options.mPipelining));
check_curl_multi_code(code, CURLMOPT_MAX_PIPELINE_LENGTH);
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_MAX_HOST_CONNECTIONS,
long(options.mPerHostConnectionLimit));
check_curl_multi_code(code, CURLMOPT_MAX_HOST_CONNECTIONS);
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_MAX_TOTAL_CONNECTIONS,
long(options.mConnectionLimit));
check_curl_multi_code(code, CURLMOPT_MAX_TOTAL_CONNECTIONS);
}
else
{
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_PIPELINING,
0L);
check_curl_multi_code(code, CURLMOPT_PIPELINING);
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_MAX_HOST_CONNECTIONS,
0L);
check_curl_multi_code(code, CURLMOPT_MAX_HOST_CONNECTIONS);
code = curl_multi_setopt(multi_handle,
check_curl_multi_setopt(multi_handle,
CURLMOPT_MAX_TOTAL_CONNECTIONS,
long(options.mConnectionLimit));
check_curl_multi_code(code, CURLMOPT_MAX_TOTAL_CONNECTIONS);
}
}
else if (! mDirtyPolicy[policy_class])

View File

@ -108,6 +108,15 @@ void os_strlower(char * str);
// Error testing and reporting for libcurl status codes
void check_curl_easy_code(CURLcode code, int curl_setopt_option);
// This is a template because different 'option' values require different
// types for 'ARG'. Just pass them through unchanged (by value).
template <typename ARG>
void check_curl_easy_setopt(CURL* handle, CURLoption option, ARG argument)
{
CURLcode code = curl_easy_setopt(handle, option, argument);
check_curl_easy_code(code, option);
}
static const char * const LOG_CORE("CoreHttp");
} // end anonymous namespace
@ -491,45 +500,28 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
return HttpStatus(HttpStatus::LLCORE, HE_BAD_ALLOC);
}
code = curl_easy_setopt(mCurlHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
check_curl_easy_code(code, CURLOPT_IPRESOLVE);
code = curl_easy_setopt(mCurlHandle, CURLOPT_NOSIGNAL, 1);
check_curl_easy_code(code, CURLOPT_NOSIGNAL);
code = curl_easy_setopt(mCurlHandle, CURLOPT_NOPROGRESS, 1);
check_curl_easy_code(code, CURLOPT_NOPROGRESS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_URL, mReqURL.c_str());
check_curl_easy_code(code, CURLOPT_URL);
code = curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, getHandle());
check_curl_easy_code(code, CURLOPT_PRIVATE);
code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
check_curl_easy_code(code, CURLOPT_ENCODING);
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, "");
code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
check_curl_easy_code(code, CURLOPT_AUTOREFERER);
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);
check_curl_easy_code(code, CURLOPT_WRITEFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, getHandle());
check_curl_easy_code(code, CURLOPT_WRITEDATA);
code = curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback);
check_curl_easy_code(code, CURLOPT_READFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, getHandle());
check_curl_easy_code(code, CURLOPT_READDATA);
code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback);
check_curl_easy_code(code, CURLOPT_SEEKFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, getHandle());
check_curl_easy_code(code, CURLOPT_SEEKDATA);
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_READDATA, getHandle());
check_curl_easy_setopt(mCurlHandle, CURLOPT_SEEKFUNCTION, seekCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SEEKDATA, getHandle());
code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
check_curl_easy_code(code, CURLOPT_COOKIEFILE);
check_curl_easy_setopt(mCurlHandle, 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, getHandle());
check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, getHandle());
mCallbackSSLVerify = gpolicy.mSslCtxCallback;
}
@ -547,16 +539,12 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
nobody = mReqOptions->getHeadersOnly() ? 1L : 0L;
}
code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
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, sslHostV);
check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
check_curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
code = curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody);
check_curl_easy_code(code, CURLOPT_NOBODY);
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,
@ -564,8 +552,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
// 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);
check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
if (gpolicy.mUseLLProxy)
{
@ -588,81 +575,66 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
{
// *TODO: This is fine for now but get fuller socks5/
// authentication thing going later....
code = curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, gpolicy.mHttpProxy.c_str());
check_curl_easy_code(code, CURLOPT_PROXY);
code = curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
check_curl_easy_code(code, CURLOPT_PROXYTYPE);
check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, gpolicy.mHttpProxy.c_str());
check_curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
}
if (gpolicy.mCAPath.size())
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, gpolicy.mCAPath.c_str());
check_curl_easy_code(code, CURLOPT_CAPATH);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CAPATH, gpolicy.mCAPath.c_str());
}
if (gpolicy.mCAFile.size())
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, gpolicy.mCAFile.c_str());
check_curl_easy_code(code, CURLOPT_CAINFO);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CAINFO, gpolicy.mCAFile.c_str());
}
switch (mReqMethod)
{
case HOR_GET:
if (nobody == 0)
code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);
check_curl_easy_code(code, CURLOPT_HTTPGET);
check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPGET, 1);
break;
case HOR_POST:
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_POST, 1);
check_curl_easy_code(code, CURLOPT_POST);
code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
check_curl_easy_code(code, CURLOPT_ENCODING);
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();
}
code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, static_cast<void *>(NULL));
check_curl_easy_code(code, CURLOPT_POSTFIELDS);
code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDSIZE, data_size);
check_curl_easy_code(code, CURLOPT_POSTFIELDSIZE);
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:
code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH");
check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "PATCH");
// fall through. The rest is the same as PUT
case HOR_PUT:
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);
check_curl_easy_code(code, CURLOPT_UPLOAD);
check_curl_easy_setopt(mCurlHandle, CURLOPT_UPLOAD, 1);
long data_size(0);
if (mReqBody)
{
data_size = mReqBody->size();
}
code = curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
check_curl_easy_code(code, CURLOPT_INFILESIZE);
check_curl_easy_setopt(mCurlHandle, CURLOPT_INFILESIZE, data_size);
mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:");
}
break;
case HOR_DELETE:
code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
case HOR_COPY:
code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "COPY");
check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "COPY");
break;
case HOR_MOVE:
code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE");
check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE");
break;
default:
@ -680,12 +652,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
// Tracing
if (mTracing >= HTTP_TRACE_CURL_HEADERS)
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1);
check_curl_easy_code(code, CURLOPT_VERBOSE);
code = curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this);
check_curl_easy_code(code, CURLOPT_DEBUGDATA);
code = curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGFUNCTION, debugCallback);
check_curl_easy_code(code, CURLOPT_DEBUGFUNCTION);
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...
@ -762,6 +731,9 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
//
// xfer_timeout *= cpolicy.mPipelining;
xfer_timeout *= 2L;
// Also try requesting HTTP/2.
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)
@ -769,10 +741,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
// xfer_timeout = 1L;
// timeout = 1L;
//}
code = curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout);
check_curl_easy_code(code, CURLOPT_TIMEOUT);
code = curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout);
check_curl_easy_code(code, CURLOPT_CONNECTTIMEOUT);
check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, xfer_timeout);
check_curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout);
// Request headers
if (mReqHeaders)
@ -780,15 +750,12 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
// Caller's headers last to override
mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders);
}
code = curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
check_curl_easy_code(code, CURLOPT_HTTPHEADER);
check_curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS | PF_USE_RETRY_AFTER))
{
code = curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback);
check_curl_easy_code(code, CURLOPT_HEADERFUNCTION);
code = curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this);
check_curl_easy_code(code, CURLOPT_HEADERDATA);
check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERFUNCTION, headerCallback);
check_curl_easy_setopt(mCurlHandle, CURLOPT_HEADERDATA, this);
}
if (status)