This patch is generated from the rproxy branch of HEAD in squid Wed May 17 00:16:13 2006 GMT See http://devel.squid-cache.org/ Index: squid/acconfig.h diff -u squid/acconfig.h:1.24 squid/acconfig.h:1.24.2.1 --- squid/acconfig.h:1.24 Mon May 15 08:52:04 2006 +++ squid/acconfig.h Mon May 15 18:01:31 2006 @@ -407,6 +407,11 @@ */ #undef X_ACCELERATOR_VARY +/* + * Enable authentication support in accelerators + */ +#undef AUTH_ON_ACCELERATION + @BOTTOM@ #endif /* __CONFIGURE_H__ */ Index: squid/configure.in diff -u squid/configure.in:1.84 squid/configure.in:1.84.2.1 --- squid/configure.in:1.84 Mon May 15 15:50:48 2006 +++ squid/configure.in Mon May 15 18:01:31 2006 @@ -679,6 +679,15 @@ fi ]) +AC_ARG_ENABLE(auth-on-acceleration, +[ --enable-auth-on-acceleration + Enable authentication in accelerators], +[ if test "$enableval" = "yes" ; then + echo "AUTH_ON_ACCELERATION enabled" + AC_DEFINE(AUTH_ON_ACCELERATION) + fi +]) + dnl Select Default Error language AC_ARG_ENABLE(default-err-language, [ --enable-default-err-language=lang Index: squid/include/cache_snmp.h diff -u squid/include/cache_snmp.h:1.4 squid/include/cache_snmp.h:1.4.2.1 --- squid/include/cache_snmp.h:1.4 Sun May 14 02:50:55 2006 +++ squid/include/cache_snmp.h Mon May 15 18:01:31 2006 @@ -124,6 +124,8 @@ MESH_PTBL_IGN, MESH_PTBL_KEEPAL_S, MESH_PTBL_KEEPAL_R, + MESH_PTBL_INDEX, + MESH_PTBL_HOST, MESH_PTBL_END }; Index: squid/src/HttpHeader.c diff -u squid/src/HttpHeader.c:1.18 squid/src/HttpHeader.c:1.18.2.1 --- squid/src/HttpHeader.c:1.18 Fri May 12 15:51:56 2006 +++ squid/src/HttpHeader.c Mon May 15 18:01:31 2006 @@ -130,6 +130,8 @@ #if X_ACCELERATOR_VARY {"X-Accelerator-Vary", HDR_X_ACCELERATOR_VARY, ftStr}, #endif + {"X-Error-URL", HDR_X_ERROR_URL, ftStr}, + {"X-Error-Status", HDR_X_ERROR_STATUS, ftInt}, {"Other:", HDR_OTHER, ftStr} /* ':' will not allow matches */ }; static HttpHeaderFieldInfo *Headers = NULL; Index: squid/src/HttpRequest.c diff -u squid/src/HttpRequest.c:1.8 squid/src/HttpRequest.c:1.8.4.1 --- squid/src/HttpRequest.c:1.8 Fri Apr 28 04:10:50 2006 +++ squid/src/HttpRequest.c Mon May 15 18:01:31 2006 @@ -61,6 +61,7 @@ authenticateAuthUserRequestUnlock(req->auth_user_request); safe_free(req->canonical); safe_free(req->vary_headers); + safe_free(req->urlgroup); stringClean(&req->urlpath); httpHeaderClean(&req->header); if (req->cache_control) Index: squid/src/Makefile.am diff -u squid/src/Makefile.am:1.33 squid/src/Makefile.am:1.33.2.1 --- squid/src/Makefile.am:1.33 Mon May 15 08:52:05 2006 +++ squid/src/Makefile.am Mon May 15 18:01:31 2006 @@ -131,6 +131,7 @@ errorpage.c \ ETag.c \ event.c \ + errormap.c \ external_acl.c \ fd.c \ filemap.c \ @@ -160,6 +161,7 @@ ipc.c \ ipcache.c \ $(LEAKFINDERSOURCE) \ + locrewrite.c \ logfile.c \ main.c \ mem.c \ @@ -172,7 +174,10 @@ Packer.c \ pconn.c \ peer_digest.c \ + peer_monitor.c \ peer_select.c \ + peer_sourcehash.c \ + peer_userhash.c \ protos.h \ redirect.c \ referer.c \ Index: squid/src/acl.c diff -u squid/src/acl.c:1.63 squid/src/acl.c:1.63.4.1 --- squid/src/acl.c:1.63 Fri Apr 28 04:10:50 2006 +++ squid/src/acl.c Mon May 15 18:01:31 2006 @@ -40,9 +40,7 @@ static void aclParseUserList(void **current); static void aclParseIpList(void *curlist); static void aclParseIntlist(void *curlist); -#if SQUID_SNMP static void aclParseWordList(void *curlist); -#endif static void aclParseProtoList(void *curlist); static void aclParseMethodList(void *curlist); static void aclParseTimeSpec(void *curlist); @@ -58,9 +56,7 @@ static int aclMatchIp(void *dataptr, struct in_addr c); static int aclMatchDomainList(void *dataptr, const char *); static int aclMatchIntegerRange(intrange * data, int i); -#if SQUID_SNMP static int aclMatchWordList(wordlist *, const char *); -#endif static void aclParseUserMaxIP(void *data); static void aclDestroyUserMaxIP(void *data); static wordlist *aclDumpUserMaxIP(void *data); @@ -144,6 +140,8 @@ if (!strcmp(s, "ident_regex")) return ACL_IDENT_REGEX; #endif + if (!strncmp(s, "type", 5)) + return ACL_TYPE; if (!strncmp(s, "proto", 5)) return ACL_PROTO; if (!strcmp(s, "method")) @@ -186,6 +184,8 @@ return ACL_EXTERNAL; if (!strcmp(s, "urllogin")) return ACL_URLLOGIN; + if (!strcmp(s, "urlgroup")) + return ACL_URLGROUP; return ACL_NONE; } @@ -224,6 +224,8 @@ if (type == ACL_IDENT_REGEX) return "ident_regex"; #endif + if (type == ACL_TYPE) + return "type"; if (type == ACL_PROTO) return "proto"; if (type == ACL_METHOD) @@ -266,6 +268,8 @@ return "external"; if (type == ACL_URLLOGIN) return "urllogin"; + if (type == ACL_URLGROUP) + return "urlgroup"; return "ERROR"; } @@ -346,6 +350,36 @@ } } +static void +aclParseType(void *current) +{ + acl_request_type **p = current; + acl_request_type *type; + char *t = NULL; + if (!*p) + *p = memAllocate(MEM_ACL_REQUEST_TYPE); + type = *p; + while ((t = strtokFile())) { + if (strcmp(t, "accelerated") == 0) { + type->accelerated = 1; + continue; + } + if (strcmp(t, "accel") == 0) { + type->accelerated = 1; + continue; + } + if (strcmp(t, "internal") == 0) { + type->internal = 1; + continue; + } + if (strcmp(t, "auth") == 0) { + type->internal = 1; + continue; + } + fatalf("unknown acl type argument '%s'\n", t); + } +} + /* * Decode a ascii representation (asc) of a IP adress, and place * adress and netmask information in addr and mask. @@ -706,7 +740,6 @@ return W; } -#if SQUID_SNMP static void aclParseWordList(void *curlist) { @@ -714,7 +747,6 @@ while ((t = strtokFile())) wordlistAdd(curlist, t); } -#endif static void aclParseUserList(void **current) @@ -878,6 +910,9 @@ aclParseRegexList(&A->data); break; #endif + case ACL_TYPE: + aclParseType(&A->data); + break; case ACL_PROTO: aclParseProtoList(&A->data); break; @@ -923,6 +958,9 @@ case ACL_EXTERNAL: aclParseExternal(&A->data); break; + case ACL_URLGROUP: + aclParseWordList(&A->data); + break; case ACL_NONE: case ACL_ENUM_MAX: fatal("Bad ACL type"); @@ -1493,7 +1531,6 @@ return 0; } -#if SQUID_SNMP static int aclMatchWordList(wordlist * w, const char *word) { @@ -1506,7 +1543,16 @@ } return 0; } -#endif + +static int +aclMatchType(acl_request_type * type, request_t * request) +{ + if (type->accelerated && request->flags.accelerated) + return 1; + if (type->internal && request->flags.internal) + return 1; + return 0; +} int aclAuthenticated(aclCheck_t * checklist) @@ -1578,6 +1624,7 @@ case ACL_DST_IP: case ACL_MAX_USER_IP: case ACL_METHOD: + case ACL_TYPE: case ACL_PROTO: case ACL_PROXY_AUTH: case ACL_PROXY_AUTH_REGEX: @@ -1735,6 +1782,8 @@ } /* NOTREACHED */ #endif + case ACL_TYPE: + return aclMatchType(ae->data, r); case ACL_PROTO: return aclMatchInteger(ae->data, r->protocol); /* NOTREACHED */ @@ -1824,6 +1873,11 @@ case ACL_EXTERNAL: return aclMatchExternal(ae->data, checklist); /* NOTREACHED */ + case ACL_URLGROUP: + if (!checklist->request->urlgroup) + return 0; + return aclMatchWordList(ae->data, checklist->request->urlgroup); + /* NOTREACHED */ case ACL_NONE: case ACL_ENUM_MAX: break; @@ -2238,6 +2292,11 @@ memFree(d, MEM_ACL_USER_DATA); } +static void +aclDestroyType(acl_request_type * type) +{ + memFree(type, MEM_ACL_REQUEST_TYPE); +} void aclDestroyAcls(acl ** head) @@ -2291,6 +2350,9 @@ case ACL_REQ_MIME_TYPE: aclDestroyRegexList(a->data); break; + case ACL_TYPE: + aclDestroyType(a->data); + break; case ACL_REP_HEADER: case ACL_REQ_HEADER: aclDestroyHeader(a->data); @@ -2315,6 +2377,9 @@ case ACL_EXTERNAL: aclDestroyExternal(&a->data); break; + case ACL_URLGROUP: + wordlistDestroy((wordlist **) & a->data); + break; case ACL_NONE: case ACL_ENUM_MAX: debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type); @@ -2673,6 +2738,17 @@ return W; } +static wordlist * +aclDumpType(acl_request_type * type) +{ + wordlist *W = NULL; + if (type->accelerated) + wordlistAdd(&W, "accelerated"); + if (type->internal) + wordlistAdd(&W, "internal"); + return W; +} + wordlist * aclDumpGeneric(const acl * a) { @@ -2722,6 +2798,8 @@ case ACL_URL_PORT: case ACL_MY_PORT: return aclDumpIntRangeList(a->data); + case ACL_TYPE: + return aclDumpType(a->data); case ACL_PROTO: return aclDumpProtoList(a->data); case ACL_METHOD: @@ -2732,6 +2810,8 @@ #endif case ACL_EXTERNAL: return aclDumpExternal(a->data); + case ACL_URLGROUP: + return wordlistDup(a->data); case ACL_NONE: case ACL_ENUM_MAX: break; Index: squid/src/cache_cf.c diff -u squid/src/cache_cf.c:1.59 squid/src/cache_cf.c:1.59.2.1 --- squid/src/cache_cf.c:1.59 Mon May 15 15:50:48 2006 +++ squid/src/cache_cf.c Mon May 15 18:01:31 2006 @@ -102,10 +102,16 @@ static void parse_denyinfo(acl_deny_info_list ** var); static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var); static void free_denyinfo(acl_deny_info_list ** var); +#if CURRENTLY_UNUSED static void parse_sockaddr_in_list(sockaddr_in_list **); static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *); static void free_sockaddr_in_list(sockaddr_in_list **); static int check_null_sockaddr_in_list(const sockaddr_in_list *); +#endif /* CURRENTLY_UNUSED */ +static void parse_http_port_list(http_port_list **); +static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *); +static void free_http_port_list(http_port_list **); +static int check_null_http_port_list(const http_port_list *); #if USE_SSL static void parse_https_port_list(https_port_list **); static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *); @@ -333,7 +339,6 @@ static void configDoConfigure(void) { - LOCAL_ARRAY(char, buf, BUFSIZ); memset(&Config2, '\0', sizeof(SquidConfig2)); /* init memory as early as possible */ memConfigure(); @@ -361,16 +366,17 @@ if (Config.dnsChildren < 1) fatal("No dnsservers allocated"); #endif - if (Config.Program.redirect) { - if (Config.redirectChildren < 1) { - Config.redirectChildren = 0; - wordlistDestroy(&Config.Program.redirect); + if (Config.Program.url_rewrite.command) { + if (Config.Program.url_rewrite.children < 1) { + Config.Program.url_rewrite.children = 0; + wordlistDestroy(&Config.Program.url_rewrite.command); } } - if (Config.Accel.host) { - snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port); - Config2.Accel.prefix = xstrdup(buf); - Config2.Accel.on = 1; + if (Config.Program.location_rewrite.command) { + if (Config.Program.location_rewrite.children < 1) { + Config.Program.location_rewrite.children = 0; + wordlistDestroy(&Config.Program.location_rewrite.command); + } } if (Config.appendDomain) if (*Config.appendDomain != '.') @@ -378,13 +384,6 @@ if (Config.errHtmlText == NULL) Config.errHtmlText = xstrdup(null_string); storeConfigure(); - if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual")) { - vhost_mode = 1; - if (Config.Accel.port == 0) - vport_mode = 1; - } - if (Config.Sockaddr.http == NULL) - fatal("No http_port specified!"); snprintf(ThisCache, sizeof(ThisCache), "%s:%d (%s)", uniqueHostname(), (int) ntohs(Config.Sockaddr.http->s.sin_port), @@ -418,8 +417,10 @@ #if USE_UNLINKD requirePathnameExists("unlinkd_program", Config.Program.unlinkd); #endif - if (Config.Program.redirect) - requirePathnameExists("redirect_program", Config.Program.redirect->key); + if (Config.Program.url_rewrite.command) + requirePathnameExists("url_rewrite_program", Config.Program.url_rewrite.command->key); + if (Config.Program.location_rewrite.command) + requirePathnameExists("location_rewrite_program", Config.Program.location_rewrite.command->key); requirePathnameExists("Icon Directory", Config.icons.directory); requirePathnameExists("Error Directory", Config.errorDirectory); #if HTTP_VIOLATIONS @@ -1510,7 +1511,7 @@ d->domain); } if (p->access) { - snprintf(xname, 128, "cache_peer_access %s", p->host); + snprintf(xname, 128, "cache_peer_access %s", p->name); dump_acl_access(entry, xname, p->access); } for (t = p->typelist; t; t = t->next) { @@ -1534,9 +1535,11 @@ p->icp.port = CACHE_ICP_PORT; p->weight = 1; p->stats.logged_state = PEER_ALIVE; + p->monitor.state = PEER_ALIVE; if ((token = strtok(NULL, w_space)) == NULL) self_destruct(); p->host = xstrdup(token); + p->name = xstrdup(token); if ((token = strtok(NULL, w_space)) == NULL) self_destruct(); p->type = parseNeighborType(token); @@ -1567,6 +1570,10 @@ p->options.default_parent = 1; } else if (!strcasecmp(token, "round-robin")) { p->options.roundrobin = 1; + } else if (!strcasecmp(token, "userhash")) { + p->options.userhash = 1; + } else if (!strcasecmp(token, "sourcehash")) { + p->options.sourcehash = 1; #if USE_HTCP } else if (!strcasecmp(token, "htcp")) { p->options.htcp = 1; @@ -1597,11 +1604,40 @@ p->options.allow_miss = 1; } else if (!strncasecmp(token, "max-conn=", 9)) { p->max_conn = atoi(token + 9); + } else if (!strcasecmp(token, "originserver")) { + p->options.originserver = 1; + } else if (!strncasecmp(token, "name=", 5)) { + safe_free(p->name); + if (token[5]) + p->name = xstrdup(token + 5); + } else if (!strncasecmp(token, "monitorurl=", 11)) { + safe_free(p->monitor.url); + if (token[11]) + p->monitor.url = xstrdup(token + 11); + } else if (!strncasecmp(token, "monitorsize=", 12)) { + p->monitor.min = atoi(token + 12); + p->monitor.max = -1; + if (strchr(token + 12, ',')) + token = strchr(token + 12, ','); + else + token = strchr(token + 12, '-'); + if (token) + p->monitor.max = atoi(token + 1); + } else if (!strncasecmp(token, "monitorinterval=", 16)) { + p->monitor.interval = atoi(token + 16); + } else if (!strncasecmp(token, "monitortimeout=", 15)) { + p->monitor.timeout = atoi(token + 15); + } else if (!strncasecmp(token, "forceddomain=", 13)) { + safe_free(p->domain); + if (token[13]) + p->domain = xstrdup(token + 13); } else { debug(3, 0) ("parse_peer: token='%s'\n", token); self_destruct(); } } + if (peerFindByName(p->name)) + fatalf("ERROR: cache_peer %s specified twice\n", p->name); if (p->weight < 1) p->weight = 1; p->icp.version = ICP_VERSION_CURRENT; @@ -2370,6 +2406,62 @@ storeAppendPrintf(entry, "\n"); } +static void +parse_errormap(errormap ** head) +{ + errormap *m = xcalloc(1, sizeof(*m)); + char *url = strtok(NULL, w_space); + char *token; + struct error_map_entry **tail = &m->map; + if (!url) + self_destruct(); + m->url = xstrdup(url); + while ((token = strtok(NULL, w_space))) { + struct error_map_entry *e = xcalloc(1, sizeof(*e)); + e->value = xstrdup(token); + e->status = atoi(token); + if (!e->status) + e->status = -errorPageId(token); + if (!e->status) + debug(15, 0) ("WARNING: Unknown errormap code: %s\n", token); + *tail = e; + tail = &e->next; + } + while (*head) + head = &(*head)->next; + *head = m; +} + +static void +dump_errormap(StoreEntry * entry, const char *name, errormap * map) +{ + while (map) { + struct error_map_entry *me; + storeAppendPrintf(entry, "%s %s", + name, map->url); + for (me = map->map; me; me = me->next) + storeAppendPrintf(entry, " %s", me->value); + storeAppendPrintf(entry, "\n"); + map = map->next; + } +} + +static void +free_errormap(errormap ** head) +{ + while (*head) { + errormap *map = *head; + *head = map->next; + while (map->map) { + struct error_map_entry *me = map->map; + map->map = me->next; + safe_free(me->value); + safe_free(me); + } + safe_free(map->url); + safe_free(map); + } +} #include "cf_parser.h" @@ -2390,6 +2482,10 @@ return PEER_SIBLING; } +#if CURRENTLY_UNUSED +/* This code was previously used by http_port. Left as it really should + * be used by icp_port and htcp_port + */ static void parse_sockaddr_in_list(sockaddr_in_list ** head) { @@ -2457,22 +2553,15 @@ { return NULL == s; } +#endif /* CURRENTLY_UNUSED */ -#if USE_SSL static void -parse_https_port_list(https_port_list ** head) +parse_http_port_specification(http_port_list * s, char *token) { - char *token; - char *t; - char *host; + char *host = NULL; const struct hostent *hp; - unsigned short port; - https_port_list *s; - token = strtok(NULL, w_space); - if (!token) - self_destruct(); - host = NULL; - port = 0; + unsigned short port = 0; + char *t; if ((t = strchr(token, ':'))) { /* host:port */ host = token; @@ -2485,16 +2574,150 @@ } else { self_destruct(); } - s = xcalloc(1, sizeof(*s)); s->s.sin_port = htons(port); if (NULL == host) s->s.sin_addr = any_addr; else if (1 == safe_inet_addr(host, &s->s.sin_addr)) (void) 0; - else if ((hp = gethostbyname(host))) /* dont use ipcache */ + else if ((hp = gethostbyname(host))) { + /* dont use ipcache */ s->s.sin_addr = inaddrFromHostent(hp); - else + s->defaultsite = xstrdup(host); + } else + self_destruct(); +} + +static void +parse_http_port_option(http_port_list * s, char *token) +{ + if (strncmp(token, "defaultsite=", 12) == 0) { + safe_free(s->defaultsite); + s->defaultsite = xstrdup(token + 12); + s->accel = 1; + } else if (strncmp(token, "name=", 5) == 0) { + safe_free(s->name); + s->name = xstrdup(token + 5); + } else if (strcmp(token, "transparent") == 0) { + s->transparent = 1; + } else if (strcmp(token, "vhost") == 0) { + s->vhost = 1; + s->accel = 1; + } else if (strcmp(token, "vport") == 0) { + s->vport = ntohs(s->s.sin_port); + s->accel = 1; + } else if (strncmp(token, "vport=", 6) == 0) { + s->vport = atoi(token + 6); + s->accel = 1; + } else if (strncmp(token, "urlgroup=", 9) == 0) { + s->urlgroup = xstrdup(token + 9); + } else if (strncmp(token, "protocol=", 9) == 0) { + s->protocol = xstrdup(token + 9); + } else { + self_destruct(); + } +} + +static void +free_generic_http_port_data(http_port_list * s) +{ + safe_free(s->name); + safe_free(s->defaultsite); +} + +static void +cbdataFree_http_port(void *data) +{ + free_generic_http_port_data(data); +} + + +static void +parse_http_port_list(http_port_list ** head) +{ + CBDATA_TYPE(http_port_list); + char *token; + http_port_list *s; + CBDATA_INIT_TYPE_FREECB(http_port_list, cbdataFree_http_port); + token = strtok(NULL, w_space); + if (!token) self_destruct(); + s = cbdataAlloc(http_port_list); + s->protocol = xstrdup("http"); + parse_http_port_specification(s, token); + /* parse options ... */ + while ((token = strtok(NULL, w_space))) { + parse_http_port_option(s, token); + } + while (*head) + head = &(*head)->next; + *head = s; +} + +static void +dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s) +{ + storeAppendPrintf(e, "%s %s:%d", + n, + inet_ntoa(s->s.sin_addr), + ntohs(s->s.sin_port)); + if (s->defaultsite) + storeAppendPrintf(e, " defaultsite=%s", s->defaultsite); + if (s->transparent) + storeAppendPrintf(e, " transparent"); + if (s->vhost) + storeAppendPrintf(e, " vhost"); + if (s->vport) + storeAppendPrintf(e, " vport"); +} +static void +dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s) +{ + while (s) { + dump_generic_http_port(e, n, s); + storeAppendPrintf(e, "\n"); + s = s->next; + } +} + +static void +free_http_port_list(http_port_list ** head) +{ + http_port_list *s; + while ((s = *head) != NULL) { + *head = s->next; + cbdataFree(s); + } +} + +static int +check_null_http_port_list(const http_port_list * s) +{ + return NULL == s; +} + +#if USE_SSL +static void +cbdataFree_https_port(void *data) +{ + https_port_list *s = data; + free_generic_http_port_data(&s->http); + safe_free(s->cert); + safe_free(s->key); +} + +static void +parse_https_port_list(https_port_list ** head) +{ + CBDATA_TYPE(https_port_list); + char *token; + https_port_list *s; + CBDATA_INIT_TYPE_FREECB(https_port_list, cbdataFree_https_port); + token = strtok(NULL, w_space); + if (!token) + self_destruct(); + s = cbdataAlloc(https_port_list); + s->http.protocol = xstrdup("https"); + parse_http_port_specification(&s->http, token); /* parse options ... */ while ((token = strtok(NULL, w_space))) { if (strncmp(token, "cert=", 5) == 0) { @@ -2514,11 +2737,11 @@ safe_free(s->cipher); s->cipher = xstrdup(token + 7); } else { - self_destruct(); + parse_http_port_option(&s->http, token); } } while (*head) - head = &(*head)->next; + head = (https_port_list **) (&(*head)->http.next); *head = s; } @@ -2526,12 +2749,11 @@ dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s) { while (s) { - storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"", - n, - inet_ntoa(s->s.sin_addr), - ntohs(s->s.sin_port), - s->cert, - s->key); + dump_generic_http_port(e, n, &s->http); + if (s->cert) + storeAppendPrintf(e, " cert=%s", s->cert); + if (s->key) + storeAppendPrintf(e, " key=%s", s->key); if (s->version) storeAppendPrintf(e, " version=%d", s->version); if (s->options) @@ -2539,7 +2761,7 @@ if (s->cipher) storeAppendPrintf(e, " cipher=%s", s->cipher); storeAppendPrintf(e, "\n"); - s = s->next; + s = (https_port_list *) s->http.next; } } @@ -2548,10 +2770,8 @@ { https_port_list *s; while ((s = *head) != NULL) { - *head = s->next; - safe_free(s->cert); - safe_free(s->key); - safe_free(s); + *head = (https_port_list *) s->http.next; + cbdataFree(s); } } @@ -2568,7 +2788,6 @@ void configFreeMemory(void) { - safe_free(Config2.Accel.prefix); free_all(); } Index: squid/src/cf.data.pre diff -u squid/src/cf.data.pre:1.95 squid/src/cf.data.pre:1.95.2.1 --- squid/src/cf.data.pre:1.95 Mon May 15 15:50:48 2006 +++ squid/src/cf.data.pre Mon May 15 18:01:31 2006 @@ -54,14 +54,14 @@ COMMENT_END NAME: http_port ascii_port -TYPE: sockaddr_in_list +TYPE: http_port_list DEFAULT: none DEFAULT_IF_NONE: @DEFAULT_HTTP_PORT@ LOC: Config.Sockaddr.http DOC_START - Usage: port - hostname:port - 1.2.3.4:port + Usage: port [options] + hostname:port [options] + 1.2.3.4:port [options] The socket addresses where Squid will listen for HTTP client requests. You may specify multiple socket addresses. @@ -83,6 +83,19 @@ You may specify multiple socket addresses on multiple lines. + options are: + transparent Support for transparent proxies + vhost Accelerator using Host directive + vport Accelerator with IP virtual host support + vport= As above, but uses specified port number + rather than the http_port number. + defaultsite= Main web site name for accelerators. + urlgroup= Default urlgroup to mark requests + with (see also acl urlgroup and + url_rewrite_program) + protocol= Protocol to reconstruct accelerated + requests with. Defaults to http. + If you run Squid on a dual-homed machine with an internal and an external interface we recommend you to specify the internal address:port in http_port. This way Squid will only be @@ -109,6 +122,15 @@ Options: + defaultsite= The name of the https site presented on + this port. + + urlgroup= Default urlgroup to mark requests with (see + also acl urlgroup and url_rewrite_program) + + protocol= Protocol to reconstruct accelerated requests + with. Defaults to https. + cert= Path to SSL certificate (PEM format) key= Path to SSL private key file (PEM format) @@ -276,6 +298,16 @@ max-conn htcp carp-load-factor + originserver + userhash + sourcehash + name=xxx + monitorurl=url + monitorsize=sizespec + monitorinterval=seconds + monitortimeout=seconds + group=name + forceddomain=name use 'proxy-only' to specify objects fetched from this cache should not be saved locally. @@ -373,7 +405,42 @@ cache as one participating in a CARP array. The 'f' values for all CARP parents must add up to 1.0. - + + 'originserver' causes this parent peer to be contacted as + a origin server. Meant to be used in accelerator setups. + + use 'userhash' to load-balance amongs a set of parents + based on the client proxy_auth or ident username. + + use 'sourcehash' to load-balanse amongs a set of parents + based on the client source ip. + + use 'name=xxx' if you have multiple peers on the same + host but different ports. This name can then be used to + differentiate the peers in cache_peer_access and similar + directives. + + use 'monitorurl=url' to have periodically request a given + URL from the peer, and only concider the peer as alive + if this monitoring is successful (default none) + + use 'monitorsize=min[-max]' to limit the size range of + 'monitorurl' replies considered valid. Defaults to 0 to + accept any size replies as valid. + + use 'monitorinterval=seconds' to change frequency of + how often the peer is monitored with 'monitorurl' + (default 300 for a 5 minute interval). If set to 0 + then monitoring is disabled even if a URL is defined. + + use 'monitortimeout=seconds' to change the timeout of + 'monitorurl'. Defaults to 'monitorinterval'. + + use 'forceddomain=name' to forcibly set the Host header + of requests forwarded to this peer. Useful in accelerator + setups where the server (peer) expects a certain domain + name and using redirectors to feed this domainname + is not feasible. NOTE: non-ICP/HTCP neighbors must be specified as 'parent'. DOC_END @@ -1309,22 +1376,36 @@ DOC_END -NAME: redirect_program +NAME: url_rewrite_program redirect_program TYPE: wordlist -LOC: Config.Program.redirect +LOC: Config.Program.url_rewrite.command DEFAULT: none DOC_START - Specify the location of the executable for the URL redirector. + Specify the location of the executable for the URL rewriter. Since they can perform almost any function there isn't one included. - See the FAQ (section 15) for information on how to write one. - By default, a redirector is not used. -DOC_END + For each requested URL rewriter will receive on line with the format + + URL client_ip "/" fqdn user method urlgroup + + And the rewriter may return a rewritten URL. The other components of + the request line does not need to be returned (ignored if they are). + + The rewriter can also indicate that a client-side redirect should + be performed to the new URL. This is done by prefixing the returned + URL with "301:" (moved permanently) or 302: (moved temporarily). + + It can also return a "urlgroup" that can subsequently be matched + in cache_peer_access and similar ACL driven rules. An urlgroup is + returned by prefixing the returned url with "!urlgroup!" + + By default, a URL rewriter is not used. +DOC_END -NAME: redirect_children +NAME: url_rewrite_children redirect_children TYPE: int DEFAULT: 5 -LOC: Config.redirectChildren +LOC: Config.Program.url_rewrite.children DOC_START The number of redirector processes to spawn. If you start too few Squid will have to wait for them to process a backlog of @@ -1332,7 +1413,7 @@ and other system resources. DOC_END -NAME: redirect_rewrites_host_header +NAME: url_rewrite_host_header redirect_rewrites_host_header TYPE: onoff DEFAULT: on LOC: Config.onoff.redir_rewrites_host @@ -1340,18 +1421,64 @@ By default Squid rewrites any Host: header in redirected requests. If you are running an accelerator this may not be a wanted effect of a redirector. + + WARNING: Entries are cached on the result of the URL rewriting + process, so be careful if you have domain-virtual hosts. DOC_END -NAME: redirector_access +NAME: url_rewrite_access redirector_access TYPE: acl_access DEFAULT: none -LOC: Config.accessList.redirector +LOC: Config.accessList.url_rewrite DOC_START If defined, this access list specifies which requests are sent to the redirector processes. By default all requests are sent. DOC_END +NAME: location_rewrite_program +TYPE: wordlist +LOC: Config.Program.location_rewrite.command +DEFAULT: none +DOC_START + Specify the location of the executable for the Location rewriter, + used to rewrite server generated redirects. Usually used in + conjunction with a url_rewrite_program + + For each Location header received the location rewriter will receive + one line with the format: + + location URL requested URL urlgroup + + And the rewriter may return a rewritten Location URL or a blank line. + The other components of the request line does not need to be returned + (ignored if they are). + + By default, a Location rewriter is not used. +DOC_END + +NAME: location_rewrite_children +TYPE: int +DEFAULT: 5 +LOC: Config.Program.location_rewrite.children +DOC_START + The number of location rewriting processes to spawn. If you start + too few Squid will have to wait for them to process a backlog of + URLs, slowing it down. If you start too many they will use RAM + and other system resources. +DOC_END + +NAME: location_rewrite_access +TYPE: acl_access +DEFAULT: none +LOC: Config.accessList.location_rewrite +DOC_START + If defined, this access list specifies which requests are + sent to the location rewriting processes. By default all Location + headers are sent. +DOC_END + + NAME: auth_param TYPE: authparam LOC: Config.authConfig @@ -2246,6 +2373,9 @@ # external ACL lookup via a helper class defined by the # external_acl_type directive. + acl urlgroup group1 ... + # match against the urlgroup as indicated by redirectors + Examples: acl macaddress arp 09:00:2b:23:45:67 acl myexample dst_as 1241 @@ -2326,6 +2456,17 @@ NOCOMMENT_END DOC_END +NAME: http_access2 +TYPE: acl_access +LOC: Config.accessList.http2 +DEFAULT: none +DOC_START + Allowing or Denying access based on defined access lists + + Identical to http_access, but runs after redirectors. If not set + then only http_access is used. +DOC_END + NAME: http_reply_access TYPE: acl_access LOC: Config.accessList.reply @@ -2748,89 +2889,6 @@ ----------------------------------------------------------------------------- COMMENT_END -NAME: httpd_accel_host -TYPE: string -LOC: Config.Accel.host -DEFAULT: none -DOC_NONE - -NAME: httpd_accel_port -TYPE: ushort -LOC: Config.Accel.port -DEFAULT: 80 -DOC_START - If you want to run Squid as an httpd accelerator, define the - host name and port number where the real HTTP server is. - - If you want IP based virtual host support specify the - hostname as "virtual". This will make Squid use the IP address - where it accepted the request as hostname in the URL. - - If you want virtual port support specify the port as "0". - - NOTE: enabling httpd_accel_host disables proxy-caching and - ICP. If you want these features enabled also, set - the 'httpd_accel_with_proxy' option. -DOC_END - -NAME: httpd_accel_single_host -COMMENT: on|off -TYPE: onoff -LOC: Config.Accel.single_host -DEFAULT: off -DOC_START - If you are running Squid as an accelerator and have a single backend - server set this to on. This causes Squid to forward the request - to this server, regardless of what any redirectors or Host headers - say. - - Leave this at off if you have multiple backend servers, and use a - redirector (or host table or private DNS) to map the requests to the - appropriate backend servers. Note that the mapping needs to be a - 1-1 mapping between requested and backend (from redirector) domain - names or caching will fail, as caching is performed using the - URL returned from the redirector. - - See also redirect_rewrites_host_header. -DOC_END - -NAME: httpd_accel_with_proxy -COMMENT: on|off -TYPE: onoff -DEFAULT: off -LOC: Config.onoff.accel_with_proxy -DOC_START - If you want to use Squid as both a local httpd accelerator - and as a proxy, change this to 'on'. Note however your - proxy users may have trouble to reach the accelerated domains - unless their browsers are configured not to use this proxy for - those domains (for example via the no_proxy browser configuration - setting) -DOC_END - -NAME: httpd_accel_uses_host_header -COMMENT: on|off -TYPE: onoff -DEFAULT: off -LOC: Config.onoff.accel_uses_host_header -DOC_START - HTTP/1.1 requests include a Host: header which is basically the - hostname from the URL. The Host: header is used for domain based - virtual hosts. If your accelerator needs to provide domain based - virtual hosts on the same IP address you will need to turn this - on. - - Note Squid does NOT check the value of the Host header matches - any of your accelerated server, so it may open a big security hole - unless you take care to set up access controls proper. We recommend - this option remain disabled unless you are sure of what you - are doing. - - However, you will need to enable this option if you run Squid - as a transparent proxy. Otherwise, virtual servers which - require the Host: header will not be properly cached. -DOC_END - NAME: httpd_accel_no_pmtu_disc COMMENT: on|off TYPE: onoff @@ -2913,6 +2971,45 @@ the default buffer size. DOC_END +NAME: error_map +TYPE: errormap +LOC: Config.errorMapList +DEFAULT: none +DOC_START + Map errors to custom messages + + error_map message_url http_status ... + + http_status ... is a list of HTTP status codes or Squid error + messages. + + Use in accelerators to substitute the error messages returned + by servers with other custom errors. + + error_map http://your.server/error/404.shtml 404 + + Requests for error messages is a GET request for the configured + URL with the following special headers + + X-Error-Status: The received HTTP status code (i.e. 404) + X-Request-URI: The requested URI where the error occurred + + In Addition the following headers are forwarded from the client + request: + + User-Agent, Cookie, X-Forwarded-For, Via, Authorization, + Accept, Referer + + And the following headers from the server reply: + + Server, Via, Location, Content-Location + + The reply returned to the client will carry the original HTTP + headers from the real error message, but with the reply body + of the configured error message. + +DOC_END + NAME: err_html_text TYPE: eol LOC: Config.errHtmlText @@ -2928,7 +3025,6 @@ insert a %L tag in the error template file. DOC_END - NAME: deny_info TYPE: denyinfo LOC: Config.denyInfoList @@ -2995,6 +3091,16 @@ reduced memory thrashing in your malloc library. DOC_END +NAME: via +COMMENT: on|off +TYPE: onoff +DEFAULT: on +LOC: Config.onoff.via +DOC_START + If set (default), Squid will include a Via header in requests and + replies. +DOC_END + NAME: forwarded_for COMMENT: on|off TYPE: onoff @@ -3012,6 +3118,7 @@ X-Forwarded-For: unknown DOC_END + NAME: log_icp_queries COMMENT: on|off TYPE: onoff Index: squid/src/client_side.c diff -u squid/src/client_side.c:1.85 squid/src/client_side.c:1.85.2.1 --- squid/src/client_side.c:1.85 Mon May 15 15:50:48 2006 +++ squid/src/client_side.c Mon May 15 18:01:31 2006 @@ -125,12 +125,12 @@ static void clientCheckNoCacheDone(int answer, void *data); static STCB clientHandleIMSReply; static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request); -static int checkAccelOnly(clientHttpRequest *); #if USE_IDENT static IDCB clientIdentDone; #endif static int clientOnlyIfCached(clientHttpRequest * http); static STCB clientSendMoreData; +static STCB clientSendMoreHeaderData; static STCB clientCacheHit; static void clientSetKeepaliveFlag(clientHttpRequest *); static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); @@ -148,27 +148,11 @@ static int clientRequestBodyTooLarge(squid_off_t clen); static void clientProcessBody(ConnStateData * conn); static void clientEatRequestBody(clientHttpRequest *); +static void clientAccessCheckDone2(int answer, void *data); +static void clientAccessCheck2(void *data); static BODY_HANDLER clientReadBody; static void clientAbortBody(request_t * req); -static int -checkAccelOnly(clientHttpRequest * http) -{ - /* return TRUE if someone makes a proxy request to us and - * we are in httpd-accel only mode */ - if (!Config2.Accel.on) - return 0; - if (Config.onoff.accel_with_proxy) - return 0; - if (http->request->protocol == PROTO_CACHEOBJ) - return 0; - if (http->flags.accel) - return 0; - if (http->request->method == METHOD_PURGE) - return 0; - return 1; -} - #if USE_IDENT static void clientIdentDone(const char *ident, void *data) @@ -203,16 +187,22 @@ clientAccessCheck(void *data) { clientHttpRequest *http = data; - if (checkAccelOnly(http)) { - /* deny proxy requests in accel_only mode */ - debug(33, 1) ("clientAccessCheck: proxy request denied in accel_only mode\n"); - clientAccessCheckDone(ACCESS_DENIED, http); - return; - } http->acl_checklist = clientAclChecklistCreate(Config.accessList.http, http); aclNBCheck(http->acl_checklist, clientAccessCheckDone, http); } +static void +clientAccessCheck2(void *data) +{ + clientHttpRequest *http = data; + if (Config.accessList.http2 && !http->redirect.status) { + http->acl_checklist = clientAclChecklistCreate(Config.accessList.http2, http); + aclNBCheck(http->acl_checklist, clientAccessCheckDone2, http); + } else { + clientCheckNoCache(http); + } +} + /* * returns true if client specified that the object must come from the cache * without contacting origin server @@ -243,7 +233,7 @@ delaySetStoreClient(h->sc, delayClient(h)); #endif storeClientCopy(h->sc, e, 0, 0, CLIENT_SOCK_SZ, - memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, h); + memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreHeaderData, h); return e; } @@ -300,7 +290,69 @@ page_id = ERR_ACCESS_DENIED; } err = errorCon(page_id, status); - err->request = requestLink(http->request); + err->request = requestLink(http->orig_request); + err->src_addr = http->conn->peer.sin_addr; + if (http->conn->auth_user_request) + err->auth_user_request = http->conn->auth_user_request; + else if (http->request->auth_user_request) + err->auth_user_request = http->request->auth_user_request; + /* lock for the error state */ + if (err->auth_user_request) + authenticateAuthUserRequestLock(err->auth_user_request); + err->callback_data = NULL; + errorAppendEntry(http->entry, err); + } +} + +static void +clientAccessCheckDone2(int answer, void *data) +{ + clientHttpRequest *http = data; + err_type page_id; + http_status status; + ErrorState *err = NULL; + char *proxy_auth_msg = NULL; + debug(33, 2) ("The request %s %s is %s, because it matched '%s'\n", + RequestMethodStr[http->request->method], http->uri, + answer == ACCESS_ALLOWED ? "ALLOWED" : "DENIED", + AclMatchedName ? AclMatchedName : "NO ACL's"); + proxy_auth_msg = authenticateAuthUserRequestMessage(http->conn->auth_user_request ? http->conn->auth_user_request : http->request->auth_user_request); + http->acl_checklist = NULL; + if (answer == ACCESS_ALLOWED) { + clientCheckNoCache(http); + } else { + debug(33, 5) ("Access Denied: %s\n", http->uri); + debug(33, 5) ("AclMatchedName = %s\n", + AclMatchedName ? AclMatchedName : ""); + debug(33, 5) ("Proxy Auth Message = %s\n", + proxy_auth_msg ? proxy_auth_msg : ""); + /* + * NOTE: get page_id here, based on AclMatchedName because + * if USE_DELAY_POOLS is enabled, then AclMatchedName gets + * clobbered in the clientCreateStoreEntry() call + * just below. Pedro Ribeiro + */ + page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName); + http->log_type = LOG_TCP_DENIED; + http->entry = clientCreateStoreEntry(http, http->request->method, + null_request_flags); + if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) { + if (!http->flags.accel) { + /* Proxy authorisation needed */ + status = HTTP_PROXY_AUTHENTICATION_REQUIRED; + } else { + /* WWW authorisation needed */ + status = HTTP_UNAUTHORIZED; + } + if (page_id == ERR_NONE) + page_id = ERR_CACHE_ACCESS_DENIED; + } else { + status = HTTP_FORBIDDEN; + if (page_id == ERR_NONE) + page_id = ERR_ACCESS_DENIED; + } + err = errorCon(page_id, status); + err->request = requestLink(http->orig_request); err->src_addr = http->conn->peer.sin_addr; if (http->conn->auth_user_request) err->auth_user_request = http->conn->auth_user_request; @@ -329,12 +381,12 @@ clientRedirectStart(clientHttpRequest * http) { debug(33, 5) ("clientRedirectStart: '%s'\n", http->uri); - if (Config.Program.redirect == NULL) { + if (Config.Program.url_rewrite.command == NULL) { clientRedirectDone(http, NULL); return; } - if (Config.accessList.redirector) { - http->acl_checklist = clientAclChecklistCreate(Config.accessList.redirector, http); + if (Config.accessList.url_rewrite) { + http->acl_checklist = clientAclChecklistCreate(Config.accessList.url_rewrite, http); aclNBCheck(http->acl_checklist, clientRedirectAccessCheckDone, http); } else { redirectStart(http, clientRedirectDone, http); @@ -347,12 +399,24 @@ clientHttpRequest *http = data; request_t *new_request = NULL; request_t *old_request = http->request; + const char *urlgroup = http->conn->port->urlgroup; debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->uri, result ? result : "NULL"); assert(http->redirect_state == REDIRECT_PENDING); http->redirect_state = REDIRECT_DONE; if (result) { - http_status status = (http_status) atoi(result); + http_status status; + if (*result == '!') { + char *t; + if ((t = strchr(result + 1, '!')) != NULL) { + urlgroup = result + 1; + *t++ = '\0'; + result = t; + } else { + debug(33, 1) ("clientRedirectDone: bad input: %s\n", result); + } + } + status = (http_status) atoi(result); if (status == HTTP_MOVED_PERMANENTLY || status == HTTP_MOVED_TEMPORARILY || status == HTTP_SEE_OTHER @@ -361,12 +425,14 @@ if ((t = strchr(result, ':')) != NULL) { http->redirect.status = status; http->redirect.location = xstrdup(t + 1); + goto redirect_parsed; } else { debug(33, 1) ("clientRedirectDone: bad input: %s\n", result); } } else if (strcmp(result, http->uri)) new_request = urlParse(old_request->method, result); } + redirect_parsed: if (new_request) { safe_free(http->uri); http->uri = xstrdup(urlCanonical(new_request)); @@ -390,13 +456,20 @@ new_request->content_length = old_request->content_length; requestUnlink(old_request); http->request = requestLink(new_request); - } + } else { + /* Don't mess with urlgroup on internal request */ + if (old_request->flags.internal) + urlgroup = NULL; + } + safe_free(http->request->urlgroup); /* only paranoia. should not happen */ + if (urlgroup && *urlgroup) + http->request->urlgroup = xstrdup(urlgroup); clientInterpretRequestHeaders(http); #if HEADERS_LOG headersLog(0, 1, request->method, request); #endif fd_note(http->conn->fd, http->uri); - clientCheckNoCache(http); + clientAccessCheck2(http); } static void @@ -611,10 +684,10 @@ http->out.offset, CLIENT_SOCK_SZ, buf, - clientSendMoreData, + clientSendMoreHeaderData, http); } else { - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } } @@ -664,7 +737,7 @@ if (!Config2.onoff.enable_purge) { http->log_type = LOG_TCP_DENIED; err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN); - err->request = requestLink(http->request); + err->request = requestLink(http->orig_request); err->src_addr = http->conn->peer.sin_addr; http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); errorAppendEntry(http->entry, err); @@ -931,8 +1004,12 @@ storeUnlockObject(e); } requestUnlink(http->request); + http->request = NULL; + requestUnlink(http->orig_request); + http->orig_request = NULL; if (http->reply) httpReplyDestroy(http->reply); + http->reply = NULL; assert(http != http->next); assert(http->conn->chr != NULL); /* Unlink us from the clients request list */ @@ -1483,6 +1560,18 @@ } if (!Config.onoff.client_pconns && !request->flags.must_keepalive) request->flags.proxy_keepalive = 0; + /* Append Via */ + { + LOCAL_ARRAY(char, bbuf, MAX_URL + 32); + String strVia = httpHeaderGetList(hdr, HDR_VIA); + snprintf(bbuf, sizeof(bbuf), "%d.%d %s", + rep->sline.version.major, + rep->sline.version.minor, ThisCache); + strListAdd(&strVia, bbuf, ','); + httpHeaderDelById(hdr, HDR_VIA); + httpHeaderPutStr(hdr, HDR_VIA, strBuf(strVia)); + stringClean(&strVia); + } /* Signal keep-alive if needed */ httpHeaderPutStr(hdr, http->flags.accel ? HDR_CONNECTION : HDR_PROXY_CONNECTION, @@ -1631,13 +1720,18 @@ return; } http->flags.hit = 1; - if (checkNegativeHit(e) + if (EBIT_TEST(e->flags, ENTRY_NEGCACHED)) { + if (checkNegativeHit(e) #if HTTP_VIOLATIONS - && !r->flags.nocache_hack + && !r->flags.nocache_hack #endif - ) { - http->log_type = LOG_TCP_NEGATIVE_HIT; - clientSendMoreData(data, buf, size); + ) { + http->log_type = LOG_TCP_NEGATIVE_HIT; + clientSendMoreHeaderData(data, buf, size); + } else { + http->log_type = LOG_TCP_MISS; + clientProcessMiss(http); + } } else if (!Config.onoff.offline && refreshCheckHTTP(e, r) && !http->flags.internal) { debug(33, 5) ("clientCacheHit: in refreshCheck() block\n"); /* @@ -1693,7 +1787,7 @@ clientProcessMiss(http); } else if (modifiedSince(e, http->request)) { http->log_type = LOG_TCP_IMS_HIT; - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } else { time_t timestamp = e->timestamp; MemBuf mb = httpPacked304Reply(e->mem_obj->reply); @@ -1724,7 +1818,7 @@ http->log_type = LOG_TCP_MEM_HIT; else if (Config.onoff.offline) http->log_type = LOG_TCP_OFFLINE_HIT; - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } } @@ -1969,13 +2063,33 @@ } } +typedef struct { + clientHttpRequest *http; + char *buf; + ssize_t size; + const char *body_buf; + ssize_t body_size; +} clientCheckHeaderStateData; + +CBDATA_TYPE(clientCheckHeaderStateData); + +static void clientHttpLocationRewriteCheck(clientCheckHeaderStateData * state); +static void clientHttpLocationRewriteCheckDone(int answer, void *data); +static void clientHttpLocationRewrite(clientCheckHeaderStateData * state); +static void clientHttpLocationRewriteDone(void *data, char *reply); +static void clientHttpReplyAccessCheck(clientCheckHeaderStateData * state); +static void clientHttpReplyAccessCheckDone(int answer, void *data); +static void clientCheckErrorMap(clientCheckHeaderStateData * state); +static void clientCheckHeaderDone(clientCheckHeaderStateData * state); + /* * accepts chunk of a http message in buf, parses prefix, filters headers and * such, writes processed message to the client's socket */ static void -clientSendMoreData(void *data, char *buf, ssize_t size) +clientSendMoreHeaderData(void *data, char *buf, ssize_t size) { + clientCheckHeaderStateData *state; clientHttpRequest *http = data; StoreEntry *entry = http->entry; ConnStateData *conn = http->conn; @@ -1983,18 +2097,16 @@ HttpReply *rep = NULL; const char *body_buf = buf; squid_off_t body_size = size; - MemBuf mb; - squid_off_t check_size = 0; - debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); + debug(33, 5) ("clientSendMoreHeaderData: %s, %d bytes\n", http->uri, (int) size); assert(size <= CLIENT_SOCK_SZ); assert(http->request != NULL); dlinkDelete(&http->active, &ClientActiveRequests); dlinkAdd(http, &http->active, &ClientActiveRequests); - debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%ld \n", + debug(33, 5) ("clientSendMoreHeaderData: FD %d '%s', out.offset=%ld \n", fd, storeUrl(entry), (long int) http->out.offset); if (conn->chr != http) { /* there is another object in progress, defer this one */ - debug(33, 2) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); + debug(33, 2) ("clientSendMoreHeaderData: Deferring %s\n", storeUrl(entry)); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (http->request->flags.reset_tcp) { @@ -2017,115 +2129,282 @@ memFree(buf, MEM_CLIENT_SOCK_BUF); return; } - if (http->out.offset == 0) { - rep = http->reply = clientBuildReply(http, buf, size); - if (rep) { - aclCheck_t *ch; - int rv; - if (Config.onoff.log_mime_hdrs) { - size_t k; - if ((k = headersEnd(buf, size))) { - safe_free(http->al.headers.reply); - http->al.headers.reply = xcalloc(k + 1, 1); - xstrncpy(http->al.headers.reply, buf, k); - } - } - clientMaxBodySize(http->request, http, rep); - if (http->log_type != LOG_TCP_DENIED && clientReplyBodyTooLarge(http, rep->content_length)) { - ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_FORBIDDEN); - err->request = requestLink(http->request); - storeUnregister(http->sc, http->entry, http); - http->sc = NULL; - storeUnlockObject(http->entry); - http->log_type = LOG_TCP_DENIED; - http->entry = clientCreateStoreEntry(http, http->request->method, - null_request_flags); - errorAppendEntry(http->entry, err); - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } - body_size = size - rep->hdr_sz; - assert(body_size >= 0); - body_buf = buf + rep->hdr_sz; - http->range_iter.prefix_size = rep->hdr_sz; - debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n", - (int) body_size, rep->hdr_sz); - if (http->log_type != LOG_TCP_DENIED && !clientAlwaysAllowResponse(rep->sline.status)) { - ch = clientAclChecklistCreate(Config.accessList.reply, http); - ch->reply = rep; - rv = aclCheckFast(Config.accessList.reply, ch); - aclChecklistFree(ch); - ch = NULL; - debug(33, 2) ("The reply for %s %s is %s, because it matched '%s'\n", - RequestMethodStr[http->request->method], http->uri, - rv ? "ALLOWED" : "DENIED", - AclMatchedName ? AclMatchedName : "NO ACL's"); - if (!rv) { - ErrorState *err; - err_type page_id; - page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName); - if (page_id == ERR_NONE) - page_id = ERR_ACCESS_DENIED; - err = errorCon(page_id, HTTP_FORBIDDEN); - err->request = requestLink(http->request); - storeUnregister(http->sc, http->entry, http); - http->sc = NULL; - storeUnlockObject(http->entry); - http->log_type = LOG_TCP_DENIED; - http->entry = clientCreateStoreEntry(http, http->request->method, - null_request_flags); - errorAppendEntry(http->entry, err); - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } - } - } - /* reset range iterator */ - http->range_iter.pos = HttpHdrRangeInitPos; - } else if (!http->request->range) { - /* Avoid copying to MemBuf for non-range requests */ - /* Note, if we're here, then 'rep' is known to be NULL */ + assert(http->out.offset == 0); + rep = http->reply = clientBuildReply(http, buf, size); + if (!rep) { + /* Forward as HTTP/0.9 body with no reply */ + MemBuf mb; + memBufDefInit(&mb); + memBufAppend(&mb, buf, size); + memFree(buf, MEM_CLIENT_SOCK_BUF); http->out.offset += body_size; - comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); - /* NULL because clientWriteBodyComplete frees it */ + comm_write_mbuf(http->conn->fd, mb, clientWriteComplete, http); return; } - if (http->request->method == METHOD_HEAD) { - if (rep) { - /* do not forward body for HEAD replies */ - body_size = 0; - http->flags.done_copying = 1; + if (Config.onoff.log_mime_hdrs) { + safe_free(http->al.headers.reply); + http->al.headers.reply = xcalloc(rep->hdr_sz + 1, 1); + xstrncpy(http->al.headers.reply, buf, rep->hdr_sz); + } + clientMaxBodySize(http->request, http, rep); + if (http->log_type != LOG_TCP_DENIED && clientReplyBodyTooLarge(http, rep->content_length)) { + ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_FORBIDDEN); + err->request = requestLink(http->orig_request); + storeUnregister(http->sc, http->entry, http); + http->sc = NULL; + storeUnlockObject(http->entry); + http->log_type = LOG_TCP_DENIED; + http->entry = clientCreateStoreEntry(http, http->request->method, + null_request_flags); + errorAppendEntry(http->entry, err); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } + body_size = size - rep->hdr_sz; + body_buf = buf + rep->hdr_sz; + assert(body_size >= 0); + http->range_iter.prefix_size = rep->hdr_sz; + debug(33, 3) ("clientSendMoreHeaderData: Appending %d bytes after %d bytes of headers\n", + (int) body_size, rep->hdr_sz); + CBDATA_INIT_TYPE(clientCheckHeaderStateData); + state = cbdataAlloc(clientCheckHeaderStateData); + state->http = http; + cbdataLock(http); + state->buf = buf; + state->size = size; + state->body_buf = body_buf; + state->body_size = body_size; + clientHttpLocationRewriteCheck(state); +} + +static void +clientHttpLocationRewriteCheck(clientCheckHeaderStateData * state) +{ + HttpReply *rep = state->http->reply; + aclCheck_t *ch; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (!Config.Program.location_rewrite.command || !httpHeaderHas(&rep->header, HDR_LOCATION)) { + clientHttpLocationRewriteDone(state, NULL); + return; + } + if (Config.accessList.location_rewrite) { + ch = clientAclChecklistCreate(Config.accessList.location_rewrite, state->http); + ch->reply = state->http->reply; + aclNBCheck(ch, clientHttpLocationRewriteCheckDone, state); + } else { + clientHttpLocationRewriteCheckDone(ACCESS_ALLOWED, state); + } +} + +static void +clientHttpLocationRewriteCheckDone(int answer, void *data) +{ + clientCheckHeaderStateData *state = data; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (answer == ACCESS_ALLOWED) { + clientHttpLocationRewrite(state); + } else { + clientHttpLocationRewriteDone(state, NULL); + } +} + +static void +clientHttpLocationRewrite(clientCheckHeaderStateData * state) +{ + HttpReply *rep = state->http->reply; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (!httpHeaderHas(&rep->header, HDR_LOCATION)) + clientHttpLocationRewriteDone(state, NULL); + else + locationRewriteStart(rep, state->http, clientHttpLocationRewriteDone, state); +} + +static void +clientHttpLocationRewriteDone(void *data, char *reply) +{ + clientCheckHeaderStateData *state = data; + clientHttpRequest *http = state->http; + HttpReply *rep = http->reply; + ConnStateData *conn = http->conn; + if (!cbdataValid(http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (reply && *reply) { + httpHeaderDelById(&rep->header, HDR_LOCATION); + if (*reply == '/') { + /* We have to restore the URL as sent by the client */ + request_t *req = http->orig_request; + const char *proto = conn->port->protocol; + const char *host = httpHeaderGetStr(&req->header, HDR_HOST); + if (!host) + host = req->host; + httpHeaderPutStrf(&rep->header, HDR_LOCATION, "%s://%s%s", proto, host, reply); } else { - /* - * If we are here, then store_status == STORE_OK and it - * seems we have a HEAD repsponse which is missing the - * empty end-of-headers line (home.mira.net, phttpd/0.99.72 - * does this). Because clientBuildReply() fails we just - * call this reply a body, set the done_copying flag and - * continue... - */ - http->flags.done_copying = 1; - /* - * And as this is a malformed HTTP reply we cannot keep - * the connection persistent - */ - http->request->flags.proxy_keepalive = 0; + httpHeaderPutStr(&rep->header, HDR_LOCATION, reply); } } - /* write headers and/or body if any */ - assert(rep || (body_buf && body_size)); - /* init mb; put status line and headers if any */ - if (rep) { + clientHttpReplyAccessCheck(state); +} + +static void +clientHttpReplyAccessCheck(clientCheckHeaderStateData * state) +{ + aclCheck_t *ch; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (Config.accessList.reply && state->http->log_type != LOG_TCP_DENIED && !clientAlwaysAllowResponse(state->http->reply->sline.status)) { + ch = clientAclChecklistCreate(Config.accessList.reply, state->http); + ch->reply = state->http->reply; + aclNBCheck(ch, clientHttpReplyAccessCheckDone, state); + } else { + clientHttpReplyAccessCheckDone(ACCESS_ALLOWED, state); + } +} + +/* Handle error mapping. + * + * 1. Look up if there is a error map for the request + * 2. Start requesting the error URL + * 3. When headers are received, create a new reply structure and copy + * over the relevant headers (start with the headers from the original + * reply, and copy over Content-Length) + * 4. Make the new reply the current one + * 5. Detatch from the previous reply + * 6. Go to clientCheckHeaderDone, as if nothing had happened, but now + * fetching from the new reply. + */ +static void +clientHttpReplyAccessCheckDone(int answer, void *data) +{ + clientCheckHeaderStateData *state = data; + clientHttpRequest *http = state->http; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + debug(33, 2) ("The reply for %s %s is %s, because it matched '%s'\n", + RequestMethodStr[http->request->method], http->uri, + answer ? "ALLOWED" : "DENIED", + AclMatchedName ? AclMatchedName : "NO ACL's"); + if (answer != ACCESS_ALLOWED) { + ErrorState *err; + err_type page_id; + page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName); + if (page_id == ERR_NONE) + page_id = ERR_ACCESS_DENIED; + err = errorCon(page_id, HTTP_FORBIDDEN); + err->request = requestLink(http->orig_request); + storeUnregister(http->sc, http->entry, http); + http->sc = NULL; + storeUnlockObject(http->entry); + http->log_type = LOG_TCP_DENIED; + http->entry = clientCreateStoreEntry(http, http->request->method, + null_request_flags); + errorAppendEntry(http->entry, err); + return; + } + clientCheckErrorMap(state); +} + +static void +clientCheckErrorMapDone(StoreEntry * e, int body_offset, squid_off_t content_length, void *data) +{ + clientCheckHeaderStateData *state = data; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (e) { + clientHttpRequest *http = state->http; + /* Get rid of the old request entry */ + storeUnregister(http->sc, http->entry, http); + storeUnlockObject(http->entry); + /* Attach ourselves to the new request entry */ + http->entry = e; + storeLockObject(e); + http->sc = storeClientListAdd(http->entry, http); + /* Adjust the header size */ + state->http->reply->hdr_sz = body_offset; + /* Clean up any old body content */ + httpBodyClean(&state->http->reply->body); + state->body_buf = NULL; + state->body_size = 0; + /* And finally, adjust content-length to the new value */ + httpHeaderDelById(&state->http->reply->header, HDR_CONTENT_LENGTH); + if (content_length >= 0) { + httpHeaderPutSize(&state->http->reply->header, HDR_CONTENT_LENGTH, content_length); + } + } + clientCheckHeaderDone(state); +} +static void +clientCheckErrorMap(clientCheckHeaderStateData * state) +{ + clientHttpRequest *http = state->http; + HttpReply *rep = state->http->reply; + if (!cbdataValid(http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (rep->sline.status < 100 || rep->sline.status >= 400) { + request_t *request = http->orig_request; + /* XXX The NULL is meant to pass ACL name, but the ACL name is not + * known here (AclMatchedName is no longer valid) + */ + if (errorMapStart(Config.errorMapList, request, rep, NULL, clientCheckErrorMapDone, state)) + return; + } + clientCheckHeaderDone(state); +} + +static void +clientCheckHeaderDone(clientCheckHeaderStateData * state) +{ + char *buf = state->buf; + const char *body_buf = state->body_buf; + ssize_t body_size = state->body_size; + HttpReply *rep = state->http->reply; + clientHttpRequest *http = state->http; + MemBuf mb; + cbdataFree(state); + if (!cbdataValid(http)) + goto aborted; + /* reset range iterator */ + http->range_iter.pos = HttpHdrRangeInitPos; + if (http->request->method == METHOD_HEAD) { + /* do not forward body for HEAD replies */ + body_size = 0; + http->flags.done_copying = 1; + } + /* init mb; put status line and headers */ + if (http->http_ver.major >= 1) mb = httpReplyPack(rep); - http->out.offset += rep->hdr_sz; - check_size += rep->hdr_sz; + else + memBufDefInit(&mb); + http->out.offset += rep->hdr_sz; #if HEADERS_LOG - headersLog(0, 0, http->request->method, rep); + headersLog(0, 0, http->request->method, rep); #endif - rep = NULL; - } else { - memBufDefInit(&mb); - } /* append body if any */ if (http->request->range) { /* Only GET requests should have ranges */ @@ -2136,11 +2415,94 @@ http->flags.done_copying = 1; } else if (body_buf && body_size) { http->out.offset += body_size; - check_size += body_size; memBufAppend(&mb, body_buf, body_size); } - if (!http->request->range && http->request->method == METHOD_GET) - assert(check_size == size); + /* write */ + comm_write_mbuf(http->conn->fd, mb, clientWriteComplete, http); + /* clean up */ + aborted: + memFree(buf, MEM_CLIENT_SOCK_BUF); + cbdataUnlock(http); + http = NULL; +} + + +/* + * accepts chunk of a http message in buf, parses prefix, filters headers and + * such, writes processed message to the client's socket + */ +static void +clientSendMoreData(void *data, char *buf, ssize_t size) +{ + clientHttpRequest *http = data; + StoreEntry *entry = http->entry; + ConnStateData *conn = http->conn; + int fd = conn->fd; + MemBuf mb; + debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); + assert(size <= CLIENT_SOCK_SZ); + assert(http->request != NULL); + dlinkDelete(&http->active, &ClientActiveRequests); + dlinkAdd(http, &http->active, &ClientActiveRequests); + debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d \n", + fd, storeUrl(entry), (int) http->out.offset); + if (conn->chr != http) { + /* there is another object in progress, defer this one */ + debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } else if (size < 0) { + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } else if (size == 0) { + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } + if (!http->request->range) { + /* Avoid copying to MemBuf for non-range requests */ + http->out.offset += size; + comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); + /* NULL because clientWriteBodyComplete frees it */ + return; + } + if (http->request->method == METHOD_HEAD) { + /* + * If we are here, then store_status == STORE_OK and it + * seems we have a HEAD repsponse which is missing the + * empty end-of-headers line (home.mira.net, phttpd/0.99.72 + * does this). Because clientBuildReply() fails we just + * call this reply a body, set the done_copying flag and + * continue... + */ + http->flags.done_copying = 1; + /* + * And as this is a malformed HTTP reply we cannot keep + * the connection persistent + */ + http->request->flags.proxy_keepalive = 0; + } + /* init mb; put status line and headers if any */ + memBufDefInit(&mb); + if (http->request->range) { + /* Only GET requests should have ranges */ + assert(http->request->method == METHOD_GET); + /* clientPackMoreRanges() updates http->out.offset */ + /* force the end of the transfer if we are done */ + if (!clientPackMoreRanges(http, buf, size, &mb)) + http->flags.done_copying = 1; + } else { + http->out.offset += size; + memBufAppend(&mb, buf, size); + } /* write */ comm_write_mbuf(fd, mb, clientWriteComplete, http); /* if we don't do it, who will? */ @@ -2214,7 +2576,7 @@ http->out.offset, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), - clientSendMoreData, + clientSendMoreHeaderData, http); } } @@ -2324,7 +2686,7 @@ RequestMethodStr[r->method], url); http->al.http.code = HTTP_GATEWAY_TIMEOUT; err = errorCon(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT); - err->request = requestLink(r); + err->request = requestLink(http->orig_request); err->src_addr = http->conn->peer.sin_addr; if (http->entry) { storeUnregister(http->sc, http->entry, http); @@ -2557,7 +2919,7 @@ if (http->flags.accel && r->flags.loopdetect) { http->al.http.code = HTTP_FORBIDDEN; err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN); - err->request = requestLink(r); + err->request = requestLink(http->orig_request); err->src_addr = http->conn->peer.sin_addr; http->log_type = LOG_TCP_DENIED; http->entry = clientCreateStoreEntry(http, r->method, null_request_flags); @@ -2614,7 +2976,6 @@ char *url = NULL; char *req_hdr = NULL; http_version_t http_ver; - char *token = NULL; char *t = NULL; char *end; size_t header_sz; /* size of headers, not including first line */ @@ -2623,34 +2984,40 @@ size_t req_sz; method_t method; clientHttpRequest *http = NULL; -#if IPF_TRANSPARENT - struct natlookup natLookup; - static int natfd = -1; - int x; -#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) - struct ipfobj obj; -#else - static int siocgnatl_cmd = SIOCGNATL & 0xff; -#endif -#endif -#if PF_TRANSPARENT - struct pfioc_natlook nl; - static int pffd = -1; -#endif -#if LINUX_NETFILTER - socklen_t sock_sz = sizeof(conn->me); -#endif + int http_version_offset = 0; /* pre-set these values to make aborting simpler */ *prefix_p = NULL; *method_p = METHOD_NONE; *status = -1; - if ((req_sz = headersEnd(conn->in.buf, conn->in.offset)) == 0) { - debug(33, 5) ("Incomplete request, waiting for end of headers\n"); + if ((t = memchr(conn->in.buf, '\n', conn->in.offset)) == NULL) { + debug(33, 5) ("Incomplete request, waiting for end of request line\n"); *status = 0; return NULL; } + *req_line_sz_p = req_sz = t - conn->in.buf + 1; /* HTTP/0.9 requests */ + while (t > conn->in.buf && xisspace(*t)) + t--; + while (t > conn->in.buf && !xisspace(*t)) + t--; + if (t > conn->in.buf && t < (conn->in.buf + conn->in.offset - 8) && strncasecmp(t + 1, "HTTP/", 5) == 0) { + if ((req_sz = headersEnd(conn->in.buf, conn->in.offset)) == 0) { + debug(33, 5) ("Incomplete request, waiting for end of headers\n"); + *status = 0; + return NULL; + } + http_version_offset = t - conn->in.buf; + if (sscanf(t + 6, "%d.%d", &http_ver.major, &http_ver.minor) != 2) { + debug(33, 3) ("parseHttpRequest: Invalid HTTP identifier.\n"); + return parseHttpRequestAbort(conn, "error:invalid-http-ident"); + } + debug(33, 6) ("parseHttpRequest: Client HTTP version %d.%d.\n", http_ver.major, http_ver.minor); + } else { + debug(33, 3) ("parseHttpRequest: Missing HTTP identifier\n"); + httpBuildVersion(&http_ver, 0, 9); /* wild guess */ + } + assert(req_sz <= conn->in.offset); /* Use memcpy, not strdup! */ inbuf = xmalloc(req_sz + 1); @@ -2666,14 +3033,16 @@ /* Barf on NULL characters in the headers */ if (strlen(inbuf) != req_sz) { debug(33, 1) ("parseHttpRequest: Requestheader contains NULL characters\n"); +#if TRY_TO_IGNORE_THIS xfree(inbuf); return parseHttpRequestAbort(conn, "error:invalid-request"); +#endif } /* Look for request method */ if ((mstr = strtok(inbuf, "\t ")) == NULL) { debug(33, 1) ("parseHttpRequest: Can't get request method\n"); xfree(inbuf); - return parseHttpRequestAbort(conn, "error:invalid-request-method"); + return parseHttpRequestAbort(conn, "error:invalid-request"); } method = urlParseMethod(mstr); if (method == METHOD_NONE) { @@ -2690,56 +3059,32 @@ xfree(inbuf); return parseHttpRequestAbort(conn, "error:missing-url"); } - while (xisspace(*url)) - url++; - t = url + strlen(url); - assert(*t == '\0'); - token = NULL; - while (t > url) { - t--; - if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) { - token = t + 1; - break; - } - } - while (t > url && xisspace(*t)) - *(t--) = '\0'; - debug(33, 5) ("parseHttpRequest: URI is '%s'\n", url); - if (token == NULL) { - debug(33, 3) ("parseHttpRequest: Missing HTTP identifier\n"); -#if RELAXED_HTTP_PARSER - httpBuildVersion(&http_ver, 0, 9); /* wild guess */ -#else - xfree(inbuf); - return parseHttpRequestAbort(conn, "error:missing-http-ident"); -#endif - } else { - if (sscanf(token + 5, "%d.%d", &http_ver.major, &http_ver.minor) != 2) { - debug(33, 3) ("parseHttpRequest: Invalid HTTP identifier.\n"); + if (http_version_offset) { + if (http_version_offset < url - inbuf) { + debug(33, 1) ("parseHttpRequest: Missing URL\n"); xfree(inbuf); - return parseHttpRequestAbort(conn, "error:invalid-http-ident"); + return parseHttpRequestAbort(conn, "error:missing-url"); } - debug(33, 6) ("parseHttpRequest: Client HTTP version %d.%d.\n", http_ver.major, http_ver.minor); + inbuf[http_version_offset] = '\0'; + } else { + t = url + strlen(url) - 1; + while (t > url && *t == '\r') + *t-- = '\0'; } + while (xisspace(*url)) + url++; + debug(33, 5) ("parseHttpRequest: URI is '%s'\n", url); /* * Process headers after request line */ - req_hdr = strtok(NULL, null_string); - header_sz = req_sz - (req_hdr - inbuf); - if (0 == header_sz) { - debug(33, 3) ("parseHttpRequest: header_sz == 0\n"); - *status = 0; - xfree(inbuf); - return NULL; - } - assert(header_sz > 0); + req_hdr = inbuf + *req_line_sz_p; + header_sz = req_sz - *req_line_sz_p; debug(33, 3) ("parseHttpRequest: req_hdr = {%s}\n", req_hdr); end = req_hdr + header_sz; debug(33, 3) ("parseHttpRequest: end = {%s}\n", end); prefix_sz = end - inbuf; - *req_line_sz_p = req_hdr - inbuf; debug(33, 3) ("parseHttpRequest: prefix_sz = %d, req_line_sz = %d\n", (int) prefix_sz, (int) *req_line_sz_p); assert(prefix_sz <= conn->in.offset); @@ -2757,198 +3102,74 @@ dlinkAdd(http, &http->active, &ClientActiveRequests); debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n", (*prefix_p) + *req_line_sz_p); + #if THIS_VIOLATES_HTTP_SPECS_ON_URL_TRANSFORMATION if ((t = strchr(url, '#'))) /* remove HTML anchors */ *t = '\0'; #endif - /* handle direct internal objects */ - if ((!Config2.Accel.on || Config.onoff.global_internal_static) && internalCheck(url)) { - /* prepend our name & port */ - http->uri = xstrdup(internalLocalUri(NULL, url)); - http->flags.accel = 1; - } - /* see if we running in Config2.Accel.on, if so got to convert it to URL */ - else if (Config2.Accel.on && *url == '/') { - int vport; - if (vhost_mode) { -#if IPF_TRANSPARENT - static time_t last_reported = 0; -#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) - obj.ipfo_rev = IPFILTER_VERSION; - obj.ipfo_size = sizeof(natLookup); - obj.ipfo_ptr = &natLookup; - obj.ipfo_type = IPFOBJ_NATLOOKUP; - obj.ipfo_offset = 0; -#endif - natLookup.nl_inport = http->conn->me.sin_port; - natLookup.nl_outport = http->conn->peer.sin_port; - natLookup.nl_inip = http->conn->me.sin_addr; - natLookup.nl_outip = http->conn->peer.sin_addr; - natLookup.nl_flags = IPN_TCP; - if (natfd < 0) { - int save_errno; - enter_suid(); -#ifdef IPNAT_NAME - natfd = open(IPNAT_NAME, O_RDONLY, 0); -#else - natfd = open(IPL_NAT, O_RDONLY, 0); -#endif - save_errno = errno; - leave_suid(); - errno = save_errno; - } - if (natfd < 0) { - if (squid_curtime - last_reported > 60) { - debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n", xstrerror()); - last_reported = squid_curtime; - } - } else { -#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) - x = ioctl(natfd, SIOCGNATL, &obj); -#else - /* - * IP-Filter changed the type for SIOCGNATL between - * 3.3 and 3.4. It also changed the cmd value for - * SIOCGNATL, so at least we can detect it. We could - * put something in configure and use ifdefs here, but - * this seems simpler. - */ - if (63 == siocgnatl_cmd) { - struct natlookup *nlp = &natLookup; - x = ioctl(natfd, SIOCGNATL, &nlp); - } else { - x = ioctl(natfd, SIOCGNATL, &natLookup); - } -#endif - if (x < 0) { - if (errno != ESRCH) { - if (squid_curtime - last_reported > 60) { - debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL): %s\n", xstrerror()); - last_reported = squid_curtime; - } - close(natfd); - natfd = -1; - } - } else { - conn->me.sin_port = natLookup.nl_realport; - conn->me.sin_addr = natLookup.nl_realip; - } - } -#elif PF_TRANSPARENT - static time_t last_reported = 0; - if (pffd < 0) - pffd = open("/dev/pf", O_RDWR); - if (pffd < 0) { - if (squid_curtime - last_reported > 60) { - debug(50, 1) ("parseHttpRequest: PF open failed: %s\n", xstrerror()); - last_reported = squid_curtime; - } - } else { - memset(&nl, 0, sizeof(struct pfioc_natlook)); - nl.saddr.v4.s_addr = http->conn->peer.sin_addr.s_addr; - nl.sport = http->conn->peer.sin_port; - nl.daddr.v4.s_addr = http->conn->me.sin_addr.s_addr; - nl.dport = http->conn->me.sin_port; - nl.af = AF_INET; - nl.proto = IPPROTO_TCP; - nl.direction = PF_OUT; - if (ioctl(pffd, DIOCNATLOOK, &nl)) { - if (errno != ENOENT) { - if (squid_curtime - last_reported > 60) { - debug(50, 1) ("parseHttpRequest: PF lookup failed: ioctl(DIOCNATLOOK): %s\n", xstrerror()); - last_reported = squid_curtime; - } - close(pffd); - pffd = -1; - } - } else { - conn->me.sin_port = nl.rdport; - conn->me.sin_addr = nl.rdaddr.v4; - } - } -#elif LINUX_NETFILTER - static time_t last_reported = 0; - /* If the call fails the address structure will be unchanged */ - if (getsockopt(conn->fd, SOL_IP, SO_ORIGINAL_DST, &conn->me, &sock_sz) != 0) { - if (squid_curtime - last_reported > 60) { - debug(50, 1) ("parseHttpRequest: NF getsockopt(SO_ORIGINAL_DST) failed: %s\n", xstrerror()); - last_reported = squid_curtime; - } - } -#endif - } - if (vport_mode) - vport = (int) ntohs(http->conn->me.sin_port); - else - vport = (int) Config.Accel.port; - /* prepend the accel prefix */ - if (Config.onoff.accel_uses_host_header && (t = mime_get_header(req_hdr, "Host"))) { - char *q; - const char *protocol_name = "http"; - /* If a Host: header was specified, use it to build the URL - * instead of the one in the Config file. */ - /* - * XXX Use of the Host: header here opens a potential - * security hole. There are no checks that the Host: value - * corresponds to one of your servers. It might, for example, - * refer to www.playboy.com. The 'dst' and/or 'dst_domain' ACL - * types should be used to prevent httpd-accelerators - * handling requests for non-local servers */ - strtok(t, " /;@"); - if ((q = strchr(t, ':'))) { - *q++ = '\0'; - if (vport_mode) - vport = atoi(q); - } + /* handle "accelerated" objects (and internal) */ + if (method == METHOD_CONNECT); /* Nothing to do */ + else if (*url == '/') + accel:{ + int vhost = conn->port->vhost || conn->port->transparent; + int vport = conn->port->vport || conn->transparent; + if (internalCheck(url)) { + /* prepend our name & port */ + http->uri = xstrdup(internalLocalUri(NULL, url)); + http->flags.internal = 1; + http->flags.accel = 1; + debug(33, 5) ("INTERNAL REWRITE: '%s'\n", http->uri); + } else if (vhost && (t = mime_get_header(req_hdr, "Host"))) { url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(t); http->uri = xcalloc(url_sz, 1); - -#if SSL_FORWARDING_NOT_YET_DONE - if (Config.Sockaddr.https->s.sin_port == http->conn->me.sin_port) { - protocol_name = "https"; - vport = ntohs(http->conn->me.sin_port); - } -#endif - snprintf(http->uri, url_sz, "%s://%s:%d%s", - protocol_name, t, vport, url); - } else if (vhost_mode) { - /* Put the local socket IP address as the hostname */ - url_sz = strlen(url) + 32 + Config.appendDomainLen; - http->uri = xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "http://%s:%d%s", - inet_ntoa(http->conn->me.sin_addr), - vport, url); + snprintf(http->uri, url_sz, "%s://%s%s", + conn->port->protocol, t, url); debug(33, 5) ("VHOST REWRITE: '%s'\n", http->uri); - } else if (vport_mode) { - const char *protocol_name = "http"; + } else if (conn->port->defaultsite) { url_sz = strlen(url) + 32 + Config.appendDomainLen + - strlen(Config.Accel.host); + strlen(conn->port->defaultsite); + http->uri = xcalloc(url_sz, 1); + snprintf(http->uri, url_sz, "%s://%s%s", + conn->port->protocol, conn->port->defaultsite, url); + debug(33, 5) ("DEFAULTSITE REWRITE: '%s'\n", http->uri); + } else if (vport) { + /* Put the local socket IP address as the hostname. + * Note: In transparent mode clientNatLookup() has replaced + * the local socket IP with the real destination + */ + url_sz = strlen(url) + 32 + Config.appendDomainLen; http->uri = xcalloc(url_sz, 1); snprintf(http->uri, url_sz, "%s://%s:%d%s", - protocol_name, Config.Accel.host, vport, url); + http->conn->port->protocol, + inet_ntoa(http->conn->me.sin_addr), + vport, url); + debug(33, 5) ("VPORT REWRITE: '%s'\n", http->uri); } else { - url_sz = strlen(Config2.Accel.prefix) + strlen(url) + - Config.appendDomainLen + 1; - http->uri = xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "%s%s", Config2.Accel.prefix, url); + goto invalid_request; } http->flags.accel = 1; - if (Config.onoff.accel_no_pmtu_disc) { -#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) - int i = IP_PMTUDISC_DONT; - setsockopt(conn->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof i); -#else - static int reported = 0; - if (!reported) { - debug(33, 1) ("Notice: httpd_accel_no_pmtu_disc not supported on your platform\n"); - reported = 1; - } -#endif + } else if (conn->transparent) { + http->flags.accel = 1; + } else if (conn->port->accel) { + http->flags.accel = 1; + if (!conn->port->vhost) { + url = strstr(url, "//"); + if (!url) + goto invalid_request; + url = strchr(url + 2, '/'); + if (!url) + url = (char *) "/"; + goto accel; } } else { - /* URL may be rewritten later, so make extra room */ + /* Proxy request */ + http->flags.accel = 0; + } + if (!http->uri) { + /* No special rewrites have been applied above, use the + * requested url. may be rewritten later, so make extra room */ url_sz = strlen(url) + Config.appendDomainLen + 5; http->uri = xcalloc(url_sz, 1); strcpy(http->uri, url); @@ -2962,6 +3183,13 @@ xfree(inbuf); *status = 1; return http; + + invalid_request: + /* This tries to back out what is done above */ + dlinkDelete(&http->active, &ClientActiveRequests); + safe_free(http->uri); + cbdataFree(http); + return parseHttpRequestAbort(conn, "error:invalid-request"); } static int @@ -3143,7 +3371,7 @@ } /* compile headers */ /* we should skip request line! */ - if (!httpRequestParseHeader(request, prefix + req_line_sz)) { + if ((http->http_ver.major >= 1) && !httpRequestParseHeader(request, prefix + req_line_sz)) { debug(33, 1) ("Failed to parse request headers: %s\n%s\n", http->uri, prefix); err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST); @@ -3156,6 +3384,8 @@ safe_free(prefix); break; } + if (conn->port->urlgroup) + request->urlgroup = xstrdup(conn->port->urlgroup); request->flags.accelerated = http->flags.accel; if (!http->flags.internal) { if (internalCheck(strBuf(request->urlpath))) { @@ -3209,6 +3439,7 @@ break; } http->request = requestLink(request); + http->orig_request = requestLink(request); clientSetKeepaliveFlag(http); /* Do we expect a request-body? */ if (request->content_length > 0) { @@ -3257,6 +3488,7 @@ /* add to the client request queue */ for (H = &conn->chr; *H; H = &(*H)->next); *H = http; + http->log_type = LOG_TCP_DENIED; http->entry = clientCreateStoreEntry(http, METHOD_NONE, null_request_flags); errorAppendEntry(http->entry, err); } @@ -3397,8 +3629,10 @@ /* Invoke callback function */ if (valid) callback(buf, size, cbdata); - if (request != NULL) + if (request != NULL) { requestUnlink(request); /* Linked in clientReadBody */ + conn->body.request = NULL; + } debug(33, 2) ("clientProcessBody: end fd=%d size=%d body_size=%lu in.offset=%ld cb=%p req=%p\n", conn->fd, size, (unsigned long int) conn->body.size_left, (long int) conn->in.offset, callback, request); } } @@ -3512,11 +3746,171 @@ return 1; } +#if IPF_TRANSPARENT +static int +clientNatLookup(ConnStateData * conn) +{ + struct natlookup natLookup; + static int natfd = -1; + int x; +#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) + struct ipfobj obj; +#else + static int siocgnatl_cmd = SIOCGNATL & 0xff; +#endif + static time_t last_reported = 0; + +#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(natLookup); + obj.ipfo_ptr = &natLookup; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + obj.ipfo_offset = 0; +#endif + + natLookup.nl_inport = conn->me.sin_port; + natLookup.nl_outport = conn->peer.sin_port; + natLookup.nl_inip = conn->me.sin_addr; + natLookup.nl_outip = conn->peer.sin_addr; + natLookup.nl_flags = IPN_TCP; + if (natfd < 0) { + int save_errno; + enter_suid(); +#ifdef IPNAT_NAME + natfd = open(IPNAT_NAME, O_RDONLY, 0); +#else + natfd = open(IPL_NAT, O_RDONLY, 0); +#endif + save_errno = errno; + leave_suid(); + errno = save_errno; + } + if (natfd < 0) { + if (squid_curtime - last_reported > 60) { + debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n", + xstrerror()); + last_reported = squid_curtime; + } + return -1; + } +#if defined(IPFILTER_VERSION) && (IPFILTER_VERSION >= 4000027) + x = ioctl(natfd, SIOCGNATL, &obj); +#else + /* + * IP-Filter changed the type for SIOCGNATL between + * 3.3 and 3.4. It also changed the cmd value for + * SIOCGNATL, so at least we can detect it. We could + * put something in configure and use ifdefs here, but + * this seems simpler. + */ + if (63 == siocgnatl_cmd) { + struct natlookup *nlp = &natLookup; + x = ioctl(natfd, SIOCGNATL, &nlp); + } else { + x = ioctl(natfd, SIOCGNATL, &natLookup); + } +#endif + if (x < 0) { + if (errno != ESRCH) { + if (squid_curtime - last_reported > 60) { + debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n"); + last_reported = squid_curtime; + } + close(natfd); + natfd = -1; + } + return -1; + } else { + int natted = conn->me.sin_addr.s_addr != natLookup.nl_realip.s_addr; + conn->me.sin_port = natLookup.nl_realport; + conn->me.sin_addr = natLookup.nl_realip; + if (natted) + return 0; + else + return -1; + } +} +#elif LINUX_NETFILTER +static int +clientNatLookup(ConnStateData * conn) +{ + size_t sock_sz = sizeof(conn->me); + struct in_addr orig_addr = conn->me.sin_addr; + static time_t last_reported = 0; + /* If the call fails the address structure will be unchanged */ + if (getsockopt(conn->fd, SOL_IP, SO_ORIGINAL_DST, &conn->me, &sock_sz) != 0) { + if (squid_curtime - last_reported > 60) { + debug(50, 1) ("parseHttpRequest: NF getsockopt(SO_ORIGINAL_DST) failed: %s\n", xstrerror()); + last_reported = squid_curtime; + } + return -1; + } + debug(33, 5) ("parseHttpRequest: addr = %s", inet_ntoa(conn->me.sin_addr)); + if (orig_addr.s_addr != conn->me.sin_addr.s_addr) + return 0; + else + return -1; +} +#elif PF_TRANSPARENT +static int +clientNatLookup(ConnStateData * conn) +{ + struct pfioc_natlook nl; + static int pffd = -1; + static time_t last_reported = 0; + if (pffd < 0) + pffd = open("/dev/pf", O_RDWR); + if (pffd < 0) { + debug(50, 1) ("parseHttpRequest: PF open failed: %s\n", + xstrerror()); + return -1; + } + memset(&nl, 0, sizeof(struct pfioc_natlook)); + nl.saddr.v4.s_addr = conn->peer.sin_addr.s_addr; + nl.sport = conn->peer.sin_port; + nl.daddr.v4.s_addr = conn->me.sin_addr.s_addr; + nl.dport = conn->me.sin_port; + nl.af = AF_INET; + nl.proto = IPPROTO_TCP; + nl.direction = PF_OUT; + if (ioctl(pffd, DIOCNATLOOK, &nl)) { + if (errno != ENOENT) { + if (squid_curtime - last_reported > 60) { + debug(50, 1) ("parseHttpRequest: PF lookup failed: ioctl(DIOCNATLOOK)\n"); + last_reported = squid_curtime; + } + close(pffd); + pffd = -1; + } + return -1; + } else { + int natted = conn->me.sin_addr.s_addr != nt.rdaddr.v4.s_addr; + conn->me.sin_port = nl.rdport; + conn->me.sin_addr = nl.rdaddr.v4; + if (natted) + return 0; + else + return -1; + } +} +#else +static int inline +clientNatLookup(ConnStateData * conn) +{ + static time_t last_reported = 0; + if (squid_curtime - last_reported > 60) { + debug(33, 1) ("WARNING: transparent proxying not supported\n"); + last_reported = squid_curtime; + } + return -1; +} +#endif + /* Handle a new connection on HTTP socket. */ void httpAccept(int sock, void *data) { - int *N = &incoming_sockets_accepted; + http_port_list *s = data; int fd = -1; fde *F; ConnStateData *connState = NULL; @@ -3526,7 +3920,7 @@ #if USE_IDENT static aclCheck_t identChecklist; #endif - commSetSelect(sock, COMM_SELECT_READ, httpAccept, NULL, 0); + commSetSelect(sock, COMM_SELECT_READ, httpAccept, data, 0); while (max-- && !httpAcceptDefer(sock, NULL)) { memset(&peer, '\0', sizeof(struct sockaddr_in)); memset(&me, '\0', sizeof(struct sockaddr_in)); @@ -3538,7 +3932,10 @@ } F = &fd_table[fd]; debug(33, 4) ("httpAccept: FD %d: accepted port %d client %s:%d\n", fd, F->local_port, F->ipaddr, F->remote_port); + fd_note(fd, "client http connect"); connState = cbdataAlloc(ConnStateData); + connState->port = s; + cbdataLock(connState->port); connState->peer = peer; connState->log_addr = peer.sin_addr; connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; @@ -3546,7 +3943,23 @@ connState->fd = fd; connState->in.size = CLIENT_REQ_BUF_SZ; connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF); - /* XXX account connState->in.buf */ + if (connState->port->transparent) { + if (clientNatLookup(connState) == 0) { + connState->transparent = 1; + if (Config.onoff.accel_no_pmtu_disc) { +#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) + int i = IP_PMTUDISC_DONT; + setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof i); +#else + static int reported = 0; + if (!reported) { + debug(33, 1) ("Notice: httpd_accel_no_pmtu_disc not supported on your platform\n"); + reported = 1; + } +#endif + } + } + } comm_add_close_handler(fd, connStateFree, connState); if (Config.onoff.log_fqdn) fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS); @@ -3561,8 +3974,7 @@ commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, connState, 0); commSetDefer(fd, clientReadDefer, connState); clientdbEstablished(peer.sin_addr, 1); - assert(N); - (*N)++; + incoming_sockets_accepted++; } } @@ -3608,19 +4020,12 @@ commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); } -struct _https_port_data { - SSL_CTX *sslContext; -}; -typedef struct _https_port_data https_port_data; -CBDATA_TYPE(https_port_data); - /* handle a new HTTPS connection */ static void httpsAccept(int sock, void *data) { - int *N = &incoming_sockets_accepted; - https_port_data *https_port = data; - SSL_CTX *sslContext = https_port->sslContext; + https_port_list *s = data; + SSL_CTX *sslContext = s->sslContext; int fd = -1; fde *F; ConnStateData *connState = NULL; @@ -3632,7 +4037,7 @@ #if USE_IDENT static aclCheck_t identChecklist; #endif - commSetSelect(sock, COMM_SELECT_READ, httpsAccept, https_port, 0); + commSetSelect(sock, COMM_SELECT_READ, httpsAccept, s, 0); while (max-- && !httpAcceptDefer(sock, NULL)) { memset(&peer, '\0', sizeof(struct sockaddr_in)); memset(&me, '\0', sizeof(struct sockaddr_in)); @@ -3655,8 +4060,11 @@ F->write_method = &ssl_write_method; debug(33, 4) ("httpsAccept: FD %d: accepted port %d client %s:%d\n", fd, F->local_port, F->ipaddr, F->remote_port); debug(50, 5) ("httpsAccept: FD %d: starting SSL negotiation.\n", fd); + fd_note(fd, "client https connect"); connState = cbdataAlloc(ConnStateData); + connState->port = (http_port_list *) s; + cbdataLock(connState->port); connState->peer = peer; connState->log_addr = peer.sin_addr; connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; @@ -3664,7 +4072,10 @@ connState->fd = fd; connState->in.size = CLIENT_REQ_BUF_SZ; connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF); - /* XXX account connState->in.buf */ + /* transparent on SSL does not really make sense, but what the heck */ + if (connState->port->transparent) + if (clientNatLookup(connState)) + connState->transparent = 1; comm_add_close_handler(fd, connStateFree, connState); if (Config.onoff.log_fqdn) fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS); @@ -3679,7 +4090,7 @@ commSetSelect(fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0); commSetDefer(fd, clientReadDefer, connState); clientdbEstablished(peer.sin_addr, 1); - (*N)++; + incoming_sockets_accepted++; } } @@ -3812,7 +4223,7 @@ static void clientHttpConnectionsOpen(void) { - sockaddr_in_list *s; + http_port_list *s; int fd; for (s = Config.Sockaddr.http; s; s = s->next) { if (MAXHTTPPORTS == NHttpSockets) { @@ -3831,7 +4242,7 @@ if (fd < 0) continue; comm_listen(fd); - commSetSelect(fd, COMM_SELECT_READ, httpAccept, NULL, 0); + commSetSelect(fd, COMM_SELECT_READ, httpAccept, s, 0); /* * We need to set a defer handler here so that we don't * peg the CPU with select() when we hit the FD limit. @@ -3850,33 +4261,34 @@ clientHttpsConnectionsOpen(void) { https_port_list *s; - https_port_data *https_port; int fd; - for (s = Config.Sockaddr.https; s; s = s->next) { + for (s = Config.Sockaddr.https; s; s = (https_port_list *) s->http.next) { if (MAXHTTPPORTS == NHttpSockets) { debug(1, 1) ("WARNING: You have too many 'https_port' lines.\n"); debug(1, 1) (" The limit is %d\n", MAXHTTPPORTS); continue; } enter_suid(); + s->sslContext = sslCreateContext(s->cert, s->key, s->version, s->cipher, s->options); + if (!s->sslContext) { + leave_suid(); + continue; + } fd = comm_open(SOCK_STREAM, - IPPROTO_TCP, - s->s.sin_addr, - ntohs(s->s.sin_port), + 0, + s->http.s.sin_addr, + ntohs(s->http.s.sin_port), COMM_NONBLOCKING, "HTTPS Socket"); leave_suid(); if (fd < 0) continue; - CBDATA_INIT_TYPE(https_port_data); - https_port = cbdataAlloc(https_port_data); - https_port->sslContext = sslCreateContext(s->cert, s->key, s->version, s->cipher, s->options); comm_listen(fd); - commSetSelect(fd, COMM_SELECT_READ, httpsAccept, https_port, 0); + commSetSelect(fd, COMM_SELECT_READ, httpsAccept, s, 0); commSetDefer(fd, httpAcceptDefer, NULL); debug(1, 1) ("Accepting HTTPS connections at %s, port %d, FD %d.\n", - inet_ntoa(s->s.sin_addr), - (int) ntohs(s->s.sin_port), + inet_ntoa(s->http.s.sin_addr), + (int) ntohs(s->http.s.sin_port), fd); HttpSockets[NHttpSockets++] = fd; } Index: squid/src/enums.h diff -u squid/src/enums.h:1.44 squid/src/enums.h:1.44.2.1 --- squid/src/enums.h:1.44 Mon May 15 16:51:55 2006 +++ squid/src/enums.h Mon May 15 18:01:31 2006 @@ -115,6 +115,7 @@ ACL_IDENT, ACL_IDENT_REGEX, #endif + ACL_TYPE, ACL_PROTO, ACL_METHOD, ACL_BROWSER, @@ -140,6 +141,7 @@ ACL_MAX_USER_IP, ACL_EXTERNAL, ACL_URLLOGIN, + ACL_URLGROUP, ACL_ENUM_MAX } squid_acl; @@ -245,6 +247,8 @@ #if X_ACCELERATOR_VARY HDR_X_ACCELERATOR_VARY, #endif + HDR_X_ERROR_URL, /* errormap, requested URL */ + HDR_X_ERROR_STATUS, /* errormap, received HTTP status line */ HDR_OTHER, HDR_ENUM_END } http_hdr_type; @@ -312,6 +316,8 @@ CARP, #endif ANY_OLD_PARENT, + USERHASH_PARENT, + SOURCEHASH_PARENT, HIER_MAX } hier_code; @@ -568,6 +574,7 @@ MEM_ACL_IP_DATA, MEM_ACL_LIST, MEM_ACL_NAME_LIST, + MEM_ACL_REQUEST_TYPE, MEM_AUTH_USER_T, MEM_AUTH_USER_HASH, MEM_ACL_PROXY_AUTH_MATCH, Index: squid/src/errormap.c diff -u /dev/null squid/src/errormap.c:1.1.30.1 --- /dev/null Thu Jan 1 01:00:00 1970 +++ squid/src/errormap.c Mon May 15 18:01:31 2006 @@ -0,0 +1,220 @@ + +/* + * $Id$ + * + * DEBUG: section ?? Error Beautifier + * AUTHOR: Henrik Nordstrom + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +static const char * +getErrorMap(const errormap * map, const http_status status, const char *squid_error, const char *aclname) +{ + while (map) { + struct error_map_entry *m; + for (m = map->map; m; m = m->next) { + if (m->status == status) + return map->url; + if (squid_error && strcmp(m->value, squid_error) == 0) + return map->url; + if (aclname && strcmp(m->value, aclname) == 0) + return map->url; + } + map = map->next; + } + return NULL; +} + + +static int client_header_identities[] = +{ + HDR_USER_AGENT, + HDR_COOKIE, + HDR_X_FORWARDED_FOR, + HDR_VIA, + HDR_AUTHORIZATION, + HDR_ACCEPT, + HDR_REFERER +}; +HttpHeaderMask client_headers; + +static int server_header_identities[] = +{ + HDR_VIA, + HDR_SERVER, + HDR_LOCATION, + HDR_CONTENT_LOCATION +}; +HttpHeaderMask server_headers; + +typedef struct { + request_t *req; + StoreEntry *e; + store_client *sc; + ERRMAPCB *callback; + void *callback_data; + char *buf; +} ErrorMapState; + +CBDATA_TYPE(ErrorMapState); + +static void +errorMapFetchComplete(ErrorMapState * state) +{ + storeUnregister(state->sc, state->e, state); + state->sc = NULL; + storeUnlockObject(state->e); + state->e = NULL; + requestUnlink(state->req); + state->req = NULL; + memFree(state->buf, MEM_4K_BUF); + cbdataUnlock(state->callback_data); + state->callback_data = NULL; + cbdataFree(state); +} + +static void +errorMapFetchAbort(ErrorMapState * state) +{ + if (cbdataValid(state->callback_data)) + state->callback(NULL, -1, -1, state->callback_data); + errorMapFetchComplete(state); +} + +static void +errorMapFetchHeaders(void *data, char *buf, ssize_t size) +{ + ErrorMapState *state = data; + size_t hdr_size; + + if (EBIT_TEST(state->e->flags, ENTRY_ABORTED)) + goto abort; + if (size == 0) + goto abort; + if (!cbdataValid(state->callback_data)) + goto abort; + + if ((hdr_size = headersEnd(buf, size))) { + http_status status; + /* httpReplyParse(reply, buf, hdr_size); */ + HttpReply *reply = state->e->mem_obj->reply; + assert(reply); + status = reply->sline.status; + if (status != HTTP_OK) + goto abort; + /* Send object to caller (cbdataValid verified above) */ + state->callback(state->e, hdr_size, httpHeaderGetSize(&reply->header, HDR_CONTENT_LENGTH), state->callback_data); + errorMapFetchComplete(state); + goto done; + } + if (size >= 4096) { + /* Not enought space for reply headers */ + goto abort; + } + /* Need more data */ + storeClientCopy(state->sc, state->e, size, 0, 4096, state->buf, errorMapFetchHeaders, state); + done: + return; + abort: + errorMapFetchAbort(state); + return; +} + +int +errorMapStart(const errormap * map, request_t * client_req, HttpReply * reply, const char *aclname, ERRMAPCB * callback, void *callback_data) +{ + char squid_error[100]; + int len = 0; + const char *errorUrl; + ErrorMapState *state; + const char *tmp; + http_status status; + request_t *req; + HttpHeaderPos hdrpos; + HttpHeaderEntry *hdr; + + if (!client_req || !reply) + return 0; + + status = reply->sline.status; + + tmp = httpHeaderGetStr(&reply->header, HDR_X_SQUID_ERROR); + squid_error[0] = '\0'; + if (tmp) { + xstrncpy(squid_error, tmp, sizeof(squid_error)); + len = strcspn(squid_error, " "); + } + squid_error[len] = '\0'; + errorUrl = getErrorMap(map, status, squid_error, aclname); + if (!errorUrl) + return 0; + req = urlParse(METHOD_GET, (char *) errorUrl); + if (!req) { + debug(0, 0) ("error_map: Invalid error URL '%s'\n", errorUrl); + return 0; + } + req->urlgroup = xstrdup("error"); + + state = cbdataAlloc(ErrorMapState); + state->req = requestLink(req); + state->e = storeCreateEntry(errorUrl, errorUrl, req->flags, req->method); + state->sc = storeClientListAdd(state->e, state); + state->callback = callback; + state->callback_data = callback_data; + cbdataLock(callback_data); + + hdrpos = HttpHeaderInitPos; + while ((hdr = httpHeaderGetEntry(&client_req->header, &hdrpos)) != NULL) { + if (CBIT_TEST(client_headers, hdr->id)) + httpHeaderAddEntry(&req->header, httpHeaderEntryClone(hdr)); + } + hdrpos = HttpHeaderInitPos; + while ((hdr = httpHeaderGetEntry(&reply->header, &hdrpos)) != NULL) { + if (CBIT_TEST(server_headers, hdr->id)) + httpHeaderAddEntry(&req->header, httpHeaderEntryClone(hdr)); + } + httpHeaderPutInt(&req->header, HDR_X_ERROR_STATUS, (int) reply->sline.status); + httpHeaderPutStr(&req->header, HDR_X_REQUEST_URI, urlCanonical(client_req)); + + state->buf = memAllocate(MEM_4K_BUF); + fwdStart(-1, state->e, req); + storeClientCopy(state->sc, state->e, 0, 0, 4096, state->buf, errorMapFetchHeaders, state); + return 1; +} + +void +errorMapInit(void) +{ + CBDATA_INIT_TYPE(ErrorMapState); + + httpHeaderCalcMask(&client_headers, client_header_identities, sizeof(client_header_identities) / sizeof(*client_header_identities)); + httpHeaderCalcMask(&server_headers, server_header_identities, sizeof(server_header_identities) / sizeof(*server_header_identities)); +} Index: squid/src/errorpage.c diff -u squid/src/errorpage.c:1.25 squid/src/errorpage.c:1.25.2.1 --- squid/src/errorpage.c:1.25 Sun May 14 08:50:33 2006 +++ squid/src/errorpage.c Mon May 15 18:01:31 2006 @@ -214,7 +214,7 @@ xfree(info); } -static int +int errorPageId(const char *page_name) { int i; @@ -248,8 +248,7 @@ if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */ return err_type_str[pageId]; if (pageId >= ERR_MAX && pageId - ERR_MAX < ErrorDynamicPages.count) - return ((ErrorDynamicPageInfo *) ErrorDynamicPages. - items[pageId - ERR_MAX])->page_name; + return ((ErrorDynamicPageInfo *) ErrorDynamicPages.items[pageId - ERR_MAX])->page_name; return "ERR_UNKNOWN"; /* should not happen */ } Index: squid/src/forward.c diff -u squid/src/forward.c:1.18 squid/src/forward.c:1.18.4.1 --- squid/src/forward.c:1.18 Fri Apr 28 04:10:52 2006 +++ squid/src/forward.c Mon May 15 18:01:32 2006 @@ -345,7 +345,9 @@ ErrorState *err; FwdServer *fs = fwdState->servers; const char *host; + const char *name; unsigned short port; + const char *domain = NULL; int ctimeout; int ftimeout = Config.Timeout.forward - (squid_curtime - fwdState->start); struct in_addr outgoing; @@ -355,16 +357,14 @@ debug(17, 3) ("fwdConnectStart: %s\n", url); if (fs->peer) { host = fs->peer->host; + name = fs->peer->name; port = fs->peer->http_port; + if (fs->peer->options.originserver) + domain = fwdState->request->host; ctimeout = fs->peer->connect_timeout > 0 ? fs->peer->connect_timeout : Config.Timeout.peer_connect; - } else if (fwdState->request->flags.accelerated && - Config.Accel.single_host && Config.Accel.host) { - host = Config.Accel.host; - port = Config.Accel.port; - ctimeout = Config.Timeout.connect; } else { - host = fwdState->request->host; + host = name = fwdState->request->host; port = fwdState->request->port; ctimeout = Config.Timeout.connect; } @@ -372,7 +372,7 @@ ftimeout = 5; if (ftimeout < ctimeout) ctimeout = ftimeout; - if ((fd = pconnPop(host, port)) >= 0) { + if ((fd = pconnPop(host, port, domain)) >= 0) { if (fwdCheckRetriable(fwdState)) { debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd); fwdState->server_fd = fd; @@ -488,9 +488,11 @@ if (fwdState->servers && (p = fwdState->servers->peer)) { p->stats.fetches++; fwdState->request->peer_login = p->login; + fwdState->request->peer_domain = p->domain; httpStart(fwdState); } else { fwdState->request->peer_login = NULL; + fwdState->request->peer_domain = NULL; switch (request->protocol) { case PROTO_HTTP: httpStart(fwdState); @@ -581,6 +583,29 @@ } void +fwdStartPeer(peer * p, StoreEntry * e, request_t * r) +{ + FwdState *fwdState; + FwdServer *peer = NULL; + debug(17, 3) ("fwdStartPeer: '%s'\n", storeUrl(e)); + e->mem_obj->request = requestLink(r); +#if URL_CHECKSUM_DEBUG + assert(e->mem_obj->chksum == url_checksum(e->mem_obj->url)); +#endif + fwdState = cbdataAlloc(FwdState); + fwdState->entry = e; + fwdState->client_fd = -1; + fwdState->server_fd = -1; + fwdState->request = requestLink(r); + fwdState->start = squid_curtime; + storeLockObject(e); + EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT); + storeRegisterAbort(e, fwdAbort, fwdState); + peerAddFwdServer(&peer, p, DIRECT); + fwdStartComplete(peer, fwdState); +} + +void fwdStart(int fd, StoreEntry * e, request_t * r) { FwdState *fwdState; Index: squid/src/globals.h diff -u squid/src/globals.h:1.20 squid/src/globals.h:1.20.2.1 --- squid/src/globals.h:1.20 Sun May 14 08:50:33 2006 +++ squid/src/globals.h Mon May 15 18:01:32 2006 @@ -102,8 +102,6 @@ extern int theOutSnmpConnection; /* -1 */ extern char *snmp_agentinfo; #endif -extern int vhost_mode; /* 0 */ -extern int vport_mode; /* 0 */ extern int n_disk_objects; /* 0 */ extern iostats IOStats; extern struct _acl_deny_info_list *DenyInfoList; /* NULL */ Index: squid/src/http.c diff -u squid/src/http.c:1.27 squid/src/http.c:1.27.4.1 --- squid/src/http.c:1.27 Fri Apr 28 04:10:52 2006 +++ squid/src/http.c Mon May 15 18:01:32 2006 @@ -738,10 +738,14 @@ #endif comm_remove_close_handler(fd, httpStateFree, httpState); fwdUnregister(fd, httpState->fwd); - if (request->flags.accelerated && Config.Accel.single_host && Config.Accel.host) - pconnPush(fd, Config.Accel.host, Config.Accel.port); - else - pconnPush(fd, request->host, request->port); + if (httpState->peer) { + if (httpState->peer->options.originserver) + pconnPush(fd, httpState->peer->name, httpState->peer->http_port, httpState->orig_request->host); + else + pconnPush(fd, httpState->peer->name, httpState->peer->http_port, NULL); + } else { + pconnPush(fd, request->host, request->port, NULL); + } fwdComplete(httpState->fwd); httpState->fd = -1; httpStateFree(fd, httpState); @@ -836,7 +840,6 @@ const HttpHeader *hdr_in = &orig_request->header; int we_do_ranges; const HttpHeaderEntry *e; - String strVia; String strFwd; HttpHeaderPos pos = HttpHeaderInitPos; httpHeaderInit(hdr_out, hoRequest); @@ -879,24 +882,23 @@ /* Only pass on proxy authentication to peers for which * authentication forwarding is explicitly enabled */ - if (request->flags.proxying && orig_request->peer_login && - strcmp(orig_request->peer_login, "PASS") == 0) { + if (flags.proxying && orig_request->peer_login && strcmp(orig_request->peer_login, "PASS") == 0) { httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); } break; case HDR_AUTHORIZATION: - /* Pass on WWW authentication even if used locally. If this is - * not wanted in an accelerator then the header can be removed - * using the anonymization functions - */ - httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); - /* XXX Some accelerators might want to strip the header - * and regard the reply as cacheable, but authentication - * is not normally enabled for accelerators without reading - * the code, so there is not much use in adding logics here - * without first defining the concept of having authentication - * in the accelerator... + /* Pass on WWW authentication. */ + if (!flags.originpeer) { + httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); + } else { + /* In accelerators, only forward authentication if enabled + * (see also below for proxy->server authentication) + */ + if (orig_request->peer_login && (strcmp(orig_request->peer_login, "PASS") == 0 || strcmp(orig_request->peer_login, "PROXYPASS") == 0)) { + httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); + } + } break; case HDR_HOST: /* @@ -905,7 +907,9 @@ * went through our redirector and the admin configured * 'redir_rewrites_host' to be off. */ - if (request->flags.redirected && !Config.onoff.redir_rewrites_host) + if (orig_request->peer_domain) + httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->peer_domain); + else if (request->flags.redirected && !Config.onoff.redir_rewrites_host) httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); else { /* use port# only if not default */ @@ -937,9 +941,13 @@ if (!we_do_ranges) httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); break; + case HDR_VIA: + /* If Via is disabled then forward any received header as-is */ + if (!Config.onoff.via) + httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); + break; case HDR_PROXY_CONNECTION: case HDR_CONNECTION: - case HDR_VIA: case HDR_X_FORWARDED_FOR: case HDR_CACHE_CONTROL: /* append these after the loop if needed */ @@ -951,14 +959,15 @@ } /* append Via */ - strVia = httpHeaderGetList(hdr_in, HDR_VIA); - snprintf(bbuf, BBUF_SZ, "%d.%d %s", - orig_request->http_ver.major, - orig_request->http_ver.minor, ThisCache); - strListAdd(&strVia, bbuf, ','); - httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia)); - stringClean(&strVia); - + if (Config.onoff.via) { + String strVia = httpHeaderGetList(hdr_in, HDR_VIA); + snprintf(bbuf, BBUF_SZ, "%d.%d %s", + orig_request->http_ver.major, + orig_request->http_ver.minor, ThisCache); + strListAdd(&strVia, bbuf, ','); + httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia)); + stringClean(&strVia); + } /* append X-Forwarded-For */ strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR); strListAdd(&strFwd, @@ -969,8 +978,10 @@ /* append Host if not there already */ if (!httpHeaderHas(hdr_out, HDR_HOST)) { - /* use port# only if not default */ - if (orig_request->port == urlDefaultPort(orig_request->protocol)) { + if (orig_request->peer_domain) { + httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->peer_domain); + } else if (orig_request->port == urlDefaultPort(orig_request->protocol)) { + /* use port# only if not default */ httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host); } else { httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d", @@ -986,8 +997,7 @@ } /* append Proxy-Authorization if configured for peer, and proxying */ if (request->flags.proxying && orig_request->peer_login && - !httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION) && - strcmp(orig_request->peer_login, "PASS") != 0) { + !httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION)) { if (*orig_request->peer_login == '*') { /* Special mode, to pass the username to the upstream cache */ char loginbuf[256]; @@ -997,11 +1007,41 @@ snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1); httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", base64_encode(loginbuf)); + } else if (strcmp(orig_request->peer_login, "PASS") == 0) { + /* Nothing to do */ + } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) { + /* Nothing to do */ } else { httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", base64_encode(orig_request->peer_login)); } } + /* append WWW-Authorization if configured for peer */ + if (flags.originpeer && orig_request->peer_login && + !httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) { + if (strcmp(orig_request->peer_login, "PASS") == 0) { + /* No credentials to forward.. (should have been done above if available) */ + } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) { + /* Special mode, convert proxy authentication to WWW authentication */ + const char *auth = httpHeaderGetStr(hdr_in, HDR_PROXY_AUTHORIZATION); + if (auth && strncasecmp(auth, "basic ", 6) == 0) { + httpHeaderPutStr(hdr_out, HDR_AUTHORIZATION, auth); + } + } else if (*orig_request->peer_login == '*') { + /* Special mode, to pass the username to the upstream cache */ + char loginbuf[256]; + const char *username = "-"; + if (orig_request->auth_user_request) + username = authenticateUserRequestUsername(orig_request->auth_user_request); + snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1); + httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", + base64_encode(loginbuf)); + } else { + /* Fixed login string */ + httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", + base64_encode(orig_request->peer_login)); + } + } /* append Cache-Control, add max-age if not there already */ { HttpHdrCc *cc = httpHeaderGetCc(hdr_in); @@ -1084,10 +1124,15 @@ else sendHeaderDone = httpSendComplete; - if (p != NULL) - httpState->flags.proxying = 1; - else + if (p != NULL) { + if (p->options.originserver) + httpState->flags.originpeer = 1; + else + httpState->flags.proxying = 1; + } else { httpState->flags.proxying = 0; + httpState->flags.originpeer = 0; + } /* * Is keep-alive okay for all request methods? */ @@ -1131,8 +1176,13 @@ if (fwd->servers) httpState->peer = fwd->servers->peer; /* might be NULL */ if (httpState->peer) { + const char *url; + if (httpState->peer->options.originserver) + url = strBuf(orig_req->urlpath); + else + url = storeUrl(httpState->entry); proxy_req = requestCreate(orig_req->method, - PROTO_NONE, storeUrl(httpState->entry)); + PROTO_NONE, url); xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN); proxy_req->port = httpState->peer->http_port; proxy_req->flags = orig_req->flags; Index: squid/src/icp_v2.c diff -u squid/src/icp_v2.c:1.8 squid/src/icp_v2.c:1.8.2.1 --- squid/src/icp_v2.c:1.8 Mon May 15 15:50:49 2006 +++ squid/src/icp_v2.c Mon May 15 18:01:32 2006 @@ -407,8 +407,6 @@ int x; socklen_t len; wordlist *s; - if (Config2.Accel.on && !Config.onoff.accel_with_proxy) - return; if ((port = Config.Port.icp) <= 0) return; enter_suid(); Index: squid/src/locrewrite.c diff -u /dev/null squid/src/locrewrite.c:1.1.8.1 --- /dev/null Thu Jan 1 01:00:00 1970 +++ squid/src/locrewrite.c Mon May 15 18:01:32 2006 @@ -0,0 +1,161 @@ + +/* + * $Id$ + * + * DEBUG: section 29 Redirector + * AUTHOR: Henrik Nordstrom + * BASED ON: redirect.c by Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +typedef struct { + void *data; + char *orig_url; + RH *handler; +} rewriteStateData; + +static HLPCB locationRewriteHandleReply; +static void locationRewriteStateFree(rewriteStateData * r); +static helper *locrewriters = NULL; +static OBJH locationRewriteStats; +static int n_bypassed = 0; +CBDATA_TYPE(rewriteStateData); + +static void +locationRewriteHandleReply(void *data, char *reply) +{ + rewriteStateData *r = data; + int valid; + char *t; + debug(29, 5) ("rewriteHandleRead: {%s}\n", reply ? reply : ""); + if (reply) { + if ((t = strchr(reply, ' '))) + *t = '\0'; + if (*reply == '\0') + reply = NULL; + } + valid = cbdataValid(r->data); + cbdataUnlock(r->data); + if (valid) + r->handler(r->data, reply); + locationRewriteStateFree(r); +} + +static void +locationRewriteStateFree(rewriteStateData * r) +{ + safe_free(r->orig_url); + cbdataFree(r); +} + +static void +locationRewriteStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "Redirector Statistics:\n"); + helperStats(sentry, locrewriters); + if (Config.onoff.redirector_bypass) + storeAppendPrintf(sentry, "\nNumber of requests bypassed " + "because all rewriters were busy: %d\n", n_bypassed); +} + +/**** PUBLIC FUNCTIONS ****/ + +void +locationRewriteStart(HttpReply * rep, clientHttpRequest * http, RH * handler, void *data) +{ + rewriteStateData *r = NULL; + const char *location = httpHeaderGetStr(&rep->header, HDR_LOCATION); + const char *urlgroup; + char buf[8192]; + + if (http->orig_request && http->orig_request->urlgroup) + urlgroup = http->orig_request->urlgroup; + else if (http->request && http->request->urlgroup) + urlgroup = http->request->urlgroup; + else + urlgroup = NULL; + + assert(handler); + if (!urlgroup || !*urlgroup) + urlgroup = "-"; + debug(29, 5) ("locationRewriteStart: '%s'\n", location); + if (Config.Program.location_rewrite.command == NULL) { + handler(data, NULL); + return; + } + if (Config.onoff.redirector_bypass && locrewriters->stats.queue_size) { + /* Skip rewriter if there is one request queued */ + n_bypassed++; + handler(data, NULL); + return; + } + r = cbdataAlloc(rewriteStateData); + r->orig_url = xstrdup(location); + r->handler = handler; + r->data = data; + cbdataLock(r->data); + snprintf(buf, 8192, "%s %s %s\n", + r->orig_url, http->uri, urlgroup); + helperSubmit(locrewriters, buf, locationRewriteHandleReply, r); +} + +void +locationRewriteInit(void) +{ + static int init = 0; + if (!Config.Program.location_rewrite.command) + return; + if (locrewriters == NULL) + locrewriters = helperCreate("location_rewriter"); + locrewriters->cmdline = Config.Program.location_rewrite.command; + locrewriters->n_to_start = Config.Program.location_rewrite.children; + locrewriters->ipc_type = IPC_TCP_SOCKET; + helperOpenServers(locrewriters); + if (!init) { + cachemgrRegister("location_rewriter", + "Location Rewriter Stats", + locationRewriteStats, 0, 1); + init = 1; + CBDATA_INIT_TYPE(rewriteStateData); + } +} + +void +locationRewriteShutdown(void) +{ + if (!locrewriters) + return; + helperShutdown(locrewriters); + if (!shutting_down) + return; + helperFree(locrewriters); + locrewriters = NULL; +} Index: squid/src/main.c diff -u squid/src/main.c:1.44 squid/src/main.c:1.44.2.1 --- squid/src/main.c:1.44 Mon May 15 08:52:05 2006 +++ squid/src/main.c Mon May 15 18:01:32 2006 @@ -136,7 +136,14 @@ opt_store_doublecheck = 1; break; case 'V': - vhost_mode = 1; + if (Config.Sockaddr.http) + Config.Sockaddr.http->vhost = 1; +#if USE_SSL + else if (Config.Sockaddr.https) + Config.Sockaddr.https->http.vhost = 1; +#endif + else + fatal("No http_port specified\n"); break; case 'X': /* force full debugging */ @@ -310,6 +317,9 @@ #if USE_CARP carpInit(); #endif + peerSourceHashInit(); + peerUserHashInit(); + peerMonitorInit(); } void @@ -360,6 +370,7 @@ idnsShutdown(); #endif redirectShutdown(); + locationRewriteShutdown(); authenticateShutdown(); externalAclShutdown(); storeDirCloseSwapLogs(); @@ -387,6 +398,7 @@ idnsInit(); #endif redirectInit(); + locationRewriteInit(); authenticateInit(&Config.authConfig); externalAclInit(); #if USE_WCCP @@ -396,18 +408,14 @@ wccp2Init(); #endif serverConnectionsOpen(); - if (theOutIcpConnection >= 0) { - if (!Config2.Accel.on || Config.onoff.accel_with_proxy) - neighbors_open(theOutIcpConnection); - else - debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n"); - } + neighbors_init(); storeDirOpenSwapLogs(); mimeInit(Config.mimeTablePathname); eventCleanup(); writePidFile(); /* write PID file */ debug(1, 1) ("Ready to serve requests.\n"); reconfiguring = 0; + peerMonitorInit(); } static void @@ -418,6 +426,7 @@ dnsShutdown(); #endif redirectShutdown(); + locationRewriteShutdown(); authenticateShutdown(); externalAclShutdown(); _db_rotate_log(); /* cache.log */ @@ -434,6 +443,7 @@ dnsInit(); #endif redirectInit(); + locationRewriteInit(); authenticateInit(&Config.authConfig); externalAclInit(); } @@ -519,6 +529,8 @@ idnsInit(); #endif redirectInit(); + locationRewriteInit(); + errorMapInit(); authenticateInit(&Config.authConfig); externalAclInit(); useragentOpenLog(); @@ -563,12 +575,7 @@ wccp2Init(); #endif serverConnectionsOpen(); - if (theOutIcpConnection >= 0) { - if (!Config2.Accel.on || Config.onoff.accel_with_proxy) - neighbors_open(theOutIcpConnection); - else - debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n"); - } + neighbors_init(); if (Config.chroot_dir) no_suid(); if (!configured_once) @@ -980,6 +987,7 @@ #endif redirectShutdown(); externalAclShutdown(); + locationRewriteShutdown(); icpConnectionClose(); #if USE_HTCP htcpSocketClose(); Index: squid/src/mem.c diff -u squid/src/mem.c:1.23 squid/src/mem.c:1.23.2.1 --- squid/src/mem.c:1.23 Fri May 12 15:51:56 2006 +++ squid/src/mem.c Mon May 15 18:01:32 2006 @@ -215,6 +215,7 @@ memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0); memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0); memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0); + memDataInit(MEM_ACL_REQUEST_TYPE, "acl_request_type", sizeof(acl_request_type), 0); memDataInit(MEM_AUTH_USER_T, "auth_user_t", sizeof(auth_user_t), 0); memDataInit(MEM_AUTH_USER_HASH, "auth_user_hash_pointer", Index: squid/src/mib.txt diff -u squid/src/mib.txt:1.6 squid/src/mib.txt:1.6.2.1 --- squid/src/mib.txt:1.6 Sun May 14 02:50:55 2006 +++ squid/src/mib.txt Mon May 15 18:01:32 2006 @@ -686,7 +686,7 @@ the peer caches, complete with info " ::= { cacheMesh 1 } - cachePeerEntry OBJECT-TYPE + OLDcachePeerEntry OBJECT-TYPE SYNTAX CachePeerEntry MAX-ACCESS not-accessible STATUS current @@ -695,7 +695,18 @@ INDEX { cachePeerAddr } ::= { cachePeerTable 1 } + cachePeerEntry OBJECT-TYPE + SYNTAX CachePeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + " An entry in cachePeerTable " + INDEX { cachePeerIndex } + ::= { cachePeerTable 2 } + CachePeerEntry ::= SEQUENCE { + cachePeerIndex Integer32, + cachePeerHost DisplayString, cachePeerName DisplayString, cachePeerAddr IpAddress, cachePeerPortHttp Integer32 (1..65535), @@ -817,6 +828,22 @@ " Number of keepalives received " ::= { cachePeerEntry 13 } + cachePeerIndex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " Reference Index for each peer " + ::= { cachePeerEntry 14 } + + cachePeerHost OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " The FQDN name for the peer cache " + ::= { cachePeerEntry 15 } + --- --- Table of cache's clients, with statistics. Children caches can be identified --- by non-zero number of ICP requests (unless browsers start using ICP). Index: squid/src/neighbors.c diff -u squid/src/neighbors.c:1.21 squid/src/neighbors.c:1.21.4.1 --- squid/src/neighbors.c:1.21 Fri Apr 28 04:10:52 2006 +++ squid/src/neighbors.c Mon May 15 18:01:32 2006 @@ -362,7 +362,7 @@ } void -neighbors_open(int fd) +neighbors_init(void) { struct sockaddr_in name; socklen_t len = sizeof(struct sockaddr_in); @@ -370,25 +370,27 @@ const char *me = getMyHostname(); peer *this; peer *next; - memset(&name, '\0', sizeof(struct sockaddr_in)); - if (getsockname(fd, (struct sockaddr *) &name, &len) < 0) - debug(15, 1) ("getsockname(%d,%p,%p) failed.\n", fd, &name, &len); - for (this = Config.peers; this; this = next) { - sockaddr_in_list *s; - next = this->next; - if (0 != strcmp(this->host, me)) - continue; - for (s = Config.Sockaddr.http; s; s = s->next) { - if (this->http_port != ntohs(s->s.sin_port)) + int fd = theInIcpConnection; + if (fd >= 0) { + memset(&name, '\0', sizeof(struct sockaddr_in)); + if (getsockname(fd, (struct sockaddr *) &name, &len) < 0) + debug(15, 1) ("getsockname(%d,%p,%p) failed.\n", fd, &name, &len); + for (this = Config.peers; this; this = next) { + http_port_list *s; + next = this->next; + if (0 != strcmp(this->host, me)) continue; - debug(15, 1) ("WARNING: Peer looks like this host\n"); - debug(15, 1) (" Ignoring %s %s/%d/%d\n", - neighborTypeStr(this), this->host, this->http_port, - this->icp.port); - neighborRemove(this); + for (s = Config.Sockaddr.http; s; s = s->next) { + if (this->http_port != ntohs(s->s.sin_port)) + continue; + debug(15, 1) ("WARNING: Peer looks like this host\n"); + debug(15, 1) (" Ignoring %s %s/%d/%d\n", + neighborTypeStr(this), this->host, this->http_port, + this->icp.port); + neighborRemove(this); + } } } - peerRefreshDNS((void *) 1); if (0 == echo_hdr.opcode) { echo_hdr.opcode = ICP_SECHO; @@ -405,9 +407,11 @@ cachemgrRegister("server_list", "Peer Cache Statistics", neighborDumpPeers, 0, 1); - cachemgrRegister("non_peers", - "List of Unknown sites sending ICP messages", - neighborDumpNonPeers, 0, 1); + if (theInIcpConnection >= 0) { + cachemgrRegister("non_peers", + "List of Unknown sites sending ICP messages", + neighborDumpNonPeers, 0, 1); + } } int @@ -505,9 +509,8 @@ /* Neighbor is dead; ping it anyway, but don't expect a reply */ /* log it once at the threshold */ if (p->stats.logged_state == PEER_ALIVE) { - debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected DEAD %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_DEAD; } } @@ -681,9 +684,8 @@ neighborAlive(peer * p, const MemObject * mem, const icp_common_t * header) { if (p->stats.logged_state == PEER_DEAD && p->tcp_up) { - debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_ALIVE; } p->stats.last_reply = squid_curtime; @@ -714,9 +716,8 @@ neighborAliveHtcp(peer * p, const MemObject * mem, const htcpReplyData * htcp) { if (p->stats.logged_state == PEER_DEAD && p->tcp_up) { - debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_ALIVE; } p->stats.last_reply = squid_curtime; @@ -907,7 +908,7 @@ { peer *p = NULL; for (p = Config.peers; p; p = p->next) { - if (!strcasecmp(name, p->host)) + if (!strcasecmp(name, p->name)) break; } return p; @@ -918,7 +919,7 @@ { peer *p = NULL; for (p = Config.peers; p; p = p->next) { - if (strcasecmp(name, p->host)) + if (strcasecmp(name, p->name)) continue; if (port != p->http_port) continue; @@ -934,6 +935,10 @@ if (!peerProbeConnect((peer *) p)) return 0; } + if (p->stats.logged_state != PEER_ALIVE) + return 0; + if (p->monitor.state != PEER_ALIVE) + return 0; if (p->options.no_query) return 1; if (p->stats.probe_start != 0 && @@ -963,6 +968,8 @@ } aclDestroyAccessList(&p->access); safe_free(p->host); + safe_free(p->name); + safe_free(p->domain); #if USE_CACHE_DIGESTS if (p->digest) { PeerDigest *pd = p->digest; @@ -1033,8 +1040,9 @@ eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 180.0, 1); return; } - for (p = Config.peers; p; p = p->next) + for (p = Config.peers; p; p = p->next) { ipcache_nbgethostbyname(p->host, peerDNSConfigure, p); + } /* Reconfigure the peers every hour */ eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 3600.0, 1); } @@ -1049,9 +1057,8 @@ } p->tcp_up--; if (!p->tcp_up) { - debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected DEAD %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_DEAD; } } @@ -1068,9 +1075,9 @@ { if (!p->tcp_up) { debug(15, 2) ("TCP connection to %s/%d succeded\n", p->host, p->http_port); - debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); + peerMonitorNow(p); p->stats.logged_state = PEER_ALIVE; } p->tcp_up = PEER_TCP_MAGIC_COUNT; @@ -1250,8 +1257,14 @@ storeAppendPrintf(sentry, " round-robin"); if (p->options.mcast_responder) storeAppendPrintf(sentry, " multicast-responder"); + if (p->weight != 1) + storeAppendPrintf(sentry, " weight=%d", p->weight); if (p->options.closest_only) storeAppendPrintf(sentry, " closest-only"); + if (p->options.userhash) + storeAppendPrintf(sentry, " userhash"); + if (p->options.sourcehash) + storeAppendPrintf(sentry, " sourcehash"); #if USE_HTCP if (p->options.htcp) storeAppendPrintf(sentry, " htcp"); @@ -1266,6 +1279,29 @@ storeAppendPrintf(sentry, " login=%s", p->login); if (p->mcast.ttl > 0) storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl); + if (p->connect_timeout > 0) + storeAppendPrintf(sentry, " connect-timeout=%d", (int) p->connect_timeout); +#if USE_CACHE_DIGESTS + if (p->digest_url) + storeAppendPrintf(sentry, " digest-url=%s", p->digest_url); +#endif + if (p->options.allow_miss) + storeAppendPrintf(sentry, " allow-miss"); + if (p->max_conn > 0) + storeAppendPrintf(sentry, " max-conn=%d", p->max_conn); + if (p->options.originserver) + storeAppendPrintf(sentry, " originserver"); + /* name is used in the heading */ + if (p->monitor.url) + storeAppendPrintf(sentry, " monitorurl=%s", p->monitor.url); + if (p->monitor.min > 0 || p->monitor.max > 0) { + if (p->monitor.max > 0) + storeAppendPrintf(sentry, " monitorsize=%d:%d", p->monitor.min, p->monitor.max); + else + storeAppendPrintf(sentry, " monitorsize=%d", p->monitor.min); + } + if (p->domain) + storeAppendPrintf(sentry, " forceddomain=%s", p->domain); storeAppendPrintf(sentry, "\n"); } @@ -1280,8 +1316,10 @@ storeAppendPrintf(sentry, "There are no neighbors installed.\n"); for (e = peers; e; e = e->next) { assert(e->host != NULL); - storeAppendPrintf(sentry, "\n%-11.11s: %s/%d/%d\n", + storeAppendPrintf(sentry, "\n%-11.11s: %s\n", neighborTypeStr(e), + e->name); + storeAppendPrintf(sentry, "Host : %s/%d/%d\n", e->host, e->http_port, e->icp.port); @@ -1295,42 +1333,49 @@ neighborUp(e) ? "Up" : "Down"); storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt); storeAppendPrintf(sentry, "OPEN CONNS : %d\n", e->stats.conn_open); - storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n", - (int) (squid_curtime - e->stats.last_query)); - storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n", - (int) (squid_curtime - e->stats.last_reply)); - storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent); - storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n", - e->stats.pings_acked, - percent(e->stats.pings_acked, e->stats.pings_sent)); + if (!e->options.no_query) { + storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n", + (int) (squid_curtime - e->stats.last_query)); + if (e->stats.last_reply > 0) + storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n", + (int) (squid_curtime - e->stats.last_reply)); + else + storeAppendPrintf(sentry, "LAST REPLY : none received\n"); + storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent); + storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n", + e->stats.pings_acked, + percent(e->stats.pings_acked, e->stats.pings_sent)); + } storeAppendPrintf(sentry, "FETCHES : %8d %3d%%\n", e->stats.fetches, percent(e->stats.fetches, e->stats.pings_acked)); storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n", e->stats.ignored_replies, percent(e->stats.ignored_replies, e->stats.pings_acked)); - storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n"); + if (!e->options.no_query) { + storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n"); #if USE_HTCP - if (e->options.htcp) { - storeAppendPrintf(sentry, "\tMisses\t%8d %3d%%\n", - e->htcp.counts[0], - percent(e->htcp.counts[0], e->stats.pings_acked)); - storeAppendPrintf(sentry, "\tHits\t%8d %3d%%\n", - e->htcp.counts[1], - percent(e->htcp.counts[1], e->stats.pings_acked)); - } else { + if (e->options.htcp) { + storeAppendPrintf(sentry, "\tMisses\t%8d %3d%%\n", + e->htcp.counts[0], + percent(e->htcp.counts[0], e->stats.pings_acked)); + storeAppendPrintf(sentry, "\tHits\t%8d %3d%%\n", + e->htcp.counts[1], + percent(e->htcp.counts[1], e->stats.pings_acked)); + } else { #endif - for (op = ICP_INVALID; op < ICP_END; op++) { - if (e->icp.counts[op] == 0) - continue; - storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n", - icp_opcode_str[op], - e->icp.counts[op], - percent(e->icp.counts[op], e->stats.pings_acked)); - } + for (op = ICP_INVALID; op < ICP_END; op++) { + if (e->icp.counts[op] == 0) + continue; + storeAppendPrintf(sentry, " %12.12s : %8d %3d%%\n", + icp_opcode_str[op], + e->icp.counts[op], + percent(e->icp.counts[op], e->stats.pings_acked)); + } #if USE_HTCP - } + } #endif + } if (e->stats.last_connect_failure) { storeAppendPrintf(sentry, "Last failed connect() at: %s\n", mkhttpdlogtime(&(e->stats.last_connect_failure))); Index: squid/src/pconn.c diff -u squid/src/pconn.c:1.8 squid/src/pconn.c:1.8.4.1 --- squid/src/pconn.c:1.8 Fri Apr 28 04:10:53 2006 +++ squid/src/pconn.c Mon May 15 18:01:32 2006 @@ -49,7 +49,7 @@ static PF pconnRead; static PF pconnTimeout; -static const char *pconnKey(const char *host, u_short port); +static const char *pconnKey(const char *host, u_short port, const char *domain); static hash_table *table = NULL; static struct _pconn *pconnNew(const char *key); static void pconnDelete(struct _pconn *p); @@ -59,10 +59,13 @@ static MemPool *pconn_fds_pool = NULL; static const char * -pconnKey(const char *host, u_short port) +pconnKey(const char *host, u_short port, const char *domain) { LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN + 10); - snprintf(buf, SQUIDHOSTNAMELEN + 10, "%s.%d", host, (int) port); + if (domain) + snprintf(buf, SQUIDHOSTNAMELEN + 10, "%s:%d/%s", host, (int) port, domain); + else + snprintf(buf, SQUIDHOSTNAMELEN + 10, "%s:%d", host, (int) port); return buf; } @@ -184,11 +187,11 @@ } void -pconnPush(int fd, const char *host, u_short port) +pconnPush(int fd, const char *host, u_short port, const char *domain) { struct _pconn *p; int *old; - LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10); + const char *key; LOCAL_ARRAY(char, desc, FD_DESC_SZ); if (fdUsageHigh()) { debug(48, 3) ("pconnPush: Not many unused FDs\n"); @@ -199,7 +202,7 @@ return; } assert(table != NULL); - strcpy(key, pconnKey(host, port)); + key = pconnKey(host, port, domain); p = (struct _pconn *) hash_lookup(table, key); if (p == NULL) p = pconnNew(key); @@ -223,14 +226,14 @@ } int -pconnPop(const char *host, u_short port) +pconnPop(const char *host, u_short port, const char *domain) { struct _pconn *p; hash_link *hptr; int fd = -1; - LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10); + const char *key; assert(table != NULL); - strcpy(key, pconnKey(host, port)); + key = pconnKey(host, port, domain); hptr = hash_lookup(table, key); if (hptr != NULL) { p = (struct _pconn *) hptr; Index: squid/src/peer_monitor.c diff -u /dev/null squid/src/peer_monitor.c:1.1.30.1 --- /dev/null Thu Jan 1 01:00:00 1970 +++ squid/src/peer_monitor.c Mon May 15 18:01:32 2006 @@ -0,0 +1,245 @@ + +/* + * $Id$ + * + * DEBUG: section ?? Peer monitoring + * AUTHOR: Henrik Nordstrom + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#define DBG 1 +#include "squid.h" + +/* local types */ + +struct _PeerMonitor { + peer *peer; + time_t last_probe; + struct { + request_t *req; + StoreEntry *e; + store_client *sc; + int size; + http_status status; + int hdr_size; + int offset; + char *buf; + } running; + char name[40]; + char url[80]; +}; + +CBDATA_TYPE(PeerMonitor); + +static void peerMonitorCompleted(PeerMonitor * pm); + +static void +freePeerMonitor(void *data) +{ + PeerMonitor *pm = data; + if (cbdataValid(pm->peer)) + pm->peer->monitor.data = NULL; + cbdataUnlock(pm->peer); + pm->peer = NULL; +} + +static void +peerMonitorFetchReply(void *data, char *buf, ssize_t size) +{ + PeerMonitor *pm = data; + + if (size == 0 || !cbdataValid(pm->peer)) { + peerMonitorCompleted(pm); + } else { + pm->running.size += size; + pm->running.offset += size; + storeClientCopy(pm->running.sc, pm->running.e, pm->running.offset, pm->running.offset, 4096, buf, peerMonitorFetchReply, pm); + } +} + +static void +peerMonitorFetchReplyHeaders(void *data, char *buf, ssize_t size) +{ + PeerMonitor *pm = data; + size_t hdr_size; + + if (EBIT_TEST(pm->running.e->flags, ENTRY_ABORTED)) + goto completed; + if (size <= 0) + goto completed; + if (!cbdataValid(pm->peer)) + goto completed; + + if ((hdr_size = headersEnd(buf, size))) { + http_status status; + HttpReply *reply = pm->running.e->mem_obj->reply; + assert(reply); + /* httpReplyParse(reply, buf, hdr_size); */ + status = reply->sline.status; + pm->running.status = status; + if (status != HTTP_OK) + goto completed; + pm->running.size = size - hdr_size; + pm->running.offset = size; + storeClientCopy(pm->running.sc, pm->running.e, pm->running.offset, pm->running.offset, 4096, buf, peerMonitorFetchReply, pm); + } else { + /* need more data, do we have space? */ + if (size >= 4096) + goto completed; + else + storeClientCopy(pm->running.sc, pm->running.e, size, 0, 4096, buf, peerMonitorFetchReplyHeaders, pm); + } + return; + + completed: + /* We are fully done with this monitoring request. Clean up */ + peerMonitorCompleted(pm); + return; +} + +static void +peerMonitorRequest(void *data) +{ + PeerMonitor *pm = data; + char *url = pm->url; + request_t *req; + + if (!cbdataValid(pm->peer)) { + cbdataFree(pm); + return; + } + req = urlParse(METHOD_GET, url); + if (!req) { + debug(DBG, 1) ("peerMonitorRequest: Failed to parse URL '%s' for cache_peer %s\n", url, pm->peer->name); + cbdataFree(pm); + return; + } + pm->last_probe = squid_curtime; + + httpHeaderPutStr(&req->header, HDR_ACCEPT, "*/*"); + httpHeaderPutStr(&req->header, HDR_USER_AGENT, full_appname_string); + if (pm->peer->login) + xstrncpy(req->login, pm->peer->login, MAX_LOGIN_SZ); + pm->running.req = requestLink(req); + pm->running.e = storeCreateEntry(url, url, req->flags, req->method); + pm->running.sc = storeClientListAdd(pm->running.e, pm); + pm->running.buf = memAllocate(MEM_4K_BUF); + fwdStartPeer(pm->peer, pm->running.e, pm->running.req); + storeClientCopy(pm->running.sc, pm->running.e, 0, 0, 4096, pm->running.buf, peerMonitorFetchReplyHeaders, pm); + return; +} + +static void +peerMonitorCompleted(PeerMonitor * pm) +{ + int state = PEER_ALIVE; + peer *p = pm->peer; + storeUnregister(pm->running.sc, pm->running.e, pm); + storeUnlockObject(pm->running.e); + requestUnlink(pm->running.req); + memFree(pm->running.buf, MEM_4K_BUF); + if (!cbdataValid(pm->peer)) { + cbdataFree(pm); + return; + } + /* Figure out if the response was OK or not */ + if (pm->running.status != HTTP_OK) { + debug(DBG, 1) ("peerMonitor %s: Failed, status != 200 (%d)\n", + p->name, pm->running.status); + state = PEER_DEAD; + } else if (pm->running.size < p->monitor.min) { + debug(DBG, 1) ("peerMonitor %s: Failed, reply size %d < min %d\n", + p->name, pm->running.size, p->monitor.min); + state = PEER_DEAD; + } else if (pm->running.size > p->monitor.max && p->monitor.max > 0) { + debug(DBG, 1) ("peerMonitor %s: Failed, reply size %d > max %d\n", + p->name, pm->running.size, p->monitor.max); + state = PEER_DEAD; + } else { + debug(DBG, 2) ("peerMonitor %s: OK\n", p->name); + } + p->monitor.state = state; + if (state != p->stats.logged_state) { + switch (state) { + case PEER_ALIVE: + debug(DBG, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); + break; + case PEER_DEAD: + debug(DBG, 1) ("Detected DEAD %s: %s\n", + neighborTypeStr(p), p->name); + break; + } + p->stats.logged_state = state; + } + memset(&pm->running, 0, sizeof(pm->running)); + eventAdd(pm->name, peerMonitorRequest, pm, (double) (pm->last_probe + pm->peer->monitor.interval - current_dtime), 1); +} + +static void +peerMonitorStart(peer * peer) +{ + PeerMonitor *pm; + char *url = peer->monitor.url; + if (!url || !*url) + return; + if (!peer->monitor.interval) + return; + CBDATA_INIT_TYPE_FREECB(PeerMonitor, freePeerMonitor); + pm = cbdataAlloc(PeerMonitor); + snprintf(pm->name, sizeof(pm->name), "monitor %s", peer->name); + pm->peer = peer; + peer->monitor.data = pm; + cbdataLock(pm->peer); + if (*url == '/') { + snprintf(pm->url, sizeof(pm->url), "http://%s:%d%s", + pm->peer->host, pm->peer->http_port, url); + } else { + xstrncpy(pm->url, url, sizeof(pm->url)); + } + peerMonitorRequest(pm); +} + +void +peerMonitorNow(peer * peer) +{ + PeerMonitor *pm = peer->monitor.data; + if (pm && !pm->running.req) { + eventDelete(peerMonitorRequest, pm); + peerMonitorRequest(pm); + } +} + +void +peerMonitorInit(void) +{ + peer *p; + for (p = Config.peers; p; p = p->next) + peerMonitorStart(p); +} Index: squid/src/peer_select.c diff -u squid/src/peer_select.c:1.18 squid/src/peer_select.c:1.18.2.1 --- squid/src/peer_select.c:1.18 Mon May 15 16:51:56 2006 +++ squid/src/peer_select.c Mon May 15 18:01:32 2006 @@ -59,6 +59,8 @@ "CARP", #endif "ANY_PARENT", + "USERHASH_PARENT", + "SOURCEHASH_PARENT", "INVALID CODE" }; @@ -90,7 +92,6 @@ static void peerGetSomeDirect(ps_state *); static void peerGetSomeParent(ps_state *); static void peerGetAllParents(ps_state *); -static void peerAddFwdServer(FwdServer **, peer *, hier_code); static void peerSelectStateFree(ps_state * psstate) @@ -443,6 +444,10 @@ return; if ((p = getDefaultParent(request))) { code = DEFAULT_PARENT; + } else if ((p = peerUserHashSelectParent(request))) { + code = USERHASH_PARENT; + } else if ((p = peerSourceHashSelectParent(request))) { + code = SOURCEHASH_PARENT; } else if ((p = getRoundRobinParent(request))) { code = ROUNDROBIN_PARENT; } else if ((p = getFirstUpParent(request))) { @@ -644,7 +649,7 @@ debug(44, 1) ("peerHandlePingReply: unknown protocol_t %d\n", (int) proto); } -static void +void peerAddFwdServer(FwdServer ** FS, peer * p, hier_code code) { FwdServer *fs = memAllocate(MEM_FWD_SERVER); Index: squid/src/peer_sourcehash.c diff -u /dev/null squid/src/peer_sourcehash.c:1.1.18.1 --- /dev/null Thu Jan 1 01:00:00 1970 +++ squid/src/peer_sourcehash.c Mon May 15 18:01:32 2006 @@ -0,0 +1,162 @@ + +/* + * $Id$ + * + * DEBUG: section 44 Peer user hash based selection + * AUTHOR: Henrik Nordstrom + * BASED ON: carp.c by Eric Stern + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (((sizeof(unsigned long)*8)-(n))))) + +static int n_sourcehash_peers = 0; +static peer **sourcehash_peers = NULL; + +static int +peerSortWeight(const void *a, const void *b) +{ + const peer *const *p1 = a, *const *p2 = b; + return (*p1)->weight - (*p2)->weight; +} + +void +peerSourceHashInit(void) +{ + int W = 0; + int K; + int k; + double P_last, X_last, Xn; + peer *p; + peer **P; + char *t; + /* Clean up */ + for (k = 0; k < n_sourcehash_peers; k++) { + cbdataUnlock(sourcehash_peers[k]); + } + safe_free(sourcehash_peers); + n_sourcehash_peers = 0; + /* find out which peers we have */ + for (p = Config.peers; p; p = p->next) { + if (!p->options.sourcehash) + continue; + assert(p->type == PEER_PARENT); + if (p->weight == 0) + continue; + n_sourcehash_peers++; + W += p->weight; + } + if (n_sourcehash_peers == 0) + return; + sourcehash_peers = xcalloc(n_sourcehash_peers, sizeof(*sourcehash_peers)); + /* Build a list of the found peers and calculate hashes and load factors */ + for (P = sourcehash_peers, p = Config.peers; p; p = p->next) { + if (!p->options.sourcehash) + continue; + if (p->weight == 0) + continue; + /* calculate this peers hash */ + p->sourcehash.hash = 0; + for (t = p->host; *t != 0; t++) + p->sourcehash.hash += ROTATE_LEFT(p->sourcehash.hash, 19) + (unsigned int) *t; + p->sourcehash.hash += p->sourcehash.hash * 0x62531965; + p->sourcehash.hash = ROTATE_LEFT(p->sourcehash.hash, 21); + /* and load factor */ + p->sourcehash.load_factor = ((double) p->weight) / (double) W; + if (floor(p->sourcehash.load_factor * 1000.0) == 0.0) + p->sourcehash.load_factor = 0.0; + /* add it to our list of peers */ + *P++ = p; + cbdataLock(p); + } + /* Sort our list on weight */ + qsort(sourcehash_peers, n_sourcehash_peers, sizeof(*sourcehash_peers), peerSortWeight); + /* Calculate the load factor multipliers X_k + * + * X_1 = pow ((K*p_1), (1/K)) + * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1}) + * X_k += pow ((X_{k-1}, {K-k+1}) + * X_k = pow (X_k, {1/(K-k+1)}) + * simplified to have X_1 part of the loop + */ + K = n_sourcehash_peers; + P_last = 0.0; /* Empty P_0 */ + Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */ + X_last = 0.0; /* Empty X_0, nullifies the first pow statement */ + for (k = 1; k <= K; k++) { + double Kk1 = (double) (K - k + 1); + p = sourcehash_peers[k - 1]; + p->sourcehash.load_multiplier = (Kk1 * (p->sourcehash.load_factor - P_last)) / Xn; + p->sourcehash.load_multiplier += pow(X_last, Kk1); + p->sourcehash.load_multiplier = pow(p->sourcehash.load_multiplier, 1.0 / Kk1); + Xn *= p->sourcehash.load_multiplier; + X_last = p->sourcehash.load_multiplier; + P_last = p->sourcehash.load_factor; + } +} + +peer * +peerSourceHashSelectParent(request_t * 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; + char *key = NULL; + + key = inet_ntoa(request->client_addr); + + /* calculate hash key */ + debug(39, 2) ("peerSourceHashSelectParent: Calculating hash for %s\n", key); + for (c = key; *c != 0; c++) + user_hash += ROTATE_LEFT(user_hash, 19) + *c; + /* select peer */ + for (k = 0; k < n_sourcehash_peers; k++) { + tp = sourcehash_peers[k]; + combined_hash = (user_hash ^ tp->sourcehash.hash); + combined_hash += combined_hash * 0x62531965; + combined_hash = ROTATE_LEFT(combined_hash, 21); + score = combined_hash * tp->sourcehash.load_multiplier; + debug(39, 3) ("peerSourceHashSelectParent: %s combined_hash %u score %.0f\n", + tp->host, combined_hash, score); + if ((score > high_score) && peerHTTPOkay(tp, request)) { + p = tp; + high_score = score; + } + } + if (p) + debug(39, 2) ("peerSourceHashSelectParent: selected %s\n", p->host); + return p; +} Index: squid/src/peer_userhash.c diff -u /dev/null squid/src/peer_userhash.c:1.1.30.1 --- /dev/null Thu Jan 1 01:00:00 1970 +++ squid/src/peer_userhash.c Mon May 15 18:01:32 2006 @@ -0,0 +1,165 @@ + +/* + * $Id$ + * + * DEBUG: section 44 Peer user hash based selection + * AUTHOR: Henrik Nordstrom + * BASED ON: carp.c by Eric Stern + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (((sizeof(unsigned long)*8)-(n))))) + +static int n_userhash_peers = 0; +static peer **userhash_peers = NULL; + +static int +peerSortWeight(const void *a, const void *b) +{ + const peer *const *p1 = a, *const *p2 = b; + return (*p1)->weight - (*p2)->weight; +} + +void +peerUserHashInit(void) +{ + int W = 0; + int K; + int k; + double P_last, X_last, Xn; + peer *p; + peer **P; + char *t; + /* Clean up */ + for (k = 0; k < n_userhash_peers; k++) { + cbdataUnlock(userhash_peers[k]); + } + safe_free(userhash_peers); + n_userhash_peers = 0; + /* find out which peers we have */ + for (p = Config.peers; p; p = p->next) { + if (!p->options.userhash) + continue; + assert(p->type == PEER_PARENT); + if (p->weight == 0) + continue; + n_userhash_peers++; + W += p->weight; + } + if (n_userhash_peers == 0) + return; + userhash_peers = xcalloc(n_userhash_peers, sizeof(*userhash_peers)); + /* Build a list of the found peers and calculate hashes and load factors */ + for (P = userhash_peers, p = Config.peers; p; p = p->next) { + if (!p->options.userhash) + continue; + if (p->weight == 0) + continue; + /* calculate this peers hash */ + p->userhash.hash = 0; + for (t = p->host; *t != 0; t++) + p->userhash.hash += ROTATE_LEFT(p->userhash.hash, 19) + (unsigned int) *t; + p->userhash.hash += p->userhash.hash * 0x62531965; + p->userhash.hash = ROTATE_LEFT(p->userhash.hash, 21); + /* and load factor */ + p->userhash.load_factor = ((double) p->weight) / (double) W; + if (floor(p->userhash.load_factor * 1000.0) == 0.0) + p->userhash.load_factor = 0.0; + /* add it to our list of peers */ + *P++ = p; + cbdataLock(p); + } + /* Sort our list on weight */ + qsort(userhash_peers, n_userhash_peers, sizeof(*userhash_peers), peerSortWeight); + /* Calculate the load factor multipliers X_k + * + * X_1 = pow ((K*p_1), (1/K)) + * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1}) + * X_k += pow ((X_{k-1}, {K-k+1}) + * X_k = pow (X_k, {1/(K-k+1)}) + * simplified to have X_1 part of the loop + */ + K = n_userhash_peers; + P_last = 0.0; /* Empty P_0 */ + Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */ + X_last = 0.0; /* Empty X_0, nullifies the first pow statement */ + for (k = 1; k <= K; k++) { + double Kk1 = (double) (K - k + 1); + p = userhash_peers[k - 1]; + p->userhash.load_multiplier = (Kk1 * (p->userhash.load_factor - P_last)) / Xn; + p->userhash.load_multiplier += pow(X_last, Kk1); + p->userhash.load_multiplier = pow(p->userhash.load_multiplier, 1.0 / Kk1); + Xn *= p->userhash.load_multiplier; + X_last = p->userhash.load_multiplier; + P_last = p->userhash.load_factor; + } +} + +peer * +peerUserHashSelectParent(request_t * 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; + char *key = NULL; + + if (request->auth_user_request) + key = authenticateUserRequestUsername(request->auth_user_request); + if (!key) + return NULL; + + /* calculate hash key */ + debug(39, 2) ("peerUserHashSelectParent: Calculating hash for %s\n", key); + for (c = key; *c != 0; c++) + user_hash += ROTATE_LEFT(user_hash, 19) + *c; + /* select peer */ + for (k = 0; k < n_userhash_peers; k++) { + tp = userhash_peers[k]; + combined_hash = (user_hash ^ tp->userhash.hash); + combined_hash += combined_hash * 0x62531965; + combined_hash = ROTATE_LEFT(combined_hash, 21); + score = combined_hash * tp->userhash.load_multiplier; + debug(39, 3) ("peerUserHashSelectParent: %s combined_hash %u score %.0f\n", + tp->host, combined_hash, score); + if ((score > high_score) && peerHTTPOkay(tp, request)) { + p = tp; + high_score = score; + } + } + if (p) + debug(39, 2) ("peerUserHashSelectParent: selected %s\n", p->host); + return p; +} Index: squid/src/protos.h diff -u squid/src/protos.h:1.72 squid/src/protos.h:1.72.2.1 --- squid/src/protos.h:1.72 Mon May 15 15:50:49 2006 +++ squid/src/protos.h Mon May 15 18:01:32 2006 @@ -661,7 +661,7 @@ extern void neighborAddAcl(const char *, const char *); extern void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *); extern void neighborAdd(const char *, const char *, int, int, int, int, int); -extern void neighbors_open(int); +extern void neighbors_init(void); extern peer *peerFindByName(const char *); extern peer *peerFindByNameAndPort(const char *, unsigned short); extern peer *getDefaultParent(request_t * request); @@ -684,6 +684,7 @@ #if USE_HTCP extern void neighborsHtcpReply(const cache_key *, htcpReplyData *, const struct sockaddr_in *); #endif +extern void peerAddFwdServer(FwdServer ** FS, peer * p, hier_code code); extern void netdbInit(void); extern void netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt); @@ -716,6 +717,7 @@ /* forward.c */ extern void fwdStart(int, StoreEntry *, request_t *); +extern void fwdStartPeer(peer *, StoreEntry *, request_t *); extern DEFER fwdCheckDeferRead; extern void fwdFail(FwdState *, ErrorState *); extern void fwdUnregister(int fd, FwdState *); @@ -737,6 +739,10 @@ extern void redirectInit(void); extern void redirectShutdown(void); +extern void locationRewriteStart(HttpReply *, clientHttpRequest *, RH *, void *); +extern void locationRewriteInit(void); +extern void locationRewriteShutdown(void); + /* auth_modules.c */ extern void authSchemeSetup(void); @@ -1142,9 +1148,10 @@ extern void errorStateFree(ErrorState * err); extern int errorReservePageId(const char *page_name); extern ErrorState *errorCon(err_type type, http_status); +extern int errorPageId(const char *page_name); -extern void pconnPush(int, const char *host, u_short port); -extern int pconnPop(const char *host, u_short port); +extern void pconnPush(int, const char *host, u_short port, const char *domain); +extern int pconnPop(const char *host, u_short port, const char *domain); extern void pconnInit(void); extern int asnMatchIp(void *, struct in_addr); @@ -1240,6 +1247,11 @@ extern peer *carpSelectParent(request_t *); #endif +extern void peerUserHashInit(void); +extern peer *peerUserHashSelectParent(request_t *); +extern void peerSourceHashInit(void); +extern peer *peerSourceHashSelectParent(request_t *); + #if DELAY_POOLS extern void delayPoolsInit(void); extern void delayInitDelayData(unsigned short pools); @@ -1361,4 +1373,12 @@ extern void dump_wccp2_service_info(StoreEntry * e, const char *label, void *v); #endif +/* peer_monitor.c */ +extern void peerMonitorInit(void); +extern void peerMonitorNow(peer *); + +/* errormap.c */ +extern void errorMapInit(void); +extern int errorMapStart(const errormap * map, request_t * req, HttpReply * reply, const char *aclname, ERRMAPCB * callback, void *data); + #endif /* SQUID_PROTOS_H */ Index: squid/src/redirect.c diff -u squid/src/redirect.c:1.11 squid/src/redirect.c:1.11.4.1 --- squid/src/redirect.c:1.11 Fri Apr 28 04:10:53 2006 +++ squid/src/redirect.c Mon May 15 18:01:32 2006 @@ -96,6 +96,7 @@ ConnStateData *conn = http->conn; redirectStateData *r = NULL; const char *fqdn; + char *urlgroup = conn->port->urlgroup; char buf[8192]; assert(http); assert(handler); @@ -122,12 +123,13 @@ cbdataLock(r->data); if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL) fqdn = dash_str; - snprintf(buf, 8192, "%s %s/%s %s %s\n", + snprintf(buf, 8192, "%s %s/%s %s %s %s\n", r->orig_url, inet_ntoa(r->client_addr), fqdn, r->client_ident[0] ? rfc1738_escape(r->client_ident) : dash_str, - r->method_s); + r->method_s, + urlgroup ? urlgroup : "-"); helperSubmit(redirectors, buf, redirectHandleReply, r); } @@ -135,17 +137,17 @@ redirectInit(void) { static int init = 0; - if (!Config.Program.redirect) + if (!Config.Program.url_rewrite.command) return; if (redirectors == NULL) - redirectors = helperCreate("redirector"); - redirectors->cmdline = Config.Program.redirect; - redirectors->n_to_start = Config.redirectChildren; + redirectors = helperCreate("url_rewriter"); + redirectors->cmdline = Config.Program.url_rewrite.command; + redirectors->n_to_start = Config.Program.url_rewrite.children; redirectors->ipc_type = IPC_TCP_SOCKET; helperOpenServers(redirectors); if (!init) { - cachemgrRegister("redirector", - "URL Redirector Stats", + cachemgrRegister("url_rewriter", + "URL Rewriter Stats", redirectStats, 0, 1); init = 1; CBDATA_INIT_TYPE(redirectStateData); Index: squid/src/snmp_agent.c diff -u squid/src/snmp_agent.c:1.11 squid/src/snmp_agent.c:1.11.2.1 --- squid/src/snmp_agent.c:1.11 Sun May 14 02:50:55 2006 +++ squid/src/snmp_agent.c Mon May 15 18:01:32 2006 @@ -153,21 +153,46 @@ { variable_list *Answer = NULL; struct in_addr *laddr; + int loop, index = 0; char *cp = NULL; peer *p = NULL; int cnt = 0; debug(49, 5) ("snmp_meshPtblFn: peer %d requested!\n", Var->name[LEN_SQ_MESH + 3]); *ErrP = SNMP_ERR_NOERROR; - laddr = oid2addr(&Var->name[LEN_SQ_MESH + 3]); - for (p = Config.peers; p != NULL; p = p->next, cnt++) - if (p->in_addr.sin_addr.s_addr == laddr->s_addr) - break; + switch (Var->name[LEN_SQ_MESH + 1]) { + case 1: + laddr = oid2addr(&Var->name[LEN_SQ_MESH + 3]); + for (p = Config.peers; p != NULL; p = p->next, cnt++) { + index++; + if (p->in_addr.sin_addr.s_addr == laddr->s_addr) + break; + } + break; + case 2: + index = Var->name[LEN_SQ_MESH + 3]; + loop = 1; + p = Config.peers; + while (loop != index && p != NULL) { + loop++; + p = p->next; + } + break; + default: + break; + } if (p == NULL) { *ErrP = SNMP_ERR_NOSUCHNAME; return NULL; } switch (Var->name[LEN_SQ_MESH + 2]) { case MESH_PTBL_NAME: + cp = p->name; + Answer = snmp_var_new(Var->name, Var->name_length); + Answer->type = ASN_OCTET_STR; + Answer->val_len = strlen(cp); + Answer->val.string = (u_char *) xstrdup(cp); + break; + case MESH_PTBL_HOST: cp = p->host; Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; @@ -234,6 +259,11 @@ p->stats.n_keepalives_recv, SMI_COUNTER32); break; + case MESH_PTBL_INDEX: + Answer = snmp_var_new_integer(Var->name, Var->name_length, + index, + ASN_INTEGER); + break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; Index: squid/src/snmp_core.c diff -u squid/src/snmp_core.c:1.12 squid/src/snmp_core.c:1.12.2.1 --- squid/src/snmp_core.c:1.12 Sun May 14 02:50:55 2006 +++ squid/src/snmp_core.c Mon May 15 18:01:32 2006 @@ -65,6 +65,7 @@ static oid *static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); +static oid *peer_InstIndex(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static void snmpDecodePacket(snmp_request_t * rq); static void snmpConstructReponse(snmp_request_t * rq); @@ -282,9 +283,9 @@ snmpAddNode(snmpCreateOid(LEN_SQ_MESH, SQ_MESH), LEN_SQ_MESH, NULL, NULL, 2, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 1, SQ_MESH, 1), - LEN_SQ_MESH + 1, NULL, NULL, 1, + LEN_SQ_MESH + 1, NULL, NULL, 2, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 1, 1), - LEN_SQ_MESH + 2, NULL, NULL, 13, + LEN_SQ_MESH + 2, NULL, NULL, 14, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 1), LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0), snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 2), @@ -310,7 +311,41 @@ snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 12), LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0), snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 13), - LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0))), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 15), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0)), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 1, 2), + LEN_SQ_MESH + 2, NULL, NULL, 15, + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 1), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 2), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 3), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 4), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 5), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 6), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 7), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 8), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 9), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 10), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 11), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 12), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 13), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 14), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 15), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0))), snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 1, SQ_MESH, 2), LEN_SQ_MESH + 1, NULL, NULL, 1, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 2, 1), @@ -766,19 +801,17 @@ { oid *instance = NULL; u_char *cp = NULL; - peer *peers = Config.peers; + peer *peerptr = Config.peers; + peer *peerptr2; struct in_addr *laddr = NULL; char *host_addr = NULL, *current_addr = NULL, *last_addr = NULL; - if (peers == NULL) { - current = current->parent->parent->parent->leaves[1]; - while ((current) && (!current->parsefunction)) - current = current->leaves[0]; - instance = client_Inst(current->name, len, current, Fn); + if (peerptr == NULL) { + /* Do nothing */ } else if (*len <= current->len) { instance = xmalloc(sizeof(name) * (*len + 4)); xmemcpy(instance, name, (sizeof(name) * *len)); - cp = (u_char *) & (peers->in_addr.sin_addr.s_addr); + cp = (u_char *) & (peerptr->in_addr.sin_addr.s_addr); instance[*len] = *cp++; instance[*len + 1] = *cp++; instance[*len + 2] = *cp++; @@ -787,33 +820,74 @@ } else { laddr = oid2addr(&name[*len - 4]); host_addr = inet_ntoa(*laddr); - last_addr = xmalloc(strlen(host_addr)); - strncpy(last_addr, host_addr, strlen(host_addr)); - current_addr = inet_ntoa(peers->in_addr.sin_addr); - while ((peers) && (strncmp(last_addr, current_addr, strlen(current_addr)))) { - if (peers->next) { - peers = peers->next; - current_addr = inet_ntoa(peers->in_addr.sin_addr); - } else { - peers = NULL; + last_addr = xstrdup(host_addr); + skip_duplicate: + current_addr = inet_ntoa(peerptr->in_addr.sin_addr); + while (peerptr && strcmp(last_addr, current_addr) != 0) { + peerptr = peerptr->next; + if (peerptr) + current_addr = inet_ntoa(peerptr->in_addr.sin_addr); + } + + /* Find the next peer */ + if (peerptr) + peerptr = peerptr->next; + + /* watch out for duplicate addresses */ + for (peerptr2 = Config.peers; peerptr && peerptr2 != peerptr; peerptr2 = peerptr2->next) { + if (peerptr2->in_addr.sin_addr.s_addr == peerptr->in_addr.sin_addr.s_addr) { + /* ouch.. there are more than one peer on this IP. Skip the second one */ + peerptr = peerptr->next; + if (peerptr) + goto skip_duplicate; } } + xfree(last_addr); - if (peers) { - if (peers->next) { - peers = peers->next; - instance = xmalloc(sizeof(name) * (*len)); - xmemcpy(instance, name, (sizeof(name) * *len)); - cp = (u_char *) & (peers->in_addr.sin_addr.s_addr); - instance[*len - 4] = *cp++; - instance[*len - 3] = *cp++; - instance[*len - 2] = *cp++; - instance[*len - 1] = *cp++; - } else { - return (instance); - } - } else { - return (instance); + + if (peerptr) { + instance = xmalloc(sizeof(name) * (*len)); + xmemcpy(instance, name, (sizeof(name) * *len)); + cp = (u_char *) & (peerptr->in_addr.sin_addr.s_addr); + instance[*len - 4] = *cp++; + instance[*len - 3] = *cp++; + instance[*len - 2] = *cp++; + instance[*len - 1] = *cp++; + } + } + *Fn = current->parsefunction; + return (instance); +} + +static oid * +peer_InstIndex(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn) +{ + oid *instance = NULL; + + if (!Config.peers) { + /* Do nothing */ + } else if (*len <= current->len) { + instance = xmalloc(sizeof(name) * (*len + 1)); + xmemcpy(instance, name, (sizeof(name) * *len)); + instance[*len] = 1; + *len += 1; + } else { + int identifier, loop = 1; /* our index starts at 1 */ + peer *p = Config.peers; + identifier = name[*len - 1]; + + /* We want the next one... */ + identifier += 1; + + /* Make sure it exists */ + while ((identifier != loop) && (p != NULL)) { + loop++; + p = p->next; + } + if (p != NULL) { + instance = xmalloc(sizeof(name) * (*len)); + xmemcpy(instance, name, (sizeof(name) * *len)); + instance[*len - 1] = loop; } } *Fn = current->parsefunction; Index: squid/src/store_key_md5.c diff -u squid/src/store_key_md5.c:1.6 squid/src/store_key_md5.c:1.6.4.1 --- squid/src/store_key_md5.c:1.6 Fri Apr 13 17:31:02 2001 +++ squid/src/store_key_md5.c Mon May 15 18:01:32 2006 @@ -138,6 +138,10 @@ MD5Update(&M, (unsigned char *) url, strlen(url)); if (request->vary_headers) MD5Update(&M, (unsigned char *) request->vary_headers, strlen(request->vary_headers)); + if (request->urlgroup) { + MD5Update(&M, (unsigned char *) " ", 1); + MD5Update(&M, (unsigned char *) request->urlgroup, strlen(request->urlgroup)); + } MD5Final(digest, &M); return digest; } Index: squid/src/structs.h diff -u squid/src/structs.h:1.78 squid/src/structs.h:1.78.2.1 --- squid/src/structs.h:1.78 Mon May 15 16:51:56 2006 +++ squid/src/structs.h Mon May 15 18:01:32 2006 @@ -336,20 +336,38 @@ relist *next; }; +struct _acl_request_type { + unsigned int accelerated:1; + unsigned int internal:1; +}; + struct _sockaddr_in_list { struct sockaddr_in s; sockaddr_in_list *next; }; +struct _http_port_list { + http_port_list *next; + struct sockaddr_in s; + char *protocol; /* protocol name */ + char *name; /* visible name */ + char *defaultsite; /* default web site */ + char *urlgroup; /* default urlgroup */ + unsigned int transparent:1; /* transparent proxy */ + unsigned int accel:1; /* HTTP accelerator */ + unsigned int vhost:1; /* uses host header */ + unsigned int vport:1; /* virtual port support */ +}; + #if USE_SSL struct _https_port_list { - https_port_list *next; - struct sockaddr_in s; + http_port_list http; /* must be first */ char *cert; char *key; int version; char *cipher; char *options; + SSL_CTX *sslContext; }; #endif @@ -443,7 +461,7 @@ #endif } Port; struct { - sockaddr_in_list *http; + http_port_list *http; #if USE_SSL https_port_list *https; #endif @@ -501,7 +519,14 @@ #if USE_DNSSERVERS char *dnsserver; #endif - wordlist *redirect; + struct { + wordlist *command; + int children; + } url_rewrite; + struct { + wordlist *command; + int children; + } location_rewrite; #if USE_ICMP char *pinger; #endif @@ -513,15 +538,9 @@ #if USE_DNSSERVERS int dnsChildren; #endif - int redirectChildren; time_t authenticateGCInterval; time_t authenticateTTL; time_t authenticateIpTTL; - struct { - int single_host; - char *host; - u_short port; - } Accel; char *appendDomain; int appendDomainLen; char *debugOptions; @@ -595,7 +614,6 @@ int log_mime_hdrs; int log_fqdn; int announce; - int accel_with_proxy; int mem_pools; int test_reachability; int half_closed_clients; @@ -623,14 +641,15 @@ int detect_broken_server_pconns; int balance_on_multiple_ip; int relaxed_header_parser; - int accel_uses_host_header; int accel_no_pmtu_disc; int global_internal_static; int httpd_suppress_version_string; + int via; } onoff; acl *aclList; struct { acl_access *http; + acl_access *http2; acl_access *icp; acl_access *miss; acl_access *NeverDirect; @@ -645,7 +664,8 @@ #if USE_IDENT acl_access *identLookup; #endif - acl_access *redirector; + acl_access *url_rewrite; + acl_access *location_rewrite; acl_access *reply; acl_address *outgoing_address; acl_tos *outgoing_tos; @@ -730,14 +750,11 @@ char *store_dir_select_algorithm; int sleep_after_fork; /* microseconds */ external_acl *externalAclHelperList; + errormap *errorMapList; }; struct _SquidConfig2 { struct { - char *prefix; - int on; - } Accel; - struct { int enable_purge; } onoff; uid_t effectiveUserID; @@ -996,6 +1013,7 @@ unsigned int keepalive_broken:1; unsigned int abuse_detected:1; unsigned int request_sent:1; + unsigned int originpeer:1; }; struct _HttpStateData { @@ -1083,6 +1101,7 @@ struct _clientHttpRequest { ConnStateData *conn; request_t *request; /* Parsed URL ... */ + request_t *orig_request; /* Parsed URL ... */ store_client *sc; /* The store_client we're using */ store_client *old_sc; /* ... for entry to be validated */ char *uri; @@ -1156,6 +1175,8 @@ int n; time_t until; } defer; + http_port_list *port; + int transparent; }; struct _ipcache_addrs { @@ -1259,6 +1280,7 @@ #endif struct _peer { + char *name; char *host; peer_t type; struct sockaddr_in in_addr; @@ -1310,6 +1332,9 @@ unsigned int no_delay:1; #endif unsigned int allow_miss:1; + unsigned int originserver:1; + unsigned int userhash:1; + unsigned int sourcehash:1; } options; int weight; struct { @@ -1341,9 +1366,29 @@ float load_factor; } carp; #endif + struct { + unsigned int hash; + double load_multiplier; + double load_factor; + } userhash; + struct { + unsigned int hash; + double load_multiplier; + double load_factor; + } sourcehash; char *login; /* Proxy authorization */ time_t connect_timeout; int max_conn; + struct { + char *url; + ssize_t min, max; + int interval; + int timeout; + int state; + time_t last; + PeerMonitor *data; + } monitor; + char *domain; /* Forced domain */ }; struct _net_db_name { @@ -1635,7 +1680,7 @@ unsigned int hierarchical:1; unsigned int loopdetect:1; unsigned int proxy_keepalive:1; - unsigned int proxying:1; + unsigned int proxying:1; /* this should be killed, also in httpstateflags */ unsigned int refresh:1; unsigned int redirected:1; unsigned int need_validation:1; @@ -1702,6 +1747,8 @@ char *peer_login; /* Configured peer login:password */ time_t lastmod; /* Used on refreshes */ const char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */ + char *urlgroup; /* urlgroup, returned by redirectors */ + char *peer_domain; /* Configured peer forceddomain */ BODY_HANDLER *body_reader; void *body_reader_data; }; @@ -2263,4 +2310,15 @@ void (*dump) (StoreEntry * e, const char *option, SwapDir * sd); }; +struct error_map_entry { + struct error_map_entry *next; + char *value; + int status; +}; +struct _errormap { + errormap *next; + char *url; + struct error_map_entry *map; +}; + #endif /* SQUID_STRUCTS_H */ Index: squid/src/typedefs.h diff -u squid/src/typedefs.h:1.31 squid/src/typedefs.h:1.31.2.1 --- squid/src/typedefs.h:1.31 Mon May 15 15:50:49 2006 +++ squid/src/typedefs.h Mon May 15 18:01:32 2006 @@ -92,6 +92,7 @@ typedef struct _acl_user_data acl_user_data; typedef struct _acl_user_ip_data acl_user_ip_data; typedef struct _acl_arp_data acl_arp_data; +typedef struct _acl_request_type acl_request_type; typedef struct _acl acl; typedef struct _acl_snmp_comm acl_snmp_comm; typedef struct _acl_list acl_list; @@ -105,6 +106,7 @@ typedef struct _ushortlist ushortlist; typedef struct _relist relist; typedef struct _sockaddr_in_list sockaddr_in_list; +typedef struct _http_port_list http_port_list; typedef struct _https_port_list https_port_list; typedef struct _SquidConfig SquidConfig; typedef struct _SquidConfig2 SquidConfig2; @@ -217,6 +219,8 @@ typedef struct _RemovalPurgeWalker RemovalPurgeWalker; typedef struct _RemovalPolicyNode RemovalPolicyNode; typedef struct _RemovalPolicySettings RemovalPolicySettings; +typedef struct _errormap errormap; +typedef struct _PeerMonitor PeerMonitor; typedef struct _http_version_t http_version_t; @@ -389,4 +393,6 @@ typedef struct _external_acl external_acl; typedef struct _external_acl_entry external_acl_entry; +typedef void ERRMAPCB(StoreEntry *, int body_offset, squid_off_t content_length, void *data); + #endif /* SQUID_TYPEDEFS_H */