=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2011-07-14 08:59:10 +0000
+++ src/cache_cf.cc	2011-07-30 18:08:42 +0000
@@ -2244,6 +2244,33 @@
                 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
 
             p->options.carp = 1;
+        } else if (!strncasecmp(token, "carp-key=", strlen("carp-key="))) {
+            if (p->options.carp != 1)
+                fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
+            p->options.carp_key.set=1;
+            char *tmp=xstrdup(token+strlen("carp-key="));
+            char *key,*nextkey;
+            for (key = nextkey = tmp; key; key=nextkey) {
+            	nextkey=strchr(key,',');
+            	if (nextkey)
+            		*nextkey++='\0';
+            	if (!strcasecmp(key,"scheme")) {
+            		p->options.carp_key.scheme=1;
+            	} else if (!strcasecmp(key,"login")) {
+            		p->options.carp_key.login=1;
+            	} else if (!strcasecmp(key,"host")) {
+            		p->options.carp_key.host=1;
+            	} else if (!strcasecmp(key,"port")) {
+            		p->options.carp_key.port=1;
+            	} else if (!strcasecmp(key,"path")) {
+            		p->options.carp_key.path=1;
+            	} else if (!strcasecmp(key,"params")) {
+            		p->options.carp_key.params=1;
+            	} else {
+            		fatalf("invalid carp key '%s'",key);
+            	}
+            }
+            safe_free(tmp);
         } else if (!strcasecmp(token, "userhash")) {
 #if USE_AUTH
             if (p->type != PEER_PARENT)

=== modified file 'src/carp.cc'
--- src/carp.cc	2010-10-28 18:52:59 +0000
+++ src/carp.cc	2011-07-30 19:15:00 +0000
@@ -35,8 +35,10 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 #include "mgr/Registration.h"
 #include "Store.h"
+#include "URLScheme.h"
 
 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
 
@@ -164,35 +166,74 @@
 carpSelectParent(HttpRequest * request)
 {
     int k;
-    const char *c;
     peer *p = NULL;
     peer *tp;
     unsigned int user_hash = 0;
     unsigned int combined_hash;
     double score;
     double high_score = 0;
-    const char *key = NULL;
 
     if (n_carp_peers == 0)
         return NULL;
 
-    key = urlCanonical(request);
-
     /* calculate hash key */
-    debugs(39, 2, "carpSelectParent: Calculating hash for " << key);
-
-    for (c = key; *c != 0; c++)
-        user_hash += ROTATE_LEFT(user_hash, 19) + *c;
+    debugs(39, 2, "carpSelectParent: Calculating hash for " << urlCanonical(request));
 
     /* select peer */
     for (k = 0; k < n_carp_peers; k++) {
+    	String key;
         tp = carp_peers[k];
+    	if (tp->options.carp_key.set) {
+    		//this code follows urlCanonical's pattern.
+    		//   all cornercases default to urlCanonical
+    		if (request->protocol == AnyP::PROTO_URN) {
+    			key=urlCanonical(request);
+    		} else if (request->method.id()==METHOD_CONNECT) {
+    			key=urlCanonical(request);
+    		} else {
+    			if (tp->options.carp_key.scheme) {
+    				 // temporary, until bug 1961 URL handling is fixed.
+    				const URLScheme sch = request->protocol;
+    				key.append(sch.const_str());
+    				key.append("://");
+    			}
+    			if (tp->options.carp_key.login) {
+    				key.append(request->login);
+    				key.append('@');
+    			}
+    			if (tp->options.carp_key.host) {
+    				key.append(request->GetHost());
+    			}
+    			if (tp->options.carp_key.port) {
+    				static char portbuf[7];
+    				snprintf(portbuf,7,":%d", request->port);
+    				key.append(portbuf);
+    			}
+    			if (tp->options.carp_key.path) {
+    				String::size_type pos;
+    				if ((pos=request->urlpath.find('?'))!=String::npos)
+    					key.append(request->urlpath.substr(0,pos));
+    				else
+    					key.append(request->urlpath);
+    			}
+    			if (tp->options.carp_key.params) {
+    				String::size_type pos;
+    				if ((pos=request->urlpath.find('?'))!=String::npos)
+    					key.append(request->urlpath.substr(pos,request->urlpath.size()));
+    			}
+
+    		}
+    	} else {
+    		key=urlCanonical(request);
+    	}
+        for (const char *c = key.rawBuf(), *e=key.rawBuf()+key.size(); c < e; c++)
+            user_hash += ROTATE_LEFT(user_hash, 19) + *c;
         combined_hash = (user_hash ^ tp->carp.hash);
         combined_hash += combined_hash * 0x62531965;
         combined_hash = ROTATE_LEFT(combined_hash, 21);
         score = combined_hash * tp->carp.load_multiplier;
-        debugs(39, 3, "carpSelectParent: " << tp->name << " combined_hash " << combined_hash  <<
-               " score " << std::setprecision(0) << score);
+        debugs(39, 3, "carpSelectParent: key=" << key << " name=" << tp->name << " combined_hash=" << combined_hash  <<
+               " score=" << std::setprecision(0) << score);
 
         if ((score > high_score) && peerHTTPOkay(tp, request)) {
             p = tp;

=== modified file 'src/cf.data.pre'
--- src/cf.data.pre	2011-07-22 13:36:58 +0000
+++ src/cf.data.pre	2011-07-30 19:21:17 +0000
@@ -2178,6 +2178,14 @@
 			than the Squid default location.
 	
 	
+	==== CARP OPTIONS ====
+	
+	carp-key=key-specification
+			use a different key than the full URL to hash against the peer.
+			the key-specification is a comma-separated list of the keywords			
+			scheme, login, host, port, path, params
+			Order is not important.
+	
 	==== ACCELERATOR / REVERSE-PROXY OPTIONS ====
 	
 	originserver	Causes this parent to be contacted as an origin server.

=== modified file 'src/structs.h'
--- src/structs.h	2011-06-23 08:33:13 +0000
+++ src/structs.h	2011-07-30 18:08:45 +0000
@@ -855,6 +855,15 @@
 #endif
         unsigned int allow_miss:1;
         unsigned int carp:1;
+        struct {
+        	unsigned int set:1; //If false, whole url is to be used. Overrides others
+        	unsigned int scheme:1;
+        	unsigned int login:1;
+        	unsigned int host:1;
+        	unsigned int port:1;
+        	unsigned int path:1;
+        	unsigned int params:1;
+        } carp_key;
 #if USE_AUTH
         unsigned int userhash:1;
 #endif