]> granicus.if.org Git - curl/commitdiff
CURLOPT_PIPEWAIT: added
authorDaniel Stenberg <daniel@haxx.se>
Tue, 12 May 2015 12:18:46 +0000 (14:18 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 18 May 2015 07:33:47 +0000 (09:33 +0200)
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.

docs/libcurl/opts/CURLOPT_PIPEWAIT.3 [new file with mode: 0644]
docs/libcurl/opts/Makefile.am
include/curl/curl.h
lib/url.c
lib/urldata.h

diff --git a/docs/libcurl/opts/CURLOPT_PIPEWAIT.3 b/docs/libcurl/opts/CURLOPT_PIPEWAIT.3
new file mode 100644 (file)
index 0000000..5f64195
--- /dev/null
@@ -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), "
index 92d2e5fef536e8bfbde8312d951fd52188abfca9..5517811d09acff63395096880c32190329782486 100644 (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_TIMERFUNCTION.3 CURLOPT_UNIX_SOCKET_PATH.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 \
  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_TIMERDATA.html CURLMOPT_TIMERFUNCTION.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    \
  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_TIMERDATA.pdf CURLMOPT_TIMERFUNCTION.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)
 
index 9ef753140e3aeb0dac12939dae9e670350ef6e84..727f19a4f8973bbd28cf6fa5191480b152514e76 100644 (file)
@@ -1638,6 +1638,9 @@ typedef enum {
   /* Service Name */
   CINIT(SERVICE_NAME, OBJECTPOINT, 236),
 
+  /* Wait/don't wait for pipe/mutex to clarify */
+  CINIT(PIPEWAIT, LONG, 237),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index a38062aed8180a25ce751e84d72bf4280498e3b6..a07aaa83743945599a9408c3489a1683a1db417b 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2649,6 +2649,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
   case CURLOPT_PATH_AS_IS:
     data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE;
     break;
+  case CURLOPT_PIPEWAIT:
+    data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE;
+    break;
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_UNKNOWN_OPTION;
@@ -3099,7 +3102,8 @@ static bool
 ConnectionExists(struct SessionHandle *data,
                  struct connectdata *needle,
                  struct connectdata **usethis,
-                 bool *force_reuse)
+                 bool *force_reuse,
+                 bool *waitpipe)
 {
   struct connectdata *check;
   struct connectdata *chosen = 0;
@@ -3112,6 +3116,7 @@ ConnectionExists(struct SessionHandle *data,
   struct connectbundle *bundle;
 
   *force_reuse = FALSE;
+  *waitpipe = FALSE;
 
   /* We can't pipe if the site is blacklisted */
   if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) {
@@ -3132,9 +3137,17 @@ ConnectionExists(struct SessionHandle *data,
           needle->host.name, (void *)bundle);
 
     /* We can't pipe if we don't know anything about the server */
-    if(canPipeline && (bundle->multiuse <= BUNDLE_UNKNOWN)) {
-      infof(data, "Server doesn't support multi-use (yet)\n");
-      canPipeline = FALSE;
+    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");
+        canPipeline = FALSE;
+      }
     }
 
     curr = bundle->conn_list->head;
@@ -5343,8 +5356,9 @@ static CURLcode create_conn(struct SessionHandle *data,
   bool reuse;
   char *proxy = NULL;
   bool prot_missing = FALSE;
-  bool no_connections_available = FALSE;
+  bool connections_available = TRUE;
   bool force_reuse = FALSE;
+  bool waitpipe = FALSE;
   size_t max_host_connections = Curl_multi_max_host_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)
     reuse = FALSE;
   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
      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
        be able to do that if we have reached the limit of how many
        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 &&
        (bundle->num_connections >= max_host_connections)) {
       struct connectdata *conn_candidate;
@@ -5748,11 +5768,12 @@ static CURLcode create_conn(struct SessionHandle *data,
       else {
         infof(data, "No more connections allowed to host: %d\n",
               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)) {
       struct connectdata *conn_candidate;
 
@@ -5766,12 +5787,11 @@ static CURLcode create_conn(struct SessionHandle *data,
       }
       else {
         infof(data, "No connections available in cache\n");
-        no_connections_available = TRUE;
+        connections_available = FALSE;
       }
     }
 
-
-    if(no_connections_available) {
+    if(!connections_available) {
       infof(data, "No connections available.\n");
 
       conn_free(conn);
index 94b6aece2a5570f4b6debdb29513be6dd82bb4e4..2484f47b04f2ca0b56ae67974ac9c924358fb367 100644 (file)
@@ -1623,6 +1623,8 @@ struct UserDefined {
   bool ssl_enable_npn;  /* TLS NPN extension? */
   bool ssl_enable_alpn; /* TLS ALPN extension? */
   bool path_as_is;      /* allow dotdots? */
+  bool pipewait;        /* wait for pipe/multiplex status before starting a
+                           new connection */
   long expect_100_timeout; /* in milliseconds */
 };