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=", 9)) {
+ 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 *nextkey=token+strlen("carp-key="), *key=nextkey;
+ for (; key; key = nextkey) {
+ nextkey=strchr(key,',');
+ if (nextkey) ++nextkey; // skip the comma, any
+ if (0==strncasecmp(key,"scheme",6)) {
+ p->options.carp_key.scheme=1;
+ } else if (0==strncasecmp(key,"host",4)) {
+ p->options.carp_key.host=1;
+ } else if (0==strncasecmp(key,"port",4)) {
+ p->options.carp_key.port=1;
+ } else if (0==strncasecmp(key,"path",4)) {
+ p->options.carp_key.path=1;
+ } else if (0==strncasecmp(key,"params",6)) {
+ p->options.carp_key.params=1;
+ } else {
+ fatalf("invalid carp-key '%s'",key);
+ }
+ }
} else if (!strcasecmp(token, "userhash")) {
#if USE_AUTH
if (p->type != PEER_PARENT)
*/
#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))))
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.
+ // corner cases should use the canonical URL
+ if (tp->options.carp_key.scheme) {
+ // temporary, until bug 1961 URL handling is fixed.
+ const URLScheme sch = request->protocol;
+ key.append(sch.const_str());
+ if (key.size()) //if the scheme is not empty
+ 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()));
+ }
+ }
+ // if the url-based key is empty, e.g. because the user is
+ // asking to balance on the path but the request doesn't supply any,
+ // then fall back to canonical URL
+
+ if (key.size()==0)
+ 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;