mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -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:
parent
df3a970cb4
commit
811443754a
63
docs/libcurl/opts/CURLOPT_PIPEWAIT.3
Normal file
63
docs/libcurl/opts/CURLOPT_PIPEWAIT.3
Normal 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), "
|
@ -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)
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
46
lib/url.c
46
lib/url.c
@ -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,9 +3137,17 @@ 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) {
|
||||||
infof(data, "Server doesn't support multi-use (yet)\n");
|
if(bundle->multiuse <= BUNDLE_UNKNOWN) {
|
||||||
canPipeline = FALSE;
|
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");
|
||||||
|
canPipeline = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curr = bundle->conn_list->head;
|
curr = bundle->conn_list->head;
|
||||||
@ -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);
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user