Hi all,

This patch fixes the bug 1632 (http://www.squid-cache.org/bugs/show_bug.cgi?id=1632) It is based on the original squid2.5 connection pinning patch developed by Henrik (http://devel.squid-cache.org/projects.html#pinning) and the related squid 2.6 connection pinning code.

Although I spend many hours looking on pined connections I am still not absolutely sure that does not have bugs. However the code is very similar with this in squid2.6 (where the pinning code runs for years) and I hope will be easy to fix problems and bugs.

Regards,
    Christos
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [EMAIL PROTECTED]
#   2khd7117cp125tnf
# target_branch: file:///home/projects/squid/squid3-bzr/squid-\
#   repo/trunk/
# testament_sha1: c79755cca30b877e873083896f61ad63a641ae88
# timestamp: 2008-09-20 20:27:37 +0300
# base_revision_id: [EMAIL PROTECTED]
#   h7e6i88s7t5lieme
# 
# Begin patch
=== modified file 'src/HttpHeader.cc'
--- src/HttpHeader.cc	2008-07-13 08:37:43 +0000
+++ src/HttpHeader.cc	2008-07-17 18:33:07 +0000
@@ -112,6 +112,7 @@
         {"Proxy-Authentication-Info", HDR_PROXY_AUTHENTICATION_INFO, ftStr},
         {"Proxy-Authorization", HDR_PROXY_AUTHORIZATION, ftStr},
         {"Proxy-Connection", HDR_PROXY_CONNECTION, ftStr},
+	{"Proxy-support", HDR_PROXY_SUPPORT, ftStr},
         {"Public", HDR_PUBLIC, ftStr},
         {"Range", HDR_RANGE, ftPRange},
         {"Referer", HDR_REFERER, ftStr},
@@ -172,6 +173,7 @@
         HDR_IF_MATCH, HDR_IF_NONE_MATCH,
         HDR_LINK, HDR_PRAGMA,
         HDR_PROXY_CONNECTION,
+	HDR_PROXY_SUPPORT,
         HDR_TRANSFER_ENCODING,
         HDR_UPGRADE,
         HDR_VARY,

=== modified file 'src/HttpHeader.h'
--- src/HttpHeader.h	2008-07-13 08:37:43 +0000
+++ src/HttpHeader.h	2008-07-17 18:33:07 +0000
@@ -83,6 +83,7 @@
     HDR_PROXY_AUTHENTICATION_INFO,
     HDR_PROXY_AUTHORIZATION,
     HDR_PROXY_CONNECTION,
+    HDR_PROXY_SUPPORT,
     HDR_PUBLIC,
     HDR_RANGE,
     HDR_REQUEST_RANGE,		/**< some clients use this, sigh */

=== modified file 'src/HttpReply.cc'
--- src/HttpReply.cc	2008-07-02 03:49:07 +0000
+++ src/HttpReply.cc	2008-09-02 08:03:35 +0000
@@ -563,5 +563,6 @@
     rep->pstate = pstate;
     rep->protocol = protocol;
     rep->sline = sline;
+    rep->keep_alive = keep_alive;
     return rep;
 }

=== modified file 'src/HttpRequest.cc'
--- src/HttpRequest.cc	2008-06-07 05:20:05 +0000
+++ src/HttpRequest.cc	2008-06-23 18:02:37 +0000
@@ -74,6 +74,7 @@
     login[0] = '\0';
     host[0] = '\0';
     auth_user_request = NULL;
+    pinned_connection = NULL;
     port = 0;
     canonical = NULL;
     memset(&flags, '\0', sizeof(flags));
@@ -127,6 +128,10 @@
         range = NULL;
     }
 
+    if(pinned_connection)
+	cbdataReferenceDone(pinned_connection);
+    pinned_connection = NULL;
+
     tag.clean();
 
     extacl_user.clean();

=== modified file 'src/HttpRequest.h'
--- src/HttpRequest.h	2008-06-07 05:20:05 +0000
+++ src/HttpRequest.h	2008-06-23 18:02:37 +0000
@@ -148,6 +148,8 @@
 
     String extacl_log;		/* String to be used for access.log purposes */
 
+    ConnStateData *pinned_connection;
+
 #if FOLLOW_X_FORWARDED_FOR
     String x_forwarded_for_iterator; /* XXX a list of IP addresses */
 #endif /* FOLLOW_X_FORWARDED_FOR */

=== modified file 'src/ICAP/ICAPModXact.cc'
--- src/ICAP/ICAPModXact.cc	2008-09-19 17:26:31 +0000
+++ src/ICAP/ICAPModXact.cc	2008-09-20 15:15:50 +0000
@@ -786,9 +786,12 @@
         HttpRequest *newR = new HttpRequest;
         inheritVirginProperties(*newR, *oldR);
         newHead = newR;
-    } else
-    if (dynamic_cast<const HttpReply*>(oldHead))
-        newHead = new HttpReply;
+    } 
+    else if (const HttpReply *oldRep = dynamic_cast<const HttpReply*>(oldHead)) {
+	HttpReply *newRep = new HttpReply;
+	inheritVirginReplyProperties(*newRep, *oldRep);
+	newHead = newRep;
+    }
     Must(newHead);
 
     adapted.setHeader(newHead);
@@ -854,6 +857,10 @@
             // http://www.squid-cache.org/mail-archive/squid-dev/200703/0040.html
             inheritVirginProperties(*newHead, *oldR);
         }
+	else if (HttpReply *newRep = dynamic_cast<HttpReply*>(adapted.header)){
+	    HttpReply *oldRep = dynamic_cast<HttpReply*>(virgin.header);
+	    inheritVirginReplyProperties(*newRep, *oldRep);
+	}
     }
 
     decideOnParsingBody();
@@ -895,6 +902,15 @@
         newR.auth_user_request = oldR.auth_user_request;
 	AUTHUSERREQUESTLOCK(newR.auth_user_request, "newR in ICAPModXact");
     }
+
+    if(oldR.pinned_connection) {
+	newR.pinned_connection = cbdataReference(oldR.pinned_connection);
+    }
+
+}
+
+void ICAPModXact::inheritVirginReplyProperties(HttpReply &newR, const HttpReply &oldR) {
+    newR.keep_alive = oldR.keep_alive;
 }
 
 void ICAPModXact::decideOnParsingBody() {

=== modified file 'src/ICAP/ICAPModXact.h'
--- src/ICAP/ICAPModXact.h	2008-03-31 01:06:13 +0000
+++ src/ICAP/ICAPModXact.h	2008-09-02 08:12:29 +0000
@@ -209,6 +209,7 @@
     void parseHttpHead();
     bool parseHead(HttpMsg *head);
     void inheritVirginProperties(HttpRequest &newR, const HttpRequest &oldR);
+    void inheritVirginReplyProperties(HttpReply &newR, const HttpReply &oldR);
 
     void decideOnParsingBody();
     void parseBody();

=== modified file 'src/ProtoPort.h'
--- src/ProtoPort.h	2008-04-09 10:17:28 +0000
+++ src/ProtoPort.h	2008-05-18 20:15:06 +0000
@@ -26,6 +26,7 @@
     unsigned int sslBump:1;            /**< intercepts CONNECT requests */
 
     int vport;                 /* virtual port support, -1 for dynamic, >0 static*/
+    int no_connection_auth;     /* Don't support connection oriented auth */
     int disable_pmtu_discovery;
 
     struct {

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2008-08-10 05:05:45 +0000
+++ src/cache_cf.cc	2008-09-02 08:32:52 +0000
@@ -1692,6 +1692,7 @@
         self_destruct();
 
     p->icp.port = GetUdpService();
+    p->connection_auth = 2;    /* auto */
 
     while ((token = strtok(NULL, w_space))) {
         if (!strcasecmp(token, "proxy-only")) {
@@ -1829,6 +1830,14 @@
             p->front_end_https = 1;
         } else if (strcmp(token, "front-end-https=auto") == 0) {
             p->front_end_https = 2;
+        }else if (strcmp(token, "connection-auth=off") == 0) {
+            p->connection_auth = 0;
+        } else if (strcmp(token, "connection-auth") == 0) {
+            p->connection_auth = 1;
+        } else if (strcmp(token, "connection-auth=on") == 0) {
+            p->connection_auth = 1;
+        } else if (strcmp(token, "connection-auth=auto") == 0) {
+            p->connection_auth = 2;
         } else {
             debugs(3, 0, "parse_peer: token='" << token << "'");
             self_destruct();
@@ -2936,6 +2945,8 @@
         s->accel = 1;
     } else if (strcmp(token, "accel") == 0) {
         s->accel = 1;
+    } else if (strcmp(token, "no-connection-auth") == 0) {
+        s->no_connection_auth = 1;
     } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) {
         if (!strcasecmp(token + 23, "off"))
             s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
@@ -3108,6 +3119,9 @@
     if (s->vport)
         storeAppendPrintf(e, " vport");
 
+    if (s->no_connection_auth)
+        storeAppendPrintf(e, " no-connection-auth");
+
     if (s->disable_pmtu_discovery != DISABLE_PMTU_OFF) {
         const char *pmtu;
 

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2008-09-20 09:43:40 +0000
+++ src/cf.data.pre	2008-09-20 15:15:50 +0000
@@ -1023,6 +1023,10 @@
 	   protocol=	Protocol to reconstruct accelerated requests with.
 			Defaults to http.
 
+           no-connection-auth
+                        Prevent forwarding of Microsoft connection oriented
+                        authentication (NTLM, Negotiate and Kerberos)
+
 	   disable-pmtu-discovery=
 			Control Path-MTU discovery usage:
 			    off		lets OS decide on what to do (default).
@@ -1588,6 +1592,7 @@
 		     sslcipher=...
 		     ssloptions=...
 		     front-end-https[=on|auto]
+                     connection-auth[=on|off|auto]
 
 		     use 'proxy-only' to specify objects fetched
 		     from this cache should not be saved locally.
@@ -1796,6 +1801,12 @@
 		     on this header. If set to auto the header will
 		     only be added if the request is forwarded as a https://
 		     URL.
+                     
+                     use connection-auth=off to tell Squid that this peer does
+                     not support Microsoft connection oriented authentication,
+                     and any such challenges received from there should be
+                     ignored. Default is auto to automatically determine the
+                     status of the peer.
 DOC_END
 
 NAME: cache_peer_domain cache_host_domain

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2008-09-11 04:54:34 +0000
+++ src/client_side.cc	2008-09-14 13:22:13 +0000
@@ -644,6 +644,9 @@
     if (!flags.swanSang)
         debugs(33, 1, "BUG: ConnStateData was not destroyed properly; FD " << fd);
 
+    if (pinning.fd >= 0)
+        comm_close(pinning.fd);
+
     AUTHUSERREQUESTUNLOCK(auth_user_request, "~conn");
 
     cbdataReferenceDone(port);
@@ -1368,6 +1371,12 @@
     debugs(33, 3, "ClientSocketContext::keepaliveNextRequest: FD " << conn->fd);
     connIsFinished();
 
+    if (conn->pinning.pinned && conn->pinning.fd == -1) {
+        debug(33, 2) ("clientKeepaliveNextRequest: FD %d Connection was pinned but server side gone. Terminating client connection\n", conn->fd);
+        comm_close(conn->fd);
+        return;
+    }
+
     /** \par
      * Attempt to parse a request from the request buffer.
      * If we've been fed a pipelined request it may already
@@ -3336,6 +3345,7 @@
 
 ConnStateData::ConnStateData() :AsyncJob("ConnStateData"), transparent_ (false), reading_ (false), closing_ (false)
 {
+    pinning.fd = -1;
 }
 
 bool
@@ -3415,3 +3425,108 @@
     if (allocatedSize)
         memFreeBuf(allocatedSize, buf);
 }
+
+/* This is a handler normally called by comm_close() */
+static void
+clientPinnedConnectionClosed(int fd, void *data)
+{
+    ConnStateData *conn = (ConnStateData *)data;
+    conn->pinning.fd = -1;
+    if (conn->pinning.peer) {
+	cbdataReferenceDone(conn->pinning.peer);
+	conn->pinning.peer = NULL;
+    }
+    safe_free(conn->pinning.host);
+    /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
+     * connection has gone away */
+}
+
+/**
+ * Correlate the current ConnStateData object with the pinning_fd socket descriptor.
+ */
+void ConnStateData::pinConnection(int pinning_fd, HttpRequest *request, struct peer *peer, int auth){
+    fde *f;
+    char desc[FD_DESC_SZ];
+
+    if (pinning.fd == pinning_fd)
+	return;
+    else if (pinning.fd != -1)
+	comm_close(pinning.fd);
+    
+    if(pinning.host)
+	safe_free(pinning.host);
+    
+    pinning.fd = pinning_fd;
+    pinning.host = xstrdup(request->GetHost());
+    pinning.port = request->port;
+    pinning.pinned = 1;
+    if (pinning.peer)
+	cbdataReferenceDone(pinning.peer);
+    if (peer)
+	pinning.peer = cbdataReference(peer);
+    pinning.auth = auth;
+    f = &fd_table[fd];
+    snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s:%d (%d)",
+	(auth || !peer) ? request->GetHost() : peer->name, f->ipaddr, (int) f->remote_port, fd);
+    fd_note(pinning_fd, desc);
+    comm_add_close_handler(pinning_fd, clientPinnedConnectionClosed, this);
+}
+
+/**
+ * If the current ConnStateData has pinned connection returns the socket descriptor of 
+ * pinned connection and the peer object if exists
+*/
+int ConnStateData::getPinnedInfo(const HttpRequest * request, struct peer * &peer){
+
+    if (pinning.fd < 0)
+	return -1;
+
+    if (pinning.auth && request && strcasecmp(pinning.host, request->GetHost()) != 0) {
+	comm_close(pinning.fd);
+	return -1;
+    }
+    if (request && pinning.port != request->port){
+	comm_close(pinning.fd);
+	return -1;
+    }
+    if (pinning.peer && !cbdataReferenceValid(pinning.peer)){
+	comm_close(pinning.fd);
+	return -1;
+    }
+
+    /*
+      Maybe the peer should be a cbdataReference of pinning.peer (and the caller 
+      use cbdataReferenceDone).
+      Now the peer is a single pointer...
+     */
+    peer = pinning.peer;
+    return pinning.fd;
+}
+
+
+/**
+ * Returns the pinned socked descriptor if exists and decorrelate the current ConnStateData
+ * object with this socket descriptor.
+ */
+int ConnStateData::getPinnedConnection(const HttpRequest * request, const struct peer * peer, int &auth){
+    int pinning_fd = pinning.fd;
+    if (pinning_fd < 0)
+	return -1;
+
+    if (pinning.auth && request && strcasecmp(pinning.host, request->GetHost()) != 0) {
+	comm_close(pinning_fd);
+	return -1;
+    }
+    auth = pinning.auth;
+    if (peer != pinning.peer){
+	comm_close(pinning_fd);
+	return -1;
+    }
+    cbdataReferenceDone(pinning.peer);
+    pinning.peer = NULL;
+    pinning.fd = -1;
+    comm_remove_close_handler(pinning_fd, clientPinnedConnectionClosed, this);
+    return pinning_fd;
+}
+
+

=== modified file 'src/client_side.h'
--- src/client_side.h	2008-09-11 04:54:34 +0000
+++ src/client_side.h	2008-09-14 13:22:13 +0000
@@ -189,6 +189,15 @@
         bool readMoreRequests;
         bool swanSang; // XXX: temporary flag to check proper cleanup
     } flags;
+    struct {
+        int fd;                 /* pinned server side connection */
+        char *host;             /* host name of pinned connection */
+        int port;               /* port of pinned connection */
+        int pinned;             /* this connection was pinned */
+        int auth;               /* pinned for www authentication */
+        struct peer *peer;             /* peer the connection goes via */
+     } pinning;
+
     http_port_list *port;
 
     bool transparent() const;
@@ -205,6 +214,9 @@
 
     void handleReadData(char *buf, size_t size);
     void handleRequestBodyData();
+    void pinConnection(int fd, HttpRequest *request, struct peer *peer, int auth);
+    int getPinnedInfo(const HttpRequest *request, struct peer * &peer);
+    int getPinnedConnection(const HttpRequest *request, const struct peer *peer, int &auth);
 
     // comm callbacks
     void clientReadRequest(const CommIoCbParams &io);

=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc	2008-09-20 05:00:47 +0000
+++ src/client_side_reply.cc	2008-09-20 17:20:16 +0000
@@ -1249,24 +1249,60 @@
     /* Filter unproxyable authentication types */
 
     if (http->logType != LOG_TCP_DENIED &&
-	    (hdr->has(HDR_WWW_AUTHENTICATE) || hdr->has(HDR_PROXY_AUTHENTICATE))) {
+            hdr->has(HDR_WWW_AUTHENTICATE)) {
         HttpHeaderPos pos = HttpHeaderInitPos;
         HttpHeaderEntry *e;
 
-        int headers_deleted = 0;
+	int connection_auth_blocked = 0;
         while ((e = hdr->getEntry(&pos))) {
-            if (e->id == HDR_WWW_AUTHENTICATE || e->id == HDR_PROXY_AUTHENTICATE) {
+            if (e->id == HDR_WWW_AUTHENTICATE) {
                 const char *value = e->value.buf();
 
                 if ((strncasecmp(value, "NTLM", 4) == 0 &&
                         (value[4] == '\0' || value[4] == ' '))
                         ||
                         (strncasecmp(value, "Negotiate", 9) == 0 &&
-                         (value[9] == '\0' || value[9] == ' ')))
-                            hdr->delAt(pos, headers_deleted);
+                         (value[9] == '\0' || value[9] == ' '))
+		        ||
+		        (strncasecmp(value, "Kerberos", 8) == 0 &&
+                         (value[8] == '\0' || value[8] == ' ')))
+		{
+		    if (request->flags.no_connection_auth) {
+			hdr->delAt(pos, connection_auth_blocked);
+                        continue;
+                    }
+		    request->flags.must_keepalive = 1;
+		    if (!request->flags.accelerated && !request->flags.intercepted) {
+			/* The use of the Proxy-Support header is documented in the RFC4559.
+			   I was not able to find documentation about the use of the header
+			   "Connection: Proxy-Support" and how other http proxies use this header.
+			   The only I found is a Henrik's comment:
+			   
+			   "[...] However, this alone is not sufficient. You must also add a 
+			   "Connection: Proxy-support" header to mark the extension header as a 
+			   hop-by-hop header to protect from other proxies inbetween this proxy 
+			   and the client.
+			   
+			   Also, you should also keep in mind that transparently intercepting 
+			   proxies are quite widely deployed on the Internet today, so to really 
+			   have a reasonable chance of working the server initiating the 
+			   "Negotiate" scheme needs to add a extension hop-by-hop header 
+			   signalling that this connection needs to be kept end-to-end and 
+			   negotiate (SPNEGO) only accepted by the client if this extension 
+			   header is seen in the reply. [...]"
+
+			   (http://osdir.com/ml/ietf.krb-wg/2002-11/msg00024.html)
+
+			 */
+                        httpHeaderPutStrf(hdr, HDR_PROXY_SUPPORT, "Session-Based-Authentication");
+                        httpHeaderPutStrf(hdr, HDR_CONNECTION, "Proxy-support");
+                    }
+                    break;
+		}
             }
         }
-        if (headers_deleted)
+
+        if (connection_auth_blocked)
             hdr->refreshMask();
     }
 
@@ -1324,6 +1360,12 @@
         debugs(88, 3, "clientBuildReplyHeader: Shutting down, don't keep-alive.");
         request->flags.proxy_keepalive = 0;
     }
+    
+     if (request->flags.connection_auth && !reply->keep_alive) {
+	 debug(33, 2) ("clientBuildReplyHeader: Connection oriented auth but server side non-persistent\n");
+	 request->flags.proxy_keepalive = 0;
+    }
+
 
     /* Append VIA */
     if (Config.onoff.via) {

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2008-09-11 11:14:39 +0000
+++ src/client_side_request.cc	2008-09-14 13:22:13 +0000
@@ -828,6 +828,55 @@
     if (req_hdr->has(HDR_AUTHORIZATION))
         request->flags.auth = 1;
 
+
+    if (!request->flags.no_connection_auth) {
+	ConnStateData *http_conn = http->getConn();
+	if (http_conn->pinning.fd != -1) {
+	    if (http_conn->pinning.auth) {
+		request->flags.connection_auth = 1;
+		request->flags.auth = 1;
+	    } else {
+		request->flags.connection_proxy_auth = 1;
+	    }
+	    request->pinned_connection = cbdataReference(http_conn);
+	}
+    }
+
+    /* check if connection auth is used, and flag as candidate for pinning
+     * in such case.
+     * Note: we may need to set flags.connection_auth even if the connection
+     * is already pinned if it was pinned earlier due to proxy auth
+     */
+    if (!request->flags.connection_auth) {
+	if (req_hdr->has(HDR_AUTHORIZATION) || req_hdr->has(HDR_PROXY_AUTHORIZATION)) {
+	    HttpHeaderPos pos = HttpHeaderInitPos;
+	    HttpHeaderEntry *e;
+	    int may_pin = 0;
+	    while ((e = req_hdr->getEntry(&pos))) {
+		if (e->id == HDR_AUTHORIZATION || e->id == HDR_PROXY_AUTHORIZATION) {
+		    const char *value = e->value.buf();
+		    if (strncasecmp(value, "NTLM ", 5) == 0
+			||
+			strncasecmp(value, "Negotiate ", 10) == 0
+			||
+			strncasecmp(value, "Kerberos ", 9) == 0) {
+			if (e->id == HDR_AUTHORIZATION) {
+			    request->flags.connection_auth = 1;
+			    may_pin = 1;
+			} else {
+			    request->flags.connection_proxy_auth = 1;
+			    may_pin = 1;
+			}
+		    }
+		}
+	    }
+	    if (may_pin && !request->pinned_connection) {
+		request->pinned_connection = cbdataReference(http->getConn());
+	    }
+	}
+    }
+
+
     if (request->login[0] != '\0')
         request->flags.auth = 1;
 

=== modified file 'src/enums.h'
--- src/enums.h	2008-07-11 20:43:43 +0000
+++ src/enums.h	2008-07-17 18:33:07 +0000
@@ -177,7 +177,8 @@
     ANY_OLD_PARENT,
     USERHASH_PARENT,
     SOURCEHASH_PARENT,
-    HIER_MAX
+    HIER_MAX,
+    PINNED
 } hier_code;
 
 /// \ingroup ServerProtocolICPAPI

=== modified file 'src/forward.cc'
--- src/forward.cc	2008-09-18 09:46:56 +0000
+++ src/forward.cc	2008-09-20 15:15:50 +0000
@@ -804,6 +804,35 @@
     if (ftimeout < ctimeout)
         ctimeout = ftimeout;
 
+
+    request->flags.pinned = 0;
+    if (fs->code == PINNED) {
+        int auth;
+	assert(request->pinned_connection);
+        fd = request->pinned_connection->getPinnedConnection(request, fs->_peer, auth);
+        if (fd >= 0) {
+#if 0
+            if (!fs->_peer)
+                fs->code = HIER_DIRECT;
+#endif
+            server_fd = fd;
+            n_tries++;
+            request->flags.pinned = 1;
+            if (auth)
+                request->flags.auth = 1;
+            comm_add_close_handler(fd, fwdServerClosedWrapper, this);
+            connectDone(fd, COMM_OK, 0);
+            return;
+        }
+       /* Failure. Fall back on next path */
+        cbdataReferenceDone(request->pinned_connection);
+        request->pinned_connection = NULL;
+        servers = fs->next;
+        fwdServerFree(fs);
+        connectStart();
+        return;
+    }	
+
     fd = fwdPconnPool->pop(host, port, domain, client_addr, checkRetriable());
     if (fd >= 0) {
         debugs(17, 3, "fwdConnectStart: reusing pconn FD " << fd);

=== modified file 'src/http.cc'
--- src/http.cc	2008-09-13 13:43:00 +0000
+++ src/http.cc	2008-09-14 13:22:13 +0000
@@ -377,7 +377,7 @@
         }
     }
 
-    if (request->flags.auth) {
+    if (request->flags.auth || request->flags.auth_sent) {
         /*
          * Responses to requests with authorization may be cached
          * only if a Cache-Control: public reply header is present.
@@ -709,6 +709,9 @@
 	 httpChunkDecoder = new ChunkedCodingParser;
     }
 
+    if(!peerSupportsConnectionPinning())
+	orig_request->flags.no_connection_auth = 1;
+
     HttpReply *vrep = setVirginReply(newrep);
     flags.headers_parsed = 1;
 
@@ -726,6 +729,67 @@
 
 }
 
+/**
+ * returns true if the peer can support connection pinning
+*/
+bool HttpStateData::peerSupportsConnectionPinning()
+{
+    const HttpReply *rep = entry->mem_obj->getReply();
+    const HttpHeader *hdr = &rep->header;
+    bool rc;
+    String header;
+
+    if (!_peer)
+	return true;
+    
+    /*If this peer does not support connection pinning (authenticated 
+      connections) return false
+     */
+    if (!_peer->connection_auth)
+	return false;
+
+    /*The peer supports connection pinning and the http reply status 
+      is not unauthorized, so the related connection can be pinned
+     */
+    if (rep->sline.status != HTTP_UNAUTHORIZED)
+	return true;
+    
+    /*The server respond with HTTP_UNAUTHORIZED and the peer configured 
+      with "connection-auth=on" we know that the peer supports pinned 
+      connections
+    */
+    if (_peer->connection_auth == 1)
+	return true;
+
+    /*At this point peer has configured with "connection-auth=auto" 
+      parameter so we need some extra checks to decide if we are going 
+      to allow pinned connections or not
+    */
+
+    /*if the peer configured with originserver just allow connection 
+        pinning (squid 2.6 behaviour)
+     */
+    if (_peer->options.originserver)
+	return true;
+
+    /*if the connections it is already pinned it is OK*/
+    if (request->flags.pinned)
+	return true;
+    
+    /*Allow pinned connections only if the Proxy-support header exists in 
+      reply and has in its list the "Session-Based-Authentication" 
+      which means that the peer supports connection pinning.
+     */
+    if (!hdr->has(HDR_PROXY_SUPPORT))
+	return false;
+
+    header = hdr->getStrOrList(HDR_PROXY_SUPPORT);
+    /* XXX This ought to be done in a case-insensitive manner */
+    rc = (strstr(header.buf(), "Session-Based-Authentication") != NULL);
+
+    return rc;
+}
+
 // Called when we parsed (and possibly adapted) the headers but
 // had not starting storing (a.k.a., sending) the body yet.
 void
@@ -1135,6 +1199,7 @@
 {
     AsyncCall::Pointer call;
     IPAddress client_addr;
+    bool ispinned = false;
 
     if (!flags.headers_parsed) {
         flags.do_next_read = 1;
@@ -1200,7 +1265,16 @@
             if (orig_request->flags.spoof_client_ip)
                 client_addr = orig_request->client_addr;
 
-            if (_peer) {
+
+	    if (request->flags.pinned) {
+		ispinned = true;
+	    } else if (request->flags.connection_auth && request->flags.auth_sent) {
+		ispinned = true;
+	    }
+	   
+	    if (orig_request->pinned_connection && ispinned) {
+		orig_request->pinned_connection->pinConnection(fd, orig_request, _peer, request->flags.connection_auth);
+	    } else if (_peer) {
                 if (_peer->options.originserver)
                     fwd->pconnPush(fd, _peer->name, orig_request->port, orig_request->GetHost(), client_addr);
                 else
@@ -1709,7 +1783,7 @@
      */
 
     if (NULL == orig_request->range || !orig_request->flags.cachable
-            || orig_request->range->offsetLimitExceeded())
+            || orig_request->range->offsetLimitExceeded() || orig_request->flags.connection_auth)
         result = false;
 
         debugs(11, 8, "decideIfWeDoRanges: range specs: " <<
@@ -1739,6 +1813,12 @@
         HttpHeader hdr(hoRequest);
         Packer p;
         httpBuildRequestHeader(request, orig_request, entry, &hdr, flags);
+	
+	if (request->flags.pinned && request->flags.connection_auth)
+            request->flags.auth_sent = 1;
+        else if (hdr.has(HDR_AUTHORIZATION))
+            request->flags.auth_sent = 1;
+
         packerToMemInit(&p, mb);
         hdr.packInto(&p);
         hdr.clean();
@@ -1792,7 +1872,9 @@
     /*
      * Is keep-alive okay for all request methods?
      */
-    if (!Config.onoff.server_pconns)
+    if (orig_request->flags.must_keepalive)
+	flags.keepalive = 1;
+    else if (!Config.onoff.server_pconns)
         flags.keepalive = 0;
     else if (_peer == NULL)
         flags.keepalive = 1;

=== modified file 'src/http.h'
--- src/http.h	2008-09-13 13:43:00 +0000
+++ src/http.h	2008-09-14 13:22:13 +0000
@@ -118,6 +118,7 @@
                                  MemBuf * mb,
                                  http_state_flags flags);
     static bool decideIfWeDoRanges (HttpRequest * orig_request);
+    bool peerSupportsConnectionPinning();
 
     ChunkedCodingParser *httpChunkDecoder;
 private:

=== modified file 'src/neighbors.cc'
--- src/neighbors.cc	2008-07-18 11:24:16 +0000
+++ src/neighbors.cc	2008-09-20 15:39:41 +0000
@@ -51,7 +51,7 @@
 /* count mcast group peers every 15 minutes */
 #define MCAST_COUNT_RATE 900
 
-static int peerAllowedToUse(const peer *, HttpRequest *);
+int peerAllowedToUse(const peer *, HttpRequest *);
 static int peerWouldBePinged(const peer *, HttpRequest *);
 static void neighborRemove(peer *);
 static void neighborAlive(peer *, const MemObject *, const icp_common_t *);
@@ -136,7 +136,7 @@
  * this function figures out if it is appropriate to fetch REQUEST
  * from PEER.
  */
-static int
+int
 peerAllowedToUse(const peer * p, HttpRequest * request)
 {
 
@@ -1635,6 +1635,13 @@
     if (p->domain)
         storeAppendPrintf(sentry, " forceddomain=%s", p->domain);
 
+    if(p->connection_auth == 0)
+	storeAppendPrintf(sentry, " connection-auth=off");
+    else if(p->connection_auth == 1)
+	storeAppendPrintf(sentry, " connection-auth=on");
+    else if(p->connection_auth == 2)
+	storeAppendPrintf(sentry, " connection-auth=auto");
+
     storeAppendPrintf(sentry, "\n");
 }
 

=== modified file 'src/peer_select.cc'
--- src/peer_select.cc	2008-07-11 20:43:43 +0000
+++ src/peer_select.cc	2008-09-07 14:20:04 +0000
@@ -100,6 +100,7 @@
 static void peerGetSomeParent(ps_state *);
 static void peerGetAllParents(ps_state *);
 static void peerAddFwdServer(FwdServer **, peer *, hier_code);
+static void peerGetPinned(ps_state * ps);
 
 CBDATA_CLASS_INIT(ps_state);
 
@@ -322,6 +323,8 @@
         debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct]);
     }
 
+    if (!entry || entry->ping_status == PING_NONE)
+        peerGetPinned(ps);
     if (entry == NULL) {
         (void) 0;
     } else if (entry->ping_status == PING_NONE) {
@@ -363,6 +366,32 @@
 }
 
 /*
+ * peerGetPinned
+ *
+ * Selects a pinned connection
+ */
+int peerAllowedToUse(const peer * p, HttpRequest * request);
+static void
+peerGetPinned(ps_state * ps)
+{
+    HttpRequest *request = ps->request;
+    peer *peer;
+    if (!request->pinned_connection)
+        return;
+    if (request->pinned_connection->getPinnedInfo(request, peer) != -1) {
+        if (peer && peerAllowedToUse(peer, request)) {
+            peerAddFwdServer(&ps->servers, peer, PINNED);
+            if (ps->entry)
+                ps->entry->ping_status = PING_DONE;     /* Skip ICP */
+        } else if (!peer && ps->direct != DIRECT_NO) {
+            peerAddFwdServer(&ps->servers, NULL, PINNED);
+            if (ps->entry)
+                ps->entry->ping_status = PING_DONE;     /* Skip ICP */
+        }
+    }
+}
+
+/*
  * peerGetSomeNeighbor
  * 
  * Selects a neighbor (parent or sibling) based on one of the

=== modified file 'src/structs.h'
--- src/structs.h	2008-08-09 06:24:33 +0000
+++ src/structs.h	2008-09-02 08:32:52 +0000
@@ -1011,6 +1011,7 @@
 #endif
 
     int front_end_https;
+    int connection_auth;
 };
 
 struct _net_db_name
@@ -1095,6 +1096,11 @@
     unsigned int internal:1;
     unsigned int internalclient:1;
     unsigned int must_keepalive:1;
+    unsigned int connection_auth:1; /** Request wants connection oriented auth */
+    unsigned int no_connection_auth:1; /** Connection oriented auth can not be supported */
+    unsigned int connection_proxy_auth:1; /** Request wants connection oriented auth */
+    unsigned int pinned:1;      /* Request seont on a pinned connection */
+    unsigned int auth_sent:1;   /* Authentication forwarded */
 
     // When adding new flags, please update cloneAdaptationImmune() as needed.
 

# Begin bundle
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
l3MyB06tBvvCb6Q57QPRxnYR0d0MESTT0+Tx+L7w4jCoKP8n48BpoVL8JrZkMOGaf6ajW4jm226k
LMExr9lOSfmn6b65PD0UdSBtPU0l+bObR0rgmEj0wXXX3/D8HxUDu9/QCtPOZSkiZ+l9ybVo/Wfr
UWUbKs2+uM5Z5LfxmbJhoozWZP2pNn8jVmTbvmwscNGzZdw/Us82a9LJ3ZJNlGrhdZk4Wf092q7J
q1YdNHCpBkcufg+3QySYODgg0WsxQyKSd0Ekmf0Es97vTDZo6cJNl1lXCaaijzEEdtEnho8m0Giy
aTVOyirV7MK57pTyWXcuGzhs8t26jNm1ZLpGvOqzJyzZmyzNuku8+bsLuDV9mrxCMkmTKEUezDp2
k5WSeSxd08Mnlh2Zr1S6XWbqrskkmzdagHk5tSQwff0xSagoJTW8gPLCB3P7qywibduhIXEIQKhi
owLty56KGozExcPNScgUFxKbTaXhpMZQ0hr5vdUAieFw09D9ng7VbQtE9QBtAf7+BunQ8Rwa0cHm
PkXIXZ5YedHzpsLUAA1QVE5vYlgC8XTxSmf4N4qFwoPOcReYjHcewcTmvZmgVkDh1GpLSE8WqHHe
QO8tKCY/IkuyatogzZp3bKNFlGyyTJNy+tqybtHDZ11k2KtWzlJmk/TGjwydOV3hhmizw7ZvDMsk
4RtZKZJyycqqMmrVo3auFSGjx4qq0dumFlHDNu8NkzDN0q333VbMnh01KunhZ011ybMJs2jRNyo2
bJLsnzQptylHDNVow7bpOmzwVdsPT2zVhElCJQVlyDJH+aGRwxLjuHlfNOBwJi48g7KAjsJVlhoa
DjaVmJtIjxwbzUiDy0+pg/EdWGb/t/12G8nPMAEanIxIBgXFx0GCg7dqvtYaVXaPtRw+z7830KtH
0OFVnCaar6oR+CImZPLp0qdO27w2axGSbNm1u3bPw+0VQcGUoZzlV3F6Fi6spOoyBkMBUtMZnCoY
cRNpIMYmnTE6h66AJ3IKW5t1+bBAnnjP+0Cec85AZJ7ABLBKCWCUEoNiUGxKDYlIywSwiQpBKAws
iUGxKDYlBsSwiQsBKDRLBLEsBJSJSMsEoNEsEoJYJQSwEliWRCxKDRLHuJ06uuE/EQyFnZS0B7Kg
WGZxHoo0QxoRGBBIMGJBKHIAej2CXnOkDqOwVfSYKLP/3BTb3JGXAhJ+31F9VM4xozO22kwggJAy
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

Reply via email to