=== modified file 'doc/release-notes/release-3.4.sgml'
--- doc/release-notes/release-3.4.sgml	2013-05-14 17:54:30 +0000
+++ doc/release-notes/release-3.4.sgml	2013-05-16 03:38:06 +0000
@@ -179,6 +179,9 @@
 	<p>New format code <em>%note</em> to log a transaction annotation linked to the
 	   transaction by ICAP, eCAP, a helper, or the <em>note</em> squid.conf directive.
 
+	<tag>pipeline_prefetch</tag>
+	<p>Updated to take a numeric count of prefetched pipeline requests instead of ON/OFF.
+
 	<tag>unlinkd_program</tag>
 	<p>New helper response format utilizing result codes <em>OK</em> and <em>BH</em>,
 	   to signal helper lookup results. Also, key-value response values to return

=== modified file 'src/Parsing.cc'
--- src/Parsing.cc	2013-05-04 13:14:23 +0000
+++ src/Parsing.cc	2013-05-16 13:55:49 +0000
@@ -33,6 +33,7 @@
 #include "squid.h"
 #include "cache_cf.h"
 #include "compat/strtoll.h"
+#include "ConfigParser.h"
 #include "Parsing.h"
 #include "globals.h"
 #include "Debug.h"
@@ -161,7 +162,7 @@
 int
 GetInteger(void)
 {
-    char *token = strtok(NULL, w_space);
+    char *token = ConfigParser::strtokFile();
     int i;
 
     if (token == NULL)

=== modified file 'src/SquidConfig.h'
--- src/SquidConfig.h	2013-05-13 03:57:03 +0000
+++ src/SquidConfig.h	2013-05-16 03:21:38 +0000
@@ -332,7 +332,6 @@
 
         int ie_refresh;
         int vary_ignore_expire;
-        int pipeline_prefetch;
         int surrogate_is_remote;
         int request_entities;
         int detect_broken_server_pconns;
@@ -361,6 +360,8 @@
         int client_dst_passthru;
     } onoff;
 
+    int pipeline_max_prefetch;
+
     int forward_max_tries;
     int connect_retries;
 

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2013-05-14 18:36:45 +0000
+++ src/cache_cf.cc	2013-05-22 12:17:28 +0000
@@ -965,6 +965,16 @@
                (uint32_t)Config.maxRequestBufferSize, (uint32_t)Config.maxRequestHeaderSize);
     }
 
+    /*
+     * Disable client side request pipelining if client_persistent_connections OFF.
+     * Waste of resources queueing any pipelined requests when the first will close the connection.
+     */
+    if (Config.pipeline_max_prefetch > 0 && !Config.onoff.client_pconns) {
+        debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch " << Config.pipeline_max_prefetch <<
+                   " requires client_persistent_connections ON. Forced pipeline_prefetch 0.");
+        Config.pipeline_max_prefetch = 0;
+    }
+
 #if USE_AUTH
     /*
      * disable client side request pipelining. There is a race with
@@ -973,12 +983,12 @@
      * pipelining OFF, the client may fail to authenticate, but squid's
      * state will be preserved.
      */
-    if (Config.onoff.pipeline_prefetch) {
+    if (Config.pipeline_max_prefetch > 0) {
         Auth::Config *nego = Auth::Config::Find("Negotiate");
         Auth::Config *ntlm = Auth::Config::Find("NTLM");
         if ((nego && nego->active()) || (ntlm && ntlm->active())) {
-            debugs(3, DBG_IMPORTANT, "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced OFF.");
-            Config.onoff.pipeline_prefetch = 0;
+            debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced pipeline_prefetch 0.");
+            Config.pipeline_max_prefetch = 0;
         }
     }
 #endif
@@ -2691,6 +2701,29 @@
 
 #define free_tristate free_int
 
+void
+parse_pipelinePrefetch(int *var)
+{
+    char *token = ConfigParser::strtokFile();
+
+    if (token == NULL)
+        self_destruct();
+
+    if (!strcmp(token, "on")) {
+        debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'pipeline_prefetch on' is deprecated. Please update to use 1 (or a higher number).");
+        *var = 1;
+    } else if (!strcmp(token, "off")) {
+        debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'.");
+        *var = 0;
+    } else {
+        ConfigParser::strtokFileUndo();
+        parse_int(var);
+    }
+}
+
+#define free_pipelinePrefetch free_int
+#define dump_pipelinePrefetch dump_int
+
 static void
 dump_refreshpattern(StoreEntry * entry, const char *name, RefreshPattern * head)
 {

=== modified file 'src/cf.data.depend'
--- src/cf.data.depend	2013-05-12 05:04:14 +0000
+++ src/cf.data.depend	2013-05-16 04:00:13 +0000
@@ -51,6 +51,7 @@
 onoff
 peer
 peer_access		cache_peer acl
+pipelinePrefetch
 PortCfg
 QosConfig
 refreshpattern

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2013-05-14 17:53:18 +0000
+++ src/cf.data.pre	2013-05-21 02:50:03 +0000
@@ -8701,17 +8701,23 @@
 DOC_END
 
 NAME: pipeline_prefetch
-TYPE: onoff
-LOC: Config.onoff.pipeline_prefetch
-DEFAULT: off
+TYPE: pipelinePrefetch
+LOC: Config.pipeline_max_prefetch
+DEFAULT: 0
+DEFAULT_DOC: Do not pre-parse pipelined requests.
 DOC_START
-	To boost the performance of pipelined requests to closer
-	match that of a non-proxied environment Squid can try to fetch
-	up to two requests in parallel from a pipeline.
+	HTTP clients may send a pipeline of 1+N requests to Squid using a
+	single connection, without waiting for Squid to respond to the first
+	of those requests. This option limits the number of concurrent
+	requests Squid will try to handle in parallel. If set to N, Squid
+	will try to receive and process up to 1+N requests on the same
+	connection concurrently.
 
-	Defaults to off for bandwidth management and access logging
+	Defaults to 0 (off) for bandwidth management and access logging
 	reasons.
 
+	NOTE: pipelining requires persistent connections to clients.
+
 	WARNING: pipelining breaks NTLM and Negotiate/Kerberos authentication.
 DOC_END
 

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2013-05-23 08:18:09 +0000
+++ src/client_side.cc	2013-05-25 06:58:00 +0000
@@ -2946,17 +2946,23 @@
     }
 }
 
-static int
-connOkToAddRequest(ConnStateData * conn)
+bool
+ConnStateData::concurrentRequestQueueFilled() const
 {
-    int result = conn->getConcurrentRequestCount() < (Config.onoff.pipeline_prefetch ? 2 : 1);
-
-    if (!result) {
-        debugs(33, 3, HERE << conn->clientConnection << " max concurrent requests reached");
-        debugs(33, 5, HERE << conn->clientConnection << " defering new request until one is done");
+    const int existingRequestCount = getConcurrentRequestCount();
+
+    // default to the configured pipeline size.
+    // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
+    const int concurrentRequestLimit = Config.pipeline_max_prefetch + 1;
+
+    // when queue filled already we cant add more.
+    if (existingRequestCount >= concurrentRequestLimit) {
+        debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
+        debugs(33, 5, clientConnection << " defering new request until one is done");
+        return false;
     }
 
-    return result;
+    return true;
 }
 
 /**
@@ -2981,8 +2987,8 @@
         if (in.notYetUsed == 0)
             break;
 
-        /* Limit the number of concurrent requests to 2 */
-        if (!connOkToAddRequest(this)) {
+        /* Limit the number of concurrent requests */
+        if (!pipelineQueueFilled()) {
             break;
         }
 

=== modified file 'src/client_side.h'
--- src/client_side.h	2013-04-04 06:15:00 +0000
+++ src/client_side.h	2013-05-25 07:06:30 +0000
@@ -178,7 +178,7 @@
 /**
  * Manages a connection to a client.
  *
- * Multiple requests (up to 2) can be pipelined. This object is responsible for managing
+ * Multiple requests (up to pipeline_prefetch) can be pipelined. This object is responsible for managing
  * which one is currently being fulfilled and what happens to the queue if the current one
  * causes the client connection to be closed early.
  *
@@ -392,6 +392,7 @@
     int connReadWasError(comm_err_t flag, int size, int xerrno);
     int connFinishedWithConn(int size);
     void clientAfterReadingRequests();
+    bool concurrentRequestQueueFilled() const;
 
 #if USE_AUTH
     /// some user details that can be used to perform authentication on this connection


