diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING.3 b/docs/libcurl/opts/CURLMOPT_PIPELINING.3 index c1df1d560352c6..c795c48ecc2464 100644 --- a/docs/libcurl/opts/CURLMOPT_PIPELINING.3 +++ b/docs/libcurl/opts/CURLMOPT_PIPELINING.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -26,17 +26,28 @@ CURLMOPT_PIPELINING \- enable/disable HTTP pipelining .SH SYNOPSIS #include -CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING, bool onoff); +CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING, long bits); .SH DESCRIPTION -Set the \fBonoff\fP parameter to 1 to make libcurl use HTTP pipelining for -HTTP transfers done using this multi handle, as far as possible. This means -that if you add a second request that can use an already existing connection, -the second request will be \&"piped" on the same connection rather than being -executed in parallel. +Set the \fBbits\fP parameter to 1 to make libcurl use HTTP pipelining for +HTTP/1.1 transfers done using this multi handle, as far as possible. This +means that if you add a second request that can use an already existing +connection, the second request will be \&"piped" on the same connection rather +than being executed in parallel. When using pipelining, there are also several other related options that are interesting to tweak and adjust to alter how libcurl spreads out requests on different connections or not etc. + +Starting in 7.43.0, the \fBbits\fP parameter's bit 1 also has a meaning and +libcurl is now offering symbol names for the bits: +.IP CURLPIPE_NOTHING (0) +Default, which means doing no attempts at pipelining or multiplexing. +.IP CURLPIPE_HTTP1 (1) +If this bit is set, libcurl will try to pipeline HTTP/1.1 requests on +connections that are already established and in use to hosts. +.IP CURLPIPE_MULTIPLEX (2) +If this bit is set, libcurl will try to multiplex the new transfer over an +existing connection if possible. This requires HTTP/2. .SH DEFAULT 0 (off) .SH PROTOCOLS @@ -44,7 +55,7 @@ HTTP(S) .SH EXAMPLE TODO .SH AVAILABILITY -Added in 7.16.0 +Added in 7.16.0. Multiplex support bit added in 7.43.0. .SH RETURN VALUE Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not. .SH "SEE ALSO" diff --git a/include/curl/multi.h b/include/curl/multi.h index 3c4acb0f6eafde..0d859f8fd98c50 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -74,6 +74,11 @@ typedef enum { curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + typedef enum { CURLMSG_NONE, /* first, not used */ CURLMSG_DONE, /* This easy handle has completed. 'result' contains diff --git a/lib/multi.c b/lib/multi.c index 5595bbd1f82d3b..5573151a8b5ce0 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -613,9 +613,10 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, return CURLM_OK; } -bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi) +/* Return TRUE if the application asked for a certain set of pipelining */ +bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits) { - return (multi && multi->pipelining_enabled) ? TRUE : FALSE; + return (multi && (multi->pipelining & bits)) ? TRUE : FALSE; } void Curl_multi_handlePipeBreak(struct SessionHandle *data) @@ -1082,7 +1083,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP @@ -1139,7 +1140,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* call again please so that we get the next socket setup */ rc = CURLM_CALL_MULTI_PERFORM; if(protocol_connect) - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); else { #ifndef CURL_DISABLE_HTTP @@ -1203,7 +1204,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_PROTOCONNECT); else if(!result) { /* protocol connect has completed, go WAITDO or DO */ - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); rc = CURLM_CALL_MULTI_PERFORM; } @@ -1220,7 +1221,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = Curl_protocol_connecting(data->easy_conn, &protocol_connect); if(!result && protocol_connect) { /* after the connect has completed, go WAITDO or DO */ - multistate(data, multi->pipelining_enabled? + multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)? CURLM_STATE_WAITDO:CURLM_STATE_DO); rc = CURLM_CALL_MULTI_PERFORM; } @@ -2340,7 +2341,7 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, multi->socket_userp = va_arg(param, void *); break; case CURLMOPT_PIPELINING: - multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE; + multi->pipelining = va_arg(param, long); break; case CURLMOPT_TIMERFUNCTION: multi->timer_cb = va_arg(param, curl_multi_timer_callback); diff --git a/lib/multihandle.h b/lib/multihandle.h index 640e3fb4b945c3..13b32d8fe4aa24 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -62,6 +62,8 @@ typedef enum { #define GETSOCK_READABLE (0x00ff) #define GETSOCK_WRITABLE (0xff00) +#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX) + /* This is the struct known as CURLM on the outside */ struct Curl_multi { /* First a simple identifier to easier detect if a user mix up @@ -97,8 +99,8 @@ struct Curl_multi { same actual socket) */ struct curl_hash sockhash; - /* Whether pipelining is enabled for this multi handle */ - bool pipelining_enabled; + /* pipelining wanted bits (CURLPIPE*) */ + long pipelining; /* Shared connection cache (bundles)*/ struct conncache conn_cache; diff --git a/lib/multiif.h b/lib/multiif.h index d8acfcabe7ce79..152cb8be21819d 100644 --- a/lib/multiif.h +++ b/lib/multiif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,8 +27,7 @@ */ void Curl_expire(struct SessionHandle *data, long milli); void Curl_expire_latest(struct SessionHandle *data, long milli); - -bool Curl_multi_pipeline_enabled(const struct Curl_multi* multi); +bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); void Curl_multi_handlePipeBreak(struct SessionHandle *data); /* Internal version of curl_multi_init() accepts size parameters for the diff --git a/lib/sendf.c b/lib/sendf.c index 71b2d6030cb564..5f39d1f2d4268f 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -551,8 +551,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; - bool pipelining = Curl_multi_pipeline_enabled(conn->data->multi) && - !conn->bits.multiplex; + bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1); /* Set 'num' to 0 or 1, depending on which socket that has been sent here. If it is the second socket, we set num to 1. Otherwise to 0. This lets diff --git a/lib/transfer.c b/lib/transfer.c index 8ac91664c52e1f..59e6acb4d6084d 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -494,7 +494,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, /* We've stopped dealing with input, get out of the do-while loop */ if(nread > 0) { - if(Curl_multi_pipeline_enabled(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { infof(data, "Rewinding stream by : %zd" " bytes on url %s (zero-length body)\n", @@ -639,7 +639,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(dataleft != 0) { infof(conn->data, "Leftovers after chunking: %zu bytes\n", dataleft); - if(Curl_multi_pipeline_enabled(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { /* only attempt the rewind if we truly are pipelining */ infof(conn->data, "Rewinding %zu bytes\n",dataleft); read_rewind(conn, dataleft); @@ -662,7 +662,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, excess = (size_t)(k->bytecount + nread - k->maxdownload); if(excess > 0 && !k->ignorebody) { - if(Curl_multi_pipeline_enabled(conn->data->multi)) { + if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) { /* The 'excess' amount below can't be more than BUFSIZE which always will fit in a size_t */ infof(data, diff --git a/lib/url.c b/lib/url.c index bdda991c80de0e..805459c82bdfff 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2782,7 +2782,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) Curl_ssl_close(conn, FIRSTSOCKET); /* Indicate to all handles on the pipe that we're dead */ - if(Curl_multi_pipeline_enabled(data->multi)) { + if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) { signalPipeClose(conn->send_pipe, TRUE); signalPipeClose(conn->recv_pipe, TRUE); } @@ -2815,7 +2815,7 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle, { /* If a HTTP protocol and pipelining is enabled */ if((conn->handler->protocol & PROTO_FAMILY_HTTP) && - Curl_multi_pipeline_enabled(handle->multi)) { + Curl_pipeline_wanted(handle->multi, CURLPIPE_ANY)) { if((handle->set.httpversion != CURL_HTTP_VERSION_1_0) && (handle->set.httpreq == HTTPREQ_GET || @@ -2830,11 +2830,6 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle, return FALSE; } -bool Curl_isPipeliningEnabled(const struct SessionHandle *handle) -{ - return Curl_multi_pipeline_enabled(handle->multi); -} - int Curl_removeHandleFromPipeline(struct SessionHandle *handle, struct curl_llist *pipeline) { @@ -3786,9 +3781,9 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->response_header = NULL; #endif - if(Curl_multi_pipeline_enabled(data->multi) && - !conn->master_buffer) { - /* Allocate master_buffer to be used for pipelining */ + if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) && + !conn->master_buffer) { + /* Allocate master_buffer to be used for HTTP/1 pipelining */ conn->master_buffer = calloc(BUFSIZE, sizeof (char)); if(!conn->master_buffer) goto error;