diff --exclude=.svn -Naur squid-2.5.STABLE9/src/cache_cf.c squid-2.5.james01/src/cache_cf.c
--- squid-2.5.STABLE9/src/cache_cf.c	2005-05-17 13:43:53.803459848 +1200
+++ squid-2.5.james01/src/cache_cf.c	2005-05-16 13:44:21.000000000 +1200
@@ -312,6 +312,13 @@
 	    wordlistDestroy(&Config.Program.redirect);
 	}
     }
+    /* JBW: Add header_rewrite.command entry */
+    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);
+        }
+    }
     if (Config.Accel.host) {
 	snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
 	Config2.Accel.prefix = xstrdup(buf);
@@ -365,6 +372,9 @@
 #endif
     if (Config.Program.redirect)
 	requirePathnameExists("redirect_program", Config.Program.redirect->key);
+    /* JBW: Add header_rewrite section */
+    if (Config.Program.header_rewrite.command)
+        requirePathnameExists("header_rewrite_program", Config.Program.header_rewrite.command->key);
     requirePathnameExists("Icon Directory", Config.icons.directory);
     requirePathnameExists("Error Directory", Config.errorDirectory);
 #if HTTP_VIOLATIONS
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/cf.data squid-2.5.james01/src/cf.data
--- squid-2.5.STABLE9/src/cf.data	2005-05-17 13:43:53.819457416 +1200
+++ squid-2.5.james01/src/cf.data	2005-05-16 13:44:21.000000000 +1200
@@ -1264,6 +1264,55 @@
 	are sent.
 DOC_END
 
+# JBW: Added header_rewrite_program,header_rewrite_children,header_rewrite_access
+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 :
+	
+		
+	headerl:	headerl_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
 LOC: Config.authConfig
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/cf_parser.h squid-2.5.james01/src/cf_parser.h
--- squid-2.5.STABLE9/src/cf_parser.h	2005-05-17 13:43:53.771464712 +1200
+++ squid-2.5.james01/src/cf_parser.h	2005-05-16 16:52:29.000000000 +1200
@@ -106,6 +106,9 @@
 	default_line("redirect_children 5");
 	default_line("redirect_rewrites_host_header on");
 	/* No default for redirector_access */
+	/* No default for header_rewrite_program */
+	default_line("header_rewrite_children 5");
+	/* No default for header_rewrite_access */
 	/* No default for auth_param */
 	default_line("authenticate_cache_garbage_interval 1 hour");
 	default_line("authenticate_ttl 1 hour");
@@ -520,6 +523,12 @@
 		parse_onoff(&Config.onoff.redir_rewrites_host);
 	else if (!strcmp(token, "redirector_access"))
 		parse_acl_access(&Config.accessList.redirector);
+	else if (!strcmp(token, "header_rewrite_program"))
+		parse_wordlist(&Config.Program.header_rewrite.command);
+	else if (!strcmp(token, "header_rewrite_children"))
+		parse_int(&Config.Program.header_rewrite.children);
+	else if (!strcmp(token, "header_rewrite_access"))
+		parse_acl_access(&Config.accessList.header_rewrite);
 	else if (!strcmp(token, "auth_param"))
 		parse_authparam(&Config.authConfig);
 	else if (!strcmp(token, "authenticate_cache_garbage_interval"))
@@ -965,6 +974,9 @@
 	dump_int(entry, "redirect_children", Config.redirectChildren);
 	dump_onoff(entry, "redirect_rewrites_host_header", Config.onoff.redir_rewrites_host);
 	dump_acl_access(entry, "redirector_access", Config.accessList.redirector);
+	dump_wordlist(entry, "header_rewrite_program", Config.Program.header_rewrite.command);
+	dump_int(entry, "header_rewrite_children", Config.Program.header_rewrite.children);
+	dump_acl_access(entry, "header_rewrite_access", Config.accessList.header_rewrite);
 	dump_authparam(entry, "auth_param", Config.authConfig);
 	dump_time_t(entry, "authenticate_cache_garbage_interval", Config.authenticateGCInterval);
 	dump_time_t(entry, "authenticate_ttl", Config.authenticateTTL);
@@ -1257,6 +1269,9 @@
 	free_int(&Config.redirectChildren);
 	free_onoff(&Config.onoff.redir_rewrites_host);
 	free_acl_access(&Config.accessList.redirector);
+	free_wordlist(&Config.Program.header_rewrite.command);
+	free_int(&Config.Program.header_rewrite.children);
+	free_acl_access(&Config.accessList.header_rewrite);
 	free_authparam(&Config.authConfig);
 	free_time_t(&Config.authenticateGCInterval);
 	free_time_t(&Config.authenticateTTL);
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/client_side.c squid-2.5.james01/src/client_side.c
--- squid-2.5.STABLE9/src/client_side.c	2005-05-17 13:43:53.794461216 +1200
+++ squid-2.5.james01/src/client_side.c	2005-05-11 10:42:02.000000000 +1200
@@ -398,7 +398,9 @@
     clientHttpRequest *http = data;
     http->request->flags.cachable = answer;
     http->acl_checklist = NULL;
-    clientProcessRequest(http);
+    /* JBW: Commented : "clientProcessRequest(http);" */
+    /* KBT+JBW: call header rewriter */
+    hdrRewriteStart(http, clientProcessRequest, http ); 
 }
 
 static void
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/helper.c squid-2.5.james01/src/helper.c
--- squid-2.5.STABLE9/src/helper.c	2005-05-17 13:43:53.000000000 +1200
+++ squid-2.5.james01/src/helper.c	2005-05-17 13:36:11.000000000 +1200
@@ -669,10 +669,21 @@
 	debug(84, 1) ("helperHandleRead: unexpected read from %s #%d, %d bytes\n",
 	    hlp->id_name, srv->index + 1, len);
 	srv->offset = 0;
-    } else if ((t = strchr(srv->buf, '\n'))) {
-	/* end of reply found */
-	debug(84, 3) ("helperHandleRead: end of reply found\n");
-	*t = '\0';
+
+	/* KBT+JBW : below changed to look for \n\n if double_cr_end is set */
+	} else if ((hlp->double_cr_end && (t = strchr(srv->buf, '\n'))) ||
+		(hlp->double_cr_end && (t = strstr(srv->buf, "\r\n\r\n")))	
+	) { /* end of reply found */
+	    debug(84, 3) ("helperHandleRead: end of reply found\n");
+	if( strstr(srv->buf, "\r\n\r\n") )
+	t += 2; *t = '\0';
+
+	/* JBW: Comments for cutting out diff
+	// if (cbdataValid(r->data))
+	// 	r->callback(r->data, srv->buf);
+	// end of reply found 
+	// debug(84, 3) ("helperHandleRead: end of reply found\n");
+	// *t = '\0'; */
 	srv->flags.busy = 0;
 	srv->offset = 0;
 	srv->request = NULL;
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/HttpHeaderTools.c squid-2.5.james01/src/HttpHeaderTools.c
--- squid-2.5.STABLE9/src/HttpHeaderTools.c	2005-05-17 13:43:53.000000000 +1200
+++ squid-2.5.james01/src/HttpHeaderTools.c	2005-05-16 13:44:21.000000000 +1200
@@ -469,3 +469,220 @@
 	if (0 == httpHdrMangle(e, request))
 	    httpHeaderDelAt(l, p);
 }
+
+/* *** KBT+JBW : Start of header rewriter helper code *** */
+ 
+
+#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;
+
+    debug(66, 5) ("hdrHandleReply: {%s}\n", reply ? reply : "<NULL>");
+    if (reply) {
+      debug(66, 5) ("hdrHandleReply: doing header parse\n");
+      /* parse the reply in separate lines and insert each line into header entries */
+      httpHeaderReset( r->req_header );
+      httpHeaderParse( r->req_header, reply, reply + strlen(reply) );
+      debug(66, 5) ("hdrHandleReply: done header parse\n");
+    }
+ 
+    /* 
+    End of helper request, call the callback function
+    */
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    debug(66, 3) ("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 hdrRewritelnit()
+    Startup the header rewriter helpers ( if configured )
+    */
+void
+hdrRewritelnit(void) {
+    static int init = 0;
+    debug(66,2) ("hdrRewritelnit:\n");
+    if (!Config.Program.header_rewrite.command){
+    debug(66,2) ("hdrRewritelnit: quitting - no header_rewrite command\n");
+    return;
+    }
+    if (hdrHelpers == NULL){
+    debug(66,2) ("hdrRewritelnit: 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,2) ("hdrRewritelnit: done\n");
+}
+
+ 
+/*
+    public function hdrRewriteShutdown()
+ 
+    Shutdown the header rewriter helpers ( if configured )
+*/
+void
+hdrRewriteShutdown() {
+    debug(66,2) ("hdrRewriteShutdown: starting-VI");
+    if (!hdrHelpers)
+    return;
+    helperShutdown(hdrHelpers);
+    if (!shutting_down)
+    return;
+    helperFree(hdrHelpers);
+    hdrHelpers = NULL;
+    debug(66,2) ("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, 3) ("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, 3) ("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, 3) ("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, 3) ("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, 3) ("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 \n to terminate */
+    strcpy(cp,"\r\n");
+
+    helperSubmit(hdrHelpers, buf, hdrHandleReply, helper);
+
+
+}
+
+/* *** End of KBT+JBW header rewriter helper code *** */
+
+
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/main.c squid-2.5.james01/src/main.c
--- squid-2.5.STABLE9/src/main.c	2005-05-17 13:43:53.000000000 +1200
+++ squid-2.5.james01/src/main.c	2005-05-11 10:42:02.000000000 +1200
@@ -349,6 +349,8 @@
     idnsShutdown();
 #endif
     redirectShutdown();
+    /* JBW: add hdrRewriteShutdown(); */
+    hdrRewriteShutdown();
     authenticateShutdown();
     externalAclShutdown();
     storeDirCloseSwapLogs();
@@ -376,6 +378,8 @@
     idnsInit();
 #endif
     redirectInit();
+    /* JBW: add hdrRewritelnit(); */
+    hdrRewritelnit(); 
     authenticateInit(&Config.authConfig);
     externalAclInit();
 #if USE_WCCP
@@ -404,6 +408,8 @@
     dnsShutdown();
 #endif
     redirectShutdown();
+    /* JBW: Add hdrRewriteShutdown(); */
+    hdrRewriteShutdown();
     authenticateShutdown();
     externalAclShutdown();
     _db_rotate_log();		/* cache.log */
@@ -420,6 +426,8 @@
     dnsInit();
 #endif
     redirectInit();
+    /* JBW: Add hdrRewritelnit(); */
+    hdrRewritelnit();
     authenticateInit(&Config.authConfig);
     externalAclInit();
 }
@@ -505,6 +513,8 @@
     idnsInit();
 #endif
     redirectInit();
+    /* JBW: Add hdrRewritelnit();  */
+    hdrRewritelnit(); 
     authenticateInit(&Config.authConfig);
     externalAclInit();
     useragentOpenLog();
@@ -730,6 +740,8 @@
 	    do_shutdown = 0;
 	    shutting_down = 1;
 	    serverConnectionsClose();
+            /* JBW: Add hdrRewriteShutdown(); */
+            hdrRewriteShutdown();
 	    eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
 	}
 	eventRun();
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/protos.h squid-2.5.james01/src/protos.h
--- squid-2.5.STABLE9/src/protos.h	2005-05-17 13:43:53.000000000 +1200
+++ squid-2.5.james01/src/protos.h	2005-05-11 10:42:02.000000000 +1200
@@ -416,6 +416,10 @@
 #else
 extern void httpHeaderPutStrf();
 #endif
+/* JBW: Add hdrRewritelnit, hdrRewriteShutdown, hdrRewriteStart */
+extern void hdrRewritelnit();
+extern void hdrRewriteShutdown();
+extern void hdrRewriteStart(clientHttpRequest*, RH *, void *);
 
 
 /* Http Header */
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/squid.conf.default squid-2.5.james01/src/squid.conf.default
--- squid-2.5.STABLE9/src/squid.conf.default	2005-05-17 13:43:53.000000000 +1200
+++ squid-2.5.james01/src/squid.conf.default	2005-05-16 16:52:29.000000000 +1200
@@ -1052,6 +1052,46 @@
 #Default:
 # none
 
+#  TAG: header_rewrite_program
+#	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 :
+#	
+#		
+#	headerl:	headerl_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.
+#
+#Default:
+# none
+
+#  TAG: header_rewrite_children
+#	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.
+#
+#Default:
+# header_rewrite_children 5
+
+#  TAG: header_rewrite_access
+#	If defined, this access list specifies which requests are
+#	sent to the header rewriting processes. By default all requests
+#	are sent.
+#
+#Default:
+# none
+
 #  TAG: auth_param
 #	This is used to define parameters for the various authentication
 #	schemes supported by Squid.
diff --exclude=.svn -Naur squid-2.5.STABLE9/src/structs.h squid-2.5.james01/src/structs.h
--- squid-2.5.STABLE9/src/structs.h	2005-05-17 13:43:53.000000000 +1200
+++ squid-2.5.james01/src/structs.h	2005-05-11 10:42:02.000000000 +1200
@@ -120,6 +120,12 @@
     auth_user_hash_pointer *usernamehash;
     /* cache of acl lookups on this username */
     dlink_list proxy_match_cache;
+
+    /*0=unchecked,l=ok,2=failed */
+    struct {
+	unsigned int credentials:1;
+    } flags;
+
     /* what ip addresses has this user been seen at?, plus a list length cache */
     dlink_list ip_list;
     size_t ipcount;
@@ -486,6 +492,13 @@
 	char *dnsserver;
 #endif
 	wordlist *redirect;
+	/* JBW: Add header_rewrite and url_rewrite */
+	struct {
+	wordlist *command; 
+	int children;
+	} header_rewrite;
+	acl_access *url_rewrite;
+	
 #if USE_ICMP
 	char *pinger;
 #endif
@@ -626,6 +639,8 @@
 	acl_access *identLookup;
 #endif
 	acl_access *redirector;
+	/* JBW: Add header rewrite */
+	acl_access *header_rewrite; 
 	acl_access *reply;
 	acl_address *outgoing_address;
 	acl_tos *outgoing_tos;
@@ -2033,6 +2048,8 @@
     int n_running;
     int n_active;
     int ipc_type;
+    /* JBW: add double_cr_end */
+    int double_cr_end;
     time_t last_queue_warn;
     struct {
 	int requests;
