diff --exclude=.svn -Naur squid-2.6.STABLE7/src/cache_cf.c squid-2.6.STABLE7_PATCHED/src/cache_cf.c --- squid-2.6.STABLE7/src/cache_cf.c 2007-01-09 23:24:41.000000000 +1300 +++ squid-2.6.STABLE7_PATCHED/src/cache_cf.c 2007-01-18 11:47:51.000000000 +1300 @@ -427,6 +427,14 @@ wordlistDestroy(&Config.Program.location_rewrite.command); } } + /* header_rewrite */ + if (Config.Program.header_rewrite.command) { + if (Config.Program.header_rewrite.children < 1){ + Config.Program.header_rewrite.children = 0; + wordlistDestroy(&Config.Program.header_rewrite.command); + } + } + /* end of change */ if (Config.appendDomain) if (*Config.appendDomain != '.') fatal("append_domain must begin with a '.'"); @@ -470,6 +478,10 @@ 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); + /* header_rewrite */ + if (Config.Program.header_rewrite.command) + requirePathnameExists("header_rewrite_program",Config.Program.header_rewrite.command->key); + /* end of change */ requirePathnameExists("Icon Directory", Config.icons.directory); requirePathnameExists("Error Directory", Config.errorDirectory); authenticateConfigure(&Config.authConfig); diff --exclude=.svn -Naur squid-2.6.STABLE7/src/cf.data.pre squid-2.6.STABLE7_PATCHED/src/cf.data.pre --- squid-2.6.STABLE7/src/cf.data.pre 2007-01-14 05:06:42.000000000 +1300 +++ squid-2.6.STABLE7_PATCHED/src/cf.data.pre 2007-01-18 11:47:47.000000000 +1300 @@ -1807,6 +1807,97 @@ headers are sent. DOC_END +NAME: header_rewrite_program +TYPE: wordlist +LOC: Config.Program.header_rewrite.command +DEFAULT: none +DOC_START + Specify the location of the executable for the header rewriter. + Since they can perform almost any function there isn't one included. + + For each requested URL which matches the header_rewriter ACL, Squid + will send a block of header lines to the rewriter program terminated + by an empty line : + + header1: header1_contents + header2: header2_contents + header3: header3_contents + header4: header4_contents + \n + + And the rewriter should return modified or additional headers. Note + that all of the original request headers will be removed and replaced + by whatever the header_rewriter generates. + + By default, a header rewriter is not used. +DOC_END + +NAME: header_rewrite_children +TYPE: int +DEFAULT: 5 +LOC: Config.Program.header_rewrite.children +DOC_START + The number of header rewriting processes to spawn. If you start + too few Squid will have to wait for them to process a backlog of + headers, slowing it down. If you start too many they will use RAM + and other system resources. +DOC_END + +NAME: header_rewrite_access +TYPE: acl_access +DEFAULT: none +LOC: Config.accessList.header_rewrite +DOC_START + If defined, this access list specifies which requests are + sent to the header rewriting processes. By default all requests + are sent. +DOC_END + +NAME: header_rewrite_program +TYPE: wordlist +LOC: Config.Program.header_rewrite.command +DEFAULT: none +DOC_START + Specify the location of the executable for the header rewriter. + Since they can perform almost any function there isn't one included. + + For each requested URL which matches the header_rewriter ACL, Squid + will send a block of header lines to the rewriter program terminated + by an empty line : + + header1: header1_contents + header2: header2_contents + header3: header3_contents + header4: header4_contents + \n + + And the rewriter should return modified or additional headers. Note + that all of the original request headers will be removed and replaced + by whatever the header_rewriter generates. + + By default, a header rewriter is not used. +DOC_END + +NAME: header_rewrite_children +TYPE: int +DEFAULT: 5 +LOC: Config.Program.header_rewrite.children +DOC_START + The number of header rewriting processes to spawn. If you start + too few Squid will have to wait for them to process a backlog of + headers, slowing it down. If you start too many they will use RAM + and other system resources. +DOC_END + +NAME: header_rewrite_access +TYPE: acl_access +DEFAULT: none +LOC: Config.accessList.header_rewrite +DOC_START + If defined, this access list specifies which requests are + sent to the header rewriting processes. By default all requests + are sent. +DOC_END NAME: auth_param TYPE: authparam diff --exclude=.svn -Naur squid-2.6.STABLE7/src/client_side.c squid-2.6.STABLE7_PATCHED/src/client_side.c --- squid-2.6.STABLE7/src/client_side.c 2007-01-07 06:22:45.000000000 +1300 +++ squid-2.6.STABLE7_PATCHED/src/client_side.c 2007-01-18 11:53:12.000000000 +1300 @@ -664,7 +664,11 @@ clientHttpRequest *http = data; http->request->flags.cachable = answer; http->acl_checklist = NULL; + /* header_rewrite clientProcessRequest(http); + */ + hdrRewriteStart(http,(RH *)clientProcessRequest, http ); + /* end of change */ } static void diff --exclude=.svn -Naur squid-2.6.STABLE7/src/helper.c squid-2.6.STABLE7_PATCHED/src/helper.c --- squid-2.6.STABLE7/src/helper.c 2006-09-09 07:41:24.000000000 +1200 +++ squid-2.6.STABLE7_PATCHED/src/helper.c 2007-01-18 11:53:08.000000000 +1300 @@ -742,7 +742,13 @@ srv->roffset = 0; srv->rbuf[0] = '\0'; } + /* header_rewrite while ((t = strchr(srv->rbuf, '\n'))) { + check if this helper has double cr_end else go on as usual + */ + while ( (!hlp->double_cr_end && (t = strchr(srv->rbuf, '\n'))) || + (hlp->double_cr_end && (t = strstr(srv->rbuf, "\r\n\r\n"))) ) { + /* end of change */ helper_request *r; char *msg = srv->rbuf; int i = 0; diff --exclude=.svn -Naur squid-2.6.STABLE7/src/HttpHeaderTools.c squid-2.6.STABLE7_PATCHED/src/HttpHeaderTools.c --- squid-2.6.STABLE7/src/HttpHeaderTools.c 2006-07-27 08:09:33.000000000 +1200 +++ squid-2.6.STABLE7_PATCHED/src/HttpHeaderTools.c 2007-01-18 11:57:54.000000000 +1300 @@ -486,3 +486,246 @@ if (removed_headers) httpHeaderRefreshMask(l); } + +/* header_rewriter + * start of header rewriter helper code + */ + +/* Size of buffer to hold all header contents */ +#define HDR_BUFSIZE 8192 + +typedef struct { + void *data; + char *orig_url; /* copy of original URL */ + struct in_addr client_addr; + const char *client_ident; + RH *handler; + HttpHeader *req_header; /* Pointer to request headers */ +} hdrHelper_StateData; + +static HLPCB hdrHandleReply; +static helper *hdrHelpers = NULL; +static OBJH hdrHelperStats; +static int hdrHelper_n_bypassed = 0; +CBDATA_TYPE(hdrHelper_StateData); + +static void +hdrStateFree(hdrHelper_StateData * r) +{ + safe_free(r->orig_url); + cbdataFree(r); +} + +/* + hdrHandleReply + function which handles the replies from the header rewriter helpers + + read the reply from the handler, and add it to the rewritten_headers + in new_headers array + if the reply is END, then : + - remove the headers from the request + - copy the rewritten headers into the request + - call the handler ( ie, return ) +*/ +static void +hdrHandleReply(void *data, char *reply) +{ + hdrHelper_StateData *r = data; + int valid; + char *pos; + char *pos2; + char *msg_tmp; + + debug(66, 9) ("hdrHandleReply: {%s}\n", reply ? reply : ""); + if (reply) { + debug(66, 9) ("hdrHandleReply: doing header parse on hdr %p\n",r->req_header); + /* delete old header */ + httpHeaderReset( r->req_header ); + /* parse the reply in separate lines and insert each line into header entries */ + msg_tmp = reply; + while(pos=strstr(msg_tmp,"\r\n")) { + if(pos-msg_tmp>2) { + /* end of line */ + strncpy (pos,"\0\0",2); + /* delimiter */ + pos2=strstr(msg_tmp,":"); + strncpy (pos2,"\0",1); + /* avoid duplication - HDR_HOST should not be overwritten by the header_rewriter-helper */ + if(!strstr(msg_tmp,httpHeaderNameById(HDR_HOST))) { + httpHeaderPutExt(r->req_header,msg_tmp,++pos2); + } + /* goto next line */ + msg_tmp=pos+2; + } else { + if(strlen(pos)>0) { + /* line was empty - goto next line */ + msg_tmp=pos+2; + } else { + /* no more to process - just give up */ + break; + } + } + } /* while */ + } /* if reply */ + /* End of helper request, call the callback function */ + valid = cbdataValid(r->data); + cbdataUnlock(r->data); + debug(66, 9) ("hdrHandleReply: rewrite complete, calling handler\n"); + if (valid) + r->handler(r->data, reply); + hdrStateFree(r); +} + +static void +hdrHelperStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "Header Rewriter Statistics:\n"); + helperStats(sentry, hdrHelpers); + storeAppendPrintf(sentry, "\nNumber of requests bypassed " + "because all rewriters were busy: %d\n", hdrHelper_n_bypassed); +} + +/* + public function hdrRewriteInit() + Startup the header rewriter helpers ( if configured ) +*/ +void +hdrRewriteInit(void) { + static int init = 0; + debug(66,1) ("hdrRewriteInit:\n"); + if (!Config.Program.header_rewrite.command){ + debug(66,1) ("hdrRewriteInit: quitting - no header_rewrite command\n"); + return; + } + if (hdrHelpers == NULL){ + debug(66,1) ("hdrRewriteInit: creating helpers\n"); + hdrHelpers = helperCreate("header_rewriter"); + } + hdrHelpers->cmdline = Config.Program.header_rewrite.command; + hdrHelpers->n_to_start = Config.Program.header_rewrite.children; + hdrHelpers->ipc_type = IPC_TCP_SOCKET; + hdrHelpers->double_cr_end = 1; + helperOpenServers(hdrHelpers); + if (!init) { + cachemgrRegister("header_rewriter", + "Header Rewriter Stats", + hdrHelperStats, 0, 1); + init = 1; + CBDATA_INIT_TYPE(hdrHelper_StateData); + } + debug(66,1) ("hdrRewriteInit: done\n"); +} + + +/* + public function hdrRewriteShutdown() + Shutdown the header rewriter helpers ( if configured ) +*/ +void +hdrRewriteShutdown() { + debug(66,1) ("hdrRewriteShutdown: starting\n"); + if (!hdrHelpers) + return; + helperShutdown(hdrHelpers); + if (!shutting_down) + return; + helperFree(hdrHelpers); + hdrHelpers = NULL; + debug(66,1) ("hdrRewriteShutdown: done\n"); +} + + +/* + public function hdrRewriteStart() + Call the header rewriter helpers + + + *** This needs serious fixing *** + +*/ +void +hdrRewriteStart(clientHttpRequest * http, RH * handler, void *data) +{ + ConnStateData *conn = http->conn; + hdrHelper_StateData *helper = NULL; + char buf[HDR_BUFSIZE], *cp; + HttpHeader *reqheaders = &http->request->header; + HttpHeaderEntry *e; + HttpHeaderPos p = HttpHeaderInitPos; + int nl, vl; + + assert(http); + assert(handler); + debug(66, 9) ("hdrRewriteStart: '%s'\n", http->uri); + + if (Config.Program.header_rewrite.command == NULL) { + /* No header rewriting command has been defined, so just return by calling the handler + */ + debug(66, 9) ("hdrRewriteStart: finishing because header_rewrite command not defined\n"); + handler(data, NULL); + return; + } + + if (Config.accessList.header_rewrite) { + aclCheck_t ch; + memset(&ch, '\0', sizeof(ch)); + ch.src_addr = http->conn->peer.sin_addr; + ch.my_addr = http->conn->me.sin_addr; + ch.my_port = ntohs(http->conn->me.sin_port); + ch.request = http->request; + if (!aclCheckFast(Config.accessList.header_rewrite, &ch)) { + /* denied -- bypass redirector */ + debug(66, 9) ("hdrRewriteStart: finishing because request not in ACL\n"); + handler(data, NULL); + return; + } + } + + if (hdrHelpers->stats.queue_size) { + /* Skip helper if there is one request queued */ + hdrHelper_n_bypassed++; + debug(66, 9) ("hdrRewriteStart: finishing because too many requests queued\n"); + handler(data, NULL); + return; + } + + /* + put together the callback struct + */ + helper = cbdataAlloc(hdrHelper_StateData); + helper->orig_url = xstrdup(http->uri); + helper->client_addr = conn->log_addr; + if (http->request->auth_user_request) + helper->client_ident = authenticateUserRequestUsername(http->request->auth_user_request); + else if (conn->rfc931[0]) { + helper->client_ident = conn->rfc931; + } else { + helper->client_ident = dash_str; + } + helper->handler = handler; + helper->data = data; + cbdataLock(helper->data); + helper->req_header = reqheaders; + + /* + Format the buffer in preparation for sending to helper + */ + cp = buf; + while ((e = httpHeaderGetEntry(reqheaders, &p))){ + debug(66, 9) ("hdrRewriteStart: sending header %s:%s\n",strBuf(e->name),strBuf(e->value)); + nl = strlen(strBuf(e->name)); + vl = strlen(strBuf(e->value)); + assert( (cp + nl + vl + 4) < (buf + HDR_BUFSIZE) ); + strcpy(cp,strBuf(e->name)); cp += nl; + strcpy(cp,": "); cp += 2; + strcpy(cp,strBuf(e->value)); cp += vl; + strcpy(cp,"\r\n"); cp += 2; + } + /* Extra \r\n to terminate (\r\n\r\n will mark the end of athe reply of the rewrite-helper)*/ + strcpy(cp,"\r\n"); + + debug(66, 9) ("hdrRewriteStart: calling helperSubmit with %s\n",buf); + helperSubmit(hdrHelpers, buf, hdrHandleReply, helper); +} + +/* end of change */ \ No newline at end of file diff --exclude=.svn -Naur squid-2.6.STABLE7/src/main.c squid-2.6.STABLE7_PATCHED/src/main.c --- squid-2.6.STABLE7/src/main.c 2007-01-14 05:10:14.000000000 +1300 +++ squid-2.6.STABLE7_PATCHED/src/main.c 2007-01-18 12:02:31.000000000 +1300 @@ -393,6 +393,9 @@ #endif redirectShutdown(); locationRewriteShutdown(); + /* header_rewrite */ + hdrRewriteShutdown(); + /* end of change */ authenticateShutdown(); externalAclShutdown(); storeDirCloseSwapLogs(); @@ -421,6 +424,9 @@ idnsInit(); #endif redirectInit(); + /* header_rewrite */ + hdrRewriteInit(); + /* end of change */ locationRewriteInit(); authenticateInit(&Config.authConfig); externalAclInit(); @@ -456,6 +462,9 @@ dnsShutdown(); #endif redirectShutdown(); + /* header_rewrite */ + hdrRewriteShutdown(); + /* end of change */ locationRewriteShutdown(); authenticateShutdown(); externalAclShutdown(); @@ -474,6 +483,9 @@ dnsInit(); #endif redirectInit(); + /* header_rewrite */ + hdrRewriteInit(); + /* end of change */ locationRewriteInit(); authenticateInit(&Config.authConfig); externalAclInit(); @@ -571,6 +583,9 @@ idnsInit(); #endif redirectInit(); + /* header_rewrite */ + hdrRewriteInit(); + /* end of change */ locationRewriteInit(); errorMapInit(); authenticateInit(&Config.authConfig); @@ -1076,6 +1091,9 @@ idnsShutdown(); #endif redirectShutdown(); + /* header_rewrite */ + hdrRewriteShutdown(); + /* end of change */ externalAclShutdown(); locationRewriteShutdown(); icpConnectionClose(); diff --exclude=.svn -Naur squid-2.6.STABLE7/src/protos.h squid-2.6.STABLE7_PATCHED/src/protos.h --- squid-2.6.STABLE7/src/protos.h 2007-01-07 06:22:45.000000000 +1300 +++ squid-2.6.STABLE7_PATCHED/src/protos.h 2007-01-18 12:03:12.000000000 +1300 @@ -413,6 +413,11 @@ extern void httpHeaderPutStrf(); #endif +/* header_rewrite */ +extern void hdrRewriteInit(); +extern void hdrRewriteShutdown(); +extern void hdrRewriteStart(clientHttpRequest *,RH *,void *); +/* end of change */ /* Http Header */ extern void httpHeaderInitModule(void); diff --exclude=.svn -Naur squid-2.6.STABLE7/src/structs.h squid-2.6.STABLE7_PATCHED/src/structs.h --- squid-2.6.STABLE7/src/structs.h 2006-11-30 04:58:52.000000000 +1300 +++ squid-2.6.STABLE7_PATCHED/src/structs.h 2007-01-18 12:09:18.000000000 +1300 @@ -128,6 +128,11 @@ auth_user_hash_pointer *usernamehash; /* cache of acl lookups on this username */ dlink_list proxy_match_cache; + /* header_rewrite */ + struct { + unsigned int credentials_ok:2; /*0=unchecked,1=ok,2=failed*/ + } flags; + /* end of changes */ /* what ip addresses has this user been seen at?, plus a list length cache */ dlink_list ip_list; int ipcount; @@ -551,6 +556,12 @@ int children; int concurrency; } location_rewrite; + /* header_rewrite */ + struct { + wordlist *command; + int children; + } header_rewrite; + /* end of changes */ #if USE_ICMP char *pinger; #endif @@ -700,6 +711,9 @@ #endif acl_access *url_rewrite; acl_access *location_rewrite; + /* header_rewrite */ + acl_access *header_rewrite; + /* end of changes */ acl_access *reply; acl_address *outgoing_address; acl_tos *outgoing_tos; @@ -2288,6 +2302,9 @@ int n_active; int ipc_type; int concurrency; + /* header_rewrite */ + int double_cr_end; + /* end of changes */ time_t last_queue_warn; struct { int requests;