1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

CURLOPT_PIPEWAIT: added

By setting this option to 1 libcurl will wait for a connection to reveal
if it is possible to pipeline/multiplex on before it continues.
This commit is contained in:
Daniel Stenberg 2015-05-12 14:18:46 +02:00
parent df3a970cb4
commit 811443754a
5 changed files with 106 additions and 16 deletions

View File

@ -0,0 +1,63 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
.\" * are also available at http://curl.haxx.se/docs/copyright.html.
.\" *
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\" * copies of the Software, and permit persons to whom the Software is
.\" * furnished to do so, under the terms of the COPYING file.
.\" *
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\" * KIND, either express or implied.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_PIPEWAIT 3 "12 May 2015" "libcurl 7.43.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_PIPEWAIT \- wait for pipelining/multiplexing
.SH SYNOPSIS
#include <curl/curl.h>
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PIPEWAIT, long wait);
.SH DESCRIPTION
Set \fIwait\fP to 1L to tell libcurl to prefer to wait for a connection to
confirm or deny that it can do pipelining or multiplexing before continuing.
When about to perform a new transfer that allows pipelining or multiplexing,
libcurl will check for existing connections to re-use and pipeline on. If no
such connection exists it will immediately continue and create a fresh new
connection to use.
By setting this option to 1 - and having \fICURLMOPT_PIPELINE\fP enabled for
the multi handle this transfer is associated with - libcurl will instead wait
for the connection to reveal if it is possible to pipeline/multiplex on before
it continues. This enables libcurl to much better keep the number of
connections to a minimum when using pipelining or multiplexing protocols.
The effect thus becomes that with this option set, libcurl prefers to wait and
re-use an existing connection for pipelining rather than the opposite: prefer
to open a new connection rather than waiting.
The waiting time is as long as it takes for the connection to get up and for
libcurl to get the necessary response back that informs it about its protocol
and support level.
.SH DEFAULT
0 (off)
.SH PROTOCOLS
HTTP(S)
.SH EXAMPLE
.SH AVAILABILITY
Added in 7.43.0
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
.BR CURLOPT_FORBID_REUSE "(3), " CURLOPT_FRESH_CONNECT "(3), "
.BR CURLMOPT_PIPELINING "(3), " CURLMOPT_MAX_HOST_CONNECTIONS "(3), "

View File

@ -114,7 +114,7 @@ man_MANS = CURLOPT_ACCEPT_ENCODING.3 CURLOPT_ACCEPTTIMEOUT_MS.3 \
CURLMOPT_SOCKETDATA.3 CURLMOPT_SOCKETFUNCTION.3 CURLMOPT_TIMERDATA.3 \ CURLMOPT_SOCKETDATA.3 CURLMOPT_SOCKETFUNCTION.3 CURLMOPT_TIMERDATA.3 \
CURLMOPT_TIMERFUNCTION.3 CURLOPT_UNIX_SOCKET_PATH.3 \ CURLMOPT_TIMERFUNCTION.3 CURLOPT_UNIX_SOCKET_PATH.3 \
CURLOPT_PATH_AS_IS.3 CURLOPT_PROXY_SERVICE_NAME.3 \ CURLOPT_PATH_AS_IS.3 CURLOPT_PROXY_SERVICE_NAME.3 \
CURLOPT_SERVICE_NAME.3 CURLOPT_SERVICE_NAME.3 CURLOPT_PIPEWAIT.3
HTMLPAGES = CURLOPT_ACCEPT_ENCODING.html CURLOPT_ACCEPTTIMEOUT_MS.html \ HTMLPAGES = CURLOPT_ACCEPT_ENCODING.html CURLOPT_ACCEPTTIMEOUT_MS.html \
CURLOPT_ADDRESS_SCOPE.html CURLOPT_APPEND.html \ CURLOPT_ADDRESS_SCOPE.html CURLOPT_APPEND.html \
@ -221,7 +221,8 @@ HTMLPAGES = CURLOPT_ACCEPT_ENCODING.html CURLOPT_ACCEPTTIMEOUT_MS.html \
CURLMOPT_SOCKETDATA.html CURLMOPT_SOCKETFUNCTION.html \ CURLMOPT_SOCKETDATA.html CURLMOPT_SOCKETFUNCTION.html \
CURLMOPT_TIMERDATA.html CURLMOPT_TIMERFUNCTION.html \ CURLMOPT_TIMERDATA.html CURLMOPT_TIMERFUNCTION.html \
CURLOPT_UNIX_SOCKET_PATH.html CURLOPT_PATH_AS_IS.html \ CURLOPT_UNIX_SOCKET_PATH.html CURLOPT_PATH_AS_IS.html \
CURLOPT_PROXY_SERVICE_NAME.html CURLOPT_SERVICE_NAME.html CURLOPT_PROXY_SERVICE_NAME.html CURLOPT_SERVICE_NAME.html \
CURLOPT_PIPEWAIT.html
PDFPAGES = CURLOPT_ACCEPT_ENCODING.pdf CURLOPT_ACCEPTTIMEOUT_MS.pdf \ PDFPAGES = CURLOPT_ACCEPT_ENCODING.pdf CURLOPT_ACCEPTTIMEOUT_MS.pdf \
CURLOPT_ADDRESS_SCOPE.pdf CURLOPT_APPEND.pdf CURLOPT_AUTOREFERER.pdf \ CURLOPT_ADDRESS_SCOPE.pdf CURLOPT_APPEND.pdf CURLOPT_AUTOREFERER.pdf \
@ -326,7 +327,8 @@ PDFPAGES = CURLOPT_ACCEPT_ENCODING.pdf CURLOPT_ACCEPTTIMEOUT_MS.pdf \
CURLMOPT_SOCKETDATA.pdf CURLMOPT_SOCKETFUNCTION.pdf \ CURLMOPT_SOCKETDATA.pdf CURLMOPT_SOCKETFUNCTION.pdf \
CURLMOPT_TIMERDATA.pdf CURLMOPT_TIMERFUNCTION.pdf \ CURLMOPT_TIMERDATA.pdf CURLMOPT_TIMERFUNCTION.pdf \
CURLOPT_UNIX_SOCKET_PATH.pdf CURLOPT_PATH_AS_IS.pdf \ CURLOPT_UNIX_SOCKET_PATH.pdf CURLOPT_PATH_AS_IS.pdf \
CURLOPT_PROXY_SERVICE_NAME.pdf CURLOPT_SERVICE_NAME.pdf CURLOPT_PROXY_SERVICE_NAME.pdf CURLOPT_SERVICE_NAME.pdf \
CURLOPT_PIPEWAIT.pdf
CLEANFILES = $(HTMLPAGES) $(PDFPAGES) CLEANFILES = $(HTMLPAGES) $(PDFPAGES)

View File

@ -1638,6 +1638,9 @@ typedef enum {
/* Service Name */ /* Service Name */
CINIT(SERVICE_NAME, OBJECTPOINT, 236), CINIT(SERVICE_NAME, OBJECTPOINT, 236),
/* Wait/don't wait for pipe/mutex to clarify */
CINIT(PIPEWAIT, LONG, 237),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -2649,6 +2649,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
case CURLOPT_PATH_AS_IS: case CURLOPT_PATH_AS_IS:
data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE; data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE;
break; break;
case CURLOPT_PIPEWAIT:
data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE;
break;
default: default:
/* unknown tag and its companion, just ignore: */ /* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION; result = CURLE_UNKNOWN_OPTION;
@ -3099,7 +3102,8 @@ static bool
ConnectionExists(struct SessionHandle *data, ConnectionExists(struct SessionHandle *data,
struct connectdata *needle, struct connectdata *needle,
struct connectdata **usethis, struct connectdata **usethis,
bool *force_reuse) bool *force_reuse,
bool *waitpipe)
{ {
struct connectdata *check; struct connectdata *check;
struct connectdata *chosen = 0; struct connectdata *chosen = 0;
@ -3112,6 +3116,7 @@ ConnectionExists(struct SessionHandle *data,
struct connectbundle *bundle; struct connectbundle *bundle;
*force_reuse = FALSE; *force_reuse = FALSE;
*waitpipe = FALSE;
/* We can't pipe if the site is blacklisted */ /* We can't pipe if the site is blacklisted */
if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) { if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) {
@ -3132,10 +3137,18 @@ ConnectionExists(struct SessionHandle *data,
needle->host.name, (void *)bundle); needle->host.name, (void *)bundle);
/* We can't pipe if we don't know anything about the server */ /* We can't pipe if we don't know anything about the server */
if(canPipeline && (bundle->multiuse <= BUNDLE_UNKNOWN)) { if(canPipeline) {
if(bundle->multiuse <= BUNDLE_UNKNOWN) {
if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
infof(data, "Server doesn't support multi-use yet, wait\n");
*waitpipe = TRUE;
return FALSE; /* no re-use */
}
infof(data, "Server doesn't support multi-use (yet)\n"); infof(data, "Server doesn't support multi-use (yet)\n");
canPipeline = FALSE; canPipeline = FALSE;
} }
}
curr = bundle->conn_list->head; curr = bundle->conn_list->head;
while(curr) { while(curr) {
@ -5343,8 +5356,9 @@ static CURLcode create_conn(struct SessionHandle *data,
bool reuse; bool reuse;
char *proxy = NULL; char *proxy = NULL;
bool prot_missing = FALSE; bool prot_missing = FALSE;
bool no_connections_available = FALSE; bool connections_available = TRUE;
bool force_reuse = FALSE; bool force_reuse = FALSE;
bool waitpipe = FALSE;
size_t max_host_connections = Curl_multi_max_host_connections(data->multi); size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
size_t max_total_connections = Curl_multi_max_total_connections(data->multi); size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
@ -5684,7 +5698,7 @@ static CURLcode create_conn(struct SessionHandle *data,
if(data->set.reuse_fresh && !data->state.this_is_a_follow) if(data->set.reuse_fresh && !data->state.this_is_a_follow)
reuse = FALSE; reuse = FALSE;
else else
reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse); reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
/* If we found a reusable connection, we may still want to /* If we found a reusable connection, we may still want to
open a new connection if we are pipelining. */ open a new connection if we are pipelining. */
@ -5730,9 +5744,15 @@ static CURLcode create_conn(struct SessionHandle *data,
/* We have decided that we want a new connection. However, we may not /* We have decided that we want a new connection. However, we may not
be able to do that if we have reached the limit of how many be able to do that if we have reached the limit of how many
connections we are allowed to open. */ connections we are allowed to open. */
struct connectbundle *bundle; struct connectbundle *bundle = NULL;
if(waitpipe)
/* There is a connection that *might* become usable for pipelining
"soon", and we wait for that */
connections_available = FALSE;
else
bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
if(max_host_connections > 0 && bundle && if(max_host_connections > 0 && bundle &&
(bundle->num_connections >= max_host_connections)) { (bundle->num_connections >= max_host_connections)) {
struct connectdata *conn_candidate; struct connectdata *conn_candidate;
@ -5748,11 +5768,12 @@ static CURLcode create_conn(struct SessionHandle *data,
else { else {
infof(data, "No more connections allowed to host: %d\n", infof(data, "No more connections allowed to host: %d\n",
max_host_connections); max_host_connections);
no_connections_available = TRUE; connections_available = FALSE;
} }
} }
if(max_total_connections > 0 && if(connections_available &&
(max_total_connections > 0) &&
(data->state.conn_cache->num_connections >= max_total_connections)) { (data->state.conn_cache->num_connections >= max_total_connections)) {
struct connectdata *conn_candidate; struct connectdata *conn_candidate;
@ -5766,12 +5787,11 @@ static CURLcode create_conn(struct SessionHandle *data,
} }
else { else {
infof(data, "No connections available in cache\n"); infof(data, "No connections available in cache\n");
no_connections_available = TRUE; connections_available = FALSE;
} }
} }
if(!connections_available) {
if(no_connections_available) {
infof(data, "No connections available.\n"); infof(data, "No connections available.\n");
conn_free(conn); conn_free(conn);

View File

@ -1623,6 +1623,8 @@ struct UserDefined {
bool ssl_enable_npn; /* TLS NPN extension? */ bool ssl_enable_npn; /* TLS NPN extension? */
bool ssl_enable_alpn; /* TLS ALPN extension? */ bool ssl_enable_alpn; /* TLS ALPN extension? */
bool path_as_is; /* allow dotdots? */ bool path_as_is; /* allow dotdots? */
bool pipewait; /* wait for pipe/multiplex status before starting a
new connection */
long expect_100_timeout; /* in milliseconds */ long expect_100_timeout; /* in milliseconds */
}; };