---------------------
PatchSet 4873 
Date: 2002/09/05 10:28:18
Author: rbcollins
Branch: rfc2616
Tag: (none) 
Log:
reinstate client Via. Begin metadata separation in store interface

Members: 
	src/HttpReply.c:1.10->1.10.38.1 
	src/HttpReply.h:1.1->1.1.2.1 
	src/HttpRequest.c:1.7->1.7.58.1 
	src/HttpRequest.h:1.1->1.1.2.1 
	src/Makefile.am:1.23.6.2->1.23.6.3 
	src/acl.c:1.54.2.1->1.54.2.2 
	src/asn.c:1.17->1.17.10.1 
	src/cache_manager.c:1.7->1.7.80.1 
	src/client_side.c:1.70.2.2->1.70.2.3 
	src/errorpage.c:1.21->1.21.6.1 
	src/forward.c:1.16->1.16.6.1 
	src/ftp.c:1.26->1.26.2.1 
	src/gopher.c:1.17.2.1->1.17.2.2 
	src/http.c:1.21.6.2->1.21.6.3 
	src/icp_v2.c:1.6->1.6.2.1 
	src/icp_v3.c:1.5->1.5.2.1 
	src/internal.c:1.9->1.9.10.1 
	src/main.c:1.36->1.36.2.1 
	src/mime.c:1.11.38.1->1.11.38.2 
	src/neighbors.c:1.19->1.19.2.1 
	src/net_db.c:1.15->1.15.6.1 
	src/peer_select.c:1.15->1.15.6.1 
	src/protos.h:1.59->1.59.6.1 
	src/ssl.c:1.15->1.15.6.1 
	src/store.c:1.17->1.17.2.1 
	src/store_client.c:1.13->1.13.8.1 
	src/store_log.c:1.7->1.7.38.1 
	src/structs.h:1.64.2.2->1.64.2.3 
	src/typedefs.h:1.27->1.27.6.1 
	src/url.c:1.10->1.10.2.1 
	src/urn.c:1.16.2.1->1.16.2.2 
	src/wais.c:1.8->1.8.38.1 
	src/whois.c:1.9->1.9.2.1 

Index: squid/src/HttpReply.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/HttpReply.c,v
retrieving revision 1.10
retrieving revision 1.10.38.1
diff -u -r1.10 -r1.10.38.1
--- squid/src/HttpReply.c	24 Oct 2001 09:42:11 -0000	1.10
+++ squid/src/HttpReply.c	5 Sep 2002 10:28:18 -0000	1.10.38.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpReply.c,v 1.10 2001/10/24 09:42:11 squidadm Exp $
+ * $Id: HttpReply.c,v 1.10.38.1 2002/09/05 10:28:18 rbcollins Exp $
  *
  * DEBUG: section 58    HTTP Reply (Response)
  * AUTHOR: Alex Rousskov
@@ -33,7 +33,9 @@
  *
  */
 
+#include "HttpReply.h"
 #include "squid.h"
+#include "HttpStrategy.h"
 
 
 /* local constants */
@@ -158,12 +160,19 @@
 }
 
 void
-httpReplyPackInto(const HttpReply * rep, Packer * p)
+httpReplyPackHeadersInto(const HttpReply * rep, Packer * p)
 {
     assert(rep);
     httpStatusLinePackInto(&rep->sline, p);
     httpHeaderPackInto(&rep->header, p);
     packerAppend(p, "\r\n", 2);
+}
+
+
+void
+httpReplyPackInto(const HttpReply * rep, Packer * p)
+{
+    httpReplyPackHeadersInto(rep, p);
     httpBodyPackInto(&rep->body, p);
 }
 
@@ -182,16 +191,15 @@
     return mb;
 }
 
-/* swap: create swap-based packer, pack, destroy packer */
+/* swap: create swap-based packer, pack, destroy packer
+ * This eats the reply.
+ */
 void
-httpReplySwapOut(const HttpReply * rep, StoreEntry * e)
+httpReplySwapOut(HttpReply * rep, StoreEntry * e)
 {
-    Packer p;
     assert(rep && e);
 
-    packerToStoreInit(&p, e);
-    httpReplyPackInto(rep, &p);
-    packerClean(&p);
+    storeEntryReplaceObject(e, rep);
 }
 
 MemBuf
@@ -206,26 +214,48 @@
     return mb;
 }
 
-MemBuf
-httpPacked304Reply(const HttpReply * rep)
+HttpReply *
+httpReplyMake304 (const HttpReply * rep)
 {
     static const http_hdr_type ImsEntries[] =
-    {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER};
+      {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER};
+    HttpReply *rv;
     int t;
-    MemBuf mb;
-    Packer p;
     HttpHeaderEntry *e;
     assert(rep);
-
-    memBufDefInit(&mb);
-    packerToMemInit(&p, &mb);
-    memBufPrintf(&mb, "%s", "HTTP/1.0 304 Not Modified\r\n");
+    
+    rv = httpReplyCreate ();
+    /* rv->content_length; */
+    rv->date = rep->date;
+    rv->last_modified = rep->last_modified;
+    rv->expires = rep->expires;
+    rv->content_type = stringDup (&rep->content_type);
+    /* rv->cache_control */
+    /* rv->content_range */
+    /* rv->keep_alive */
+    httpStatusLineSet(&rv->sline, httpStrategyOurVersion(httpStrategyGetStrategy()), 
+		      HTTP_NOT_MODIFIED, "");
+    
     for (t = 0; ImsEntries[t] != HDR_OTHER; ++t)
 	if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t])))
-	    httpHeaderEntryPackInto(e, &p);
-    memBufAppend(&mb, "\r\n", 2);
-    packerClean(&p);
-    return mb;
+	    httpHeaderAddEntry(&rv->header, httpHeaderEntryClone(e));
+    /* rv->body */
+    return rv;
+}
+
+MemBuf
+httpPacked304Reply(const HttpReply * rep)
+{
+    /* Not as efficient as skipping the header duplication,
+     * but easier to maintain 
+     */
+    HttpReply *temp;
+    MemBuf rv;
+    assert (rep);
+    temp = httpReplyMake304 (rep);
+    rv = httpReplyPack(temp);
+    httpReplyDestroy (temp);
+    return rv;
 }
 
 void
@@ -274,7 +304,7 @@
 }
 
 void
-httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep)
+httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply const * freshRep)
 {
     assert(rep && freshRep);
     /* clean cache */
@@ -450,7 +480,7 @@
  * Returns the body size of a HTTP response
  */
 int
-httpReplyBodySize(method_t method, HttpReply * reply)
+httpReplyBodySize(method_t method, HttpReply const * reply)
 {
     if (METHOD_HEAD == method)
 	return 0;
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/HttpReply.h	Wed Feb 14 01:05:24 2007
@@ -0,0 +1,78 @@
+
+/*
+ * $Id: HttpReply.h,v 1.1.2.1 2002/09/05 10:28:18 rbcollins Exp $
+ *
+ *
+ * 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.
+ *
+ */
+
+#ifndef SQUID_HTTPREPLY_H
+#define SQUID_HTTPREPLY_H
+
+#include "typedefs.h"
+
+/* Http Reply */
+extern void httpReplyInitModule(void);
+/* create/destroy */
+extern HttpReply *httpReplyCreate(void);
+extern void httpReplyDestroy(HttpReply * rep);
+/* reset: clean, then init */
+extern void httpReplyReset(HttpReply * rep);
+/* absorb: copy the contents of a new reply to the old one, destroy new one */
+extern void httpReplyAbsorb(HttpReply * rep, HttpReply * new_rep);
+/* parse returns -1,0,+1 on error,need-more-data,success */
+extern int httpReplyParse(HttpReply * rep, const char *buf, ssize_t);
+extern void httpReplyPackHeadersInto(const HttpReply * rep, Packer * p);
+extern void httpReplyPackInto(const HttpReply * rep, Packer * p);
+/* ez-routines */
+/* mem-pack: returns a ready to use mem buffer with a packed reply */
+extern MemBuf httpReplyPack(const HttpReply * rep);
+/* swap: create swap-based packer, pack, destroy packer */
+extern void httpReplySwapOut(HttpReply * rep, StoreEntry * e);
+/* set commonly used info with one call */
+extern void httpReplySetHeaders(HttpReply * rep, http_version_t ver, http_status status,
+    const char *reason, const char *ctype, int clen, time_t lmt, time_t expires);
+/* do everything in one call: init, set, pack, clean, return MemBuf */
+extern MemBuf httpPackedReply(http_version_t ver, http_status status, const char *ctype,
+    int clen, time_t lmt, time_t expires);
+/* construct 304 reply and pack it into MemBuf, return MemBuf */
+extern MemBuf httpPacked304Reply(const HttpReply * rep);
+/* construct a 304 reply and return it */
+extern HttpReply *httpReplyMake304(const HttpReply *rep);
+/* update when 304 reply is received for a cached object */
+extern void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply const * freshRep);
+/* header manipulation */
+extern int httpReplyContentLen(const HttpReply * rep);
+extern const char *httpReplyContentType(const HttpReply * rep);
+extern time_t httpReplyExpires(const HttpReply * rep);
+extern int httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type);
+extern void httpRedirectReply(HttpReply *, http_status, const char *);
+extern int httpReplyBodySize(method_t, HttpReply const *);
+extern void httpReplyBodyBuildSize(request_t *, HttpReply *, dlink_list *);
+
+#endif /* SQUID_HTTPREPLY_H */
Index: squid/src/HttpRequest.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/HttpRequest.c,v
retrieving revision 1.7
retrieving revision 1.7.58.1
diff -u -r1.7 -r1.7.58.1
--- squid/src/HttpRequest.c	14 Apr 2001 00:31:01 -0000	1.7
+++ squid/src/HttpRequest.c	5 Sep 2002 10:28:18 -0000	1.7.58.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: HttpRequest.c,v 1.7 2001/04/14 00:31:01 squidadm Exp $
+ * $Id: HttpRequest.c,v 1.7.58.1 2002/09/05 10:28:18 rbcollins Exp $
  *
  * DEBUG: section 73    HTTP Request
  * AUTHOR: Duane Wessels
@@ -33,6 +33,7 @@
  *
  */
 
+#include "HttpRequest.h"
 #include "squid.h"
 
 request_t *
--- /dev/null	Wed Feb 14 01:05:20 2007
+++ squid/src/HttpRequest.h	Wed Feb 14 01:05:24 2007
@@ -0,0 +1,51 @@
+
+/*
+ * $Id: HttpRequest.h,v 1.1.2.1 2002/09/05 10:28:19 rbcollins Exp $
+ *
+ *
+ * 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.
+ *
+ */
+
+#ifndef SQUID_HTTPREQUEST_H
+#define SQUID_HTTPREQUEST_H
+
+#include "typedefs.h"
+
+/*  Http Request */
+extern request_t *requestCreate(method_t, protocol_t, const char *urlpath);
+extern void requestDestroy(request_t *);
+extern request_t *requestLink(request_t *);
+extern void requestUnlink(request_t *);
+extern int httpRequestParseHeader(request_t * req, const char *parse_start);
+extern void httpRequestSwapOut(const request_t * req, StoreEntry * e);
+extern void httpRequestPack(const request_t * req, Packer * p);
+extern int httpRequestPrefixLen(const request_t * req);
+extern int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
+extern int httpRequestHdrAllowedByName(http_hdr_type id);
+
+#endif /* SQUID_HTTPREQUEST_H */
Index: squid/src/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/Makefile.am,v
retrieving revision 1.23.6.2
retrieving revision 1.23.6.3
diff -u -r1.23.6.2 -r1.23.6.3
--- squid/src/Makefile.am	3 Sep 2002 08:31:20 -0000	1.23.6.2
+++ squid/src/Makefile.am	5 Sep 2002 10:28:19 -0000	1.23.6.3
@@ -114,6 +114,9 @@
 	cbdata.c \
 	client_db.c \
 	client_side.c \
+	client_side_reply.c \
+	client_side_request.c \
+	clientStream.c \
 	comm.c \
 	comm_select.c \
 	comm_poll.c \
Index: squid/src/acl.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/acl.c,v
retrieving revision 1.54.2.1
retrieving revision 1.54.2.2
diff -u -r1.54.2.1 -r1.54.2.2
--- squid/src/acl.c	3 Sep 2002 08:31:21 -0000	1.54.2.1
+++ squid/src/acl.c	5 Sep 2002 10:28:19 -0000	1.54.2.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: acl.c,v 1.54.2.1 2002/09/03 08:31:21 rbcollins Exp $
+ * $Id: acl.c,v 1.54.2.2 2002/09/05 10:28:19 rbcollins Exp $
  *
  * DEBUG: section 28    Access Control
  * AUTHOR: Duane Wessels
@@ -35,6 +35,7 @@
 
 #include "squid.h"
 #include "splay.h"
+#include "HttpRequest.h"
 
 static int aclFromFile = 0;
 static FILE *aclFile;
Index: squid/src/asn.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/asn.c,v
retrieving revision 1.17
retrieving revision 1.17.10.1
diff -u -r1.17 -r1.17.10.1
--- squid/src/asn.c	13 Apr 2002 23:09:15 -0000	1.17
+++ squid/src/asn.c	5 Sep 2002 10:28:20 -0000	1.17.10.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: asn.c,v 1.17 2002/04/13 23:09:15 squidadm Exp $
+ * $Id: asn.c,v 1.17.10.1 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 53    AS Number handling
  * AUTHOR: Duane Wessels, Kostas Anagnostakis
@@ -35,6 +35,7 @@
 
 #include "squid.h"
 #include "radix.h"
+#include "HttpRequest.h"
 
 #define WHOIS_PORT 43
 #define	AS_REQBUF_SZ	4096
Index: squid/src/cache_manager.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/cache_manager.c,v
retrieving revision 1.7
retrieving revision 1.7.80.1
diff -u -r1.7 -r1.7.80.1
--- squid/src/cache_manager.c	23 Feb 2001 21:03:30 -0000	1.7
+++ squid/src/cache_manager.c	5 Sep 2002 10:28:20 -0000	1.7.80.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: cache_manager.c,v 1.7 2001/02/23 21:03:30 hno Exp $
+ * $Id: cache_manager.c,v 1.7.80.1 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 16    Cache Manager Objects
  * AUTHOR: Duane Wessels
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
 
 #define MGR_PASSWD_SZ 128
 
@@ -235,10 +237,8 @@
 	 * password depends on action
 	 */
 	httpHeaderPutAuth(&rep->header, "Basic", mgr->action);
-	/* move info to the mem_obj->reply */
-	httpReplyAbsorb(entry->mem_obj->reply, rep);
 	/* store the reply */
-	httpReplySwapOut(entry->mem_obj->reply, entry);
+	httpReplySwapOut(rep, entry);
 	entry->expires = squid_curtime;
 	storeComplete(entry);
 	cachemgrStateFree(mgr);
@@ -254,9 +254,7 @@
 	storeBuffer(entry);
     {
 	http_version_t version;
-	HttpReply *rep = entry->mem_obj->reply;
-	/* prove there are no previous reply headers around */
-	assert(0 == rep->sline.status);
+	HttpReply *rep = httpReplyCreate();
 	httpBuildVersion(&version, 1, 0);
 	httpReplySetHeaders(rep,
 	    version,
Index: squid/src/client_side.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v
retrieving revision 1.70.2.2
retrieving revision 1.70.2.3
diff -u -r1.70.2.2 -r1.70.2.3
--- squid/src/client_side.c	3 Sep 2002 10:29:38 -0000	1.70.2.2
+++ squid/src/client_side.c	5 Sep 2002 10:28:20 -0000	1.70.2.3
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.c,v 1.70.2.2 2002/09/03 10:29:38 rbcollins Exp $
+ * $Id: client_side.c,v 1.70.2.3 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
+#include "HttpReply.h"
 
 #if IPF_TRANSPARENT
 #if HAVE_SYS_IOCTL_H
@@ -93,57 +95,19 @@
 static PF connStateFree;
 static PF requestTimeout;
 static PF clientLifetimeTimeout;
-static int clientCheckTransferDone(clientHttpRequest *);
-static int clientGotNotEnough(clientHttpRequest *);
 static void checkFailureRatio(err_type, hier_code);
-static void clientProcessMiss(clientHttpRequest *);
-static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep);
 static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
 static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *);
-static RH clientRedirectDone;
-static void clientCheckNoCache(clientHttpRequest *);
-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 clientCacheHit;
+static CSR clientSocketRecipient;
 static void clientSetKeepaliveFlag(clientHttpRequest *);
-static void clientInterpretRequestHeaders(clientHttpRequest *);
-static void clientProcessRequest(clientHttpRequest *);
-static void clientProcessExpired(void *data);
-static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
-static int clientCachable(clientHttpRequest * http);
-static int clientHierarchical(clientHttpRequest * http);
 static int clientCheckContentLength(request_t * r);
 static DEFER httpAcceptDefer;
-static log_type clientProcessRequest2(clientHttpRequest * http);
-static int clientReplyBodyTooLarge(HttpReply *, ssize_t clen);
 static int clientRequestBodyTooLarge(int clen);
 static void clientProcessBody(ConnStateData * conn);
 
-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)
@@ -154,556 +118,6 @@
 
 #endif
 
-static aclCheck_t *
-clientAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http)
-{
-    aclCheck_t *ch;
-    ConnStateData *conn = http->conn;
-    ch = aclChecklistCreate(acl,
-	http->request,
-	conn->rfc931);
-
-    /*
-     * hack for ident ACL. It needs to get full addresses, and a
-     * place to store the ident result on persistent connections...
-     */
-    /* connection oriented auth also needs these two lines for it's operation. */
-    ch->conn = cbdataReference(conn);	/* unreferenced in acl.c */
-
-    return ch;
-}
-
-void
-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);
-}
-
-/*
- * returns true if client specified that the object must come from the cache
- * without contacting origin server
- */
-static int
-clientOnlyIfCached(clientHttpRequest * http)
-{
-    const request_t *r = http->request;
-    assert(r);
-    return r->cache_control &&
-	EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);
-}
-
-StoreEntry *
-clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)
-{
-    StoreEntry *e;
-    /*
-     * For erroneous requests, we might not have a h->request,
-     * so make a fake one.
-     */
-    if (h->request == NULL)
-	h->request = requestLink(requestCreate(m, PROTO_NONE, null_string));
-    e = storeCreateEntry(h->uri, h->log_uri, flags, m);
-    h->sc = storeClientListAdd(e, h);
-#if DELAY_POOLS
-    delaySetStoreClient(h->sc, delayClient(h));
-#endif
-    h->reqofs = 0;
-    h->reqsize = 0;
-    /* I don't think this is actually needed! -- adrian */
-    /* h->reqbuf = h->norm_reqbuf; */
-    assert(h->reqbuf == h->norm_reqbuf);
-    storeClientCopy(h->sc, e, 0, HTTP_REQBUF_SZ, h->reqbuf,
-	clientSendMoreData, h);
-    return e;
-}
-
-void
-clientAccessCheckDone(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) {
-	safe_free(http->uri);
-	http->uri = xstrdup(urlCanonical(http->request));
-	assert(http->redirect_state == REDIRECT_NONE);
-	http->redirect_state = REDIRECT_PENDING;
-	redirectStart(http, clientRedirectDone, http);
-    } else {
-	debug(33, 5) ("Access Denied: %s\n", http->uri);
-	debug(33, 5) ("AclMatchedName = %s\n",
-	    AclMatchedName ? AclMatchedName : "<null>");
-	debug(33, 5) ("Proxy Auth Message = %s\n",
-	    proxy_auth_msg ? proxy_auth_msg : "<null>");
-	/*
-	 * 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 <pribeiro@isel.pt>
-	 */
-	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->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
-clientRedirectDone(void *data, char *result)
-{
-    clientHttpRequest *http = data;
-    request_t *new_request = NULL;
-    request_t *old_request = http->request;
-    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);
-	if (status == HTTP_MOVED_PERMANENTLY || status == HTTP_MOVED_TEMPORARILY) {
-	    char *t = result;
-	    if ((t = strchr(result, ':')) != NULL) {
-		http->redirect.status = status;
-		http->redirect.location = xstrdup(t + 1);
-	    } else {
-		debug(33, 1) ("clientRedirectDone: bad input: %s\n", result);
-	    }
-	}
-	if (strcmp(result, http->uri))
-	    new_request = urlParse(old_request->method, result);
-    }
-    if (new_request) {
-	safe_free(http->uri);
-	http->uri = xstrdup(urlCanonical(new_request));
-	new_request->http_ver = old_request->http_ver;
-	httpHeaderAppend(&new_request->header, &old_request->header);
-	new_request->client_addr = old_request->client_addr;
-	new_request->my_addr = old_request->my_addr;
-	new_request->my_port = old_request->my_port;
-	new_request->flags.redirected = 1;
-	if (old_request->auth_user_request) {
-	    new_request->auth_user_request = old_request->auth_user_request;
-	    authenticateAuthUserRequestLock(new_request->auth_user_request);
-	}
-	if (old_request->body_connection) {
-	    new_request->body_connection = old_request->body_connection;
-	    old_request->body_connection = NULL;
-	}
-	new_request->content_length = old_request->content_length;
-	new_request->flags.proxy_keepalive = old_request->flags.proxy_keepalive;
-	requestUnlink(old_request);
-	http->request = requestLink(new_request);
-    }
-    clientInterpretRequestHeaders(http);
-#if HEADERS_LOG
-    headersLog(0, 1, request->method, request);
-#endif
-    fd_note(http->conn->fd, http->uri);
-    clientCheckNoCache(http);
-}
-
-static void
-clientCheckNoCache(clientHttpRequest * http)
-{
-    if (Config.accessList.noCache && http->request->flags.cachable) {
-	http->acl_checklist = clientAclChecklistCreate(Config.accessList.noCache, http);
-	aclNBCheck(http->acl_checklist, clientCheckNoCacheDone, http);
-    } else {
-	clientCheckNoCacheDone(http->request->flags.cachable, http);
-    }
-}
-
-void
-clientCheckNoCacheDone(int answer, void *data)
-{
-    clientHttpRequest *http = data;
-    http->request->flags.cachable = answer;
-    http->acl_checklist = NULL;
-    clientProcessRequest(http);
-}
-
-static void
-clientProcessExpired(void *data)
-{
-    clientHttpRequest *http = data;
-    char *url = http->uri;
-    StoreEntry *entry = NULL;
-    debug(33, 3) ("clientProcessExpired: '%s'\n", http->uri);
-    assert(http->entry->lastmod >= 0);
-    /*
-     * check if we are allowed to contact other servers
-     * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return 
-     *      a stale entry *if* it matches client requirements
-     */
-    if (clientOnlyIfCached(http)) {
-	clientProcessOnlyIfCachedMiss(http);
-	return;
-    }
-    http->request->flags.refresh = 1;
-    http->old_entry = http->entry;
-    http->old_sc = http->sc;
-    http->old_reqsize = http->reqsize;
-    http->old_reqofs = http->reqofs;
-    http->reqbuf = http->ims_reqbuf;
-#if STORE_CLIENT_LIST_DEBUG
-    /*
-     * Assert that 'http' is already a client of old_entry.  If 
-     * it is not, then the beginning of the object data might get
-     * freed from memory before we need to access it.
-     */
-    assert(http->sc->owner == http);
-#endif
-    entry = storeCreateEntry(url,
-	http->log_uri,
-	http->request->flags,
-	http->request->method);
-    /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */
-    http->sc = storeClientListAdd(entry, http);
-#if DELAY_POOLS
-    /* delay_id is already set on original store client */
-    delaySetStoreClient(http->sc, delayClient(http));
-#endif
-    http->request->lastmod = http->old_entry->lastmod;
-    debug(33, 5) ("clientProcessExpired: lastmod %ld\n", (long int) entry->lastmod);
-    http->entry = entry;
-    http->out.offset = 0;
-    fwdStart(http->conn->fd, http->entry, http->request);
-    /* Register with storage manager to receive updates when data comes in. */
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
-	debug(33, 0) ("clientProcessExpired: found ENTRY_ABORTED object\n");
-    http->reqofs = 0;
-    storeClientCopy(http->sc, entry,
-	http->out.offset,
-	HTTP_REQBUF_SZ,
-	http->reqbuf,
-	clientHandleIMSReply,
-	http);
-}
-
-static int
-clientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, request_t * request)
-{
-    const http_status status = new_entry->mem_obj->reply->sline.status;
-    if (0 == status) {
-	debug(33, 5) ("clientGetsOldEntry: YES, broken HTTP reply\n");
-	return 1;
-    }
-    /* If the reply is a failure then send the old object as a last
-     * resort */
-    if (status >= 500 && status < 600) {
-	debug(33, 3) ("clientGetsOldEntry: YES, failure reply=%d\n", status);
-	return 1;
-    }
-    /* If the reply is anything but "Not Modified" then
-     * we must forward it to the client */
-    if (HTTP_NOT_MODIFIED != status) {
-	debug(33, 5) ("clientGetsOldEntry: NO, reply=%d\n", status);
-	return 0;
-    }
-    /* If the client did not send IMS in the request, then it
-     * must get the old object, not this "Not Modified" reply */
-    if (!request->flags.ims) {
-	debug(33, 5) ("clientGetsOldEntry: YES, no client IMS\n");
-	return 1;
-    }
-    /* If the client IMS time is prior to the entry LASTMOD time we
-     * need to send the old object */
-    if (modifiedSince(old_entry, request)) {
-	debug(33, 5) ("clientGetsOldEntry: YES, modified since %ld\n",
-	    (long int) request->ims);
-	return 1;
-    }
-    debug(33, 5) ("clientGetsOldEntry: NO, new one is fine\n");
-    return 0;
-}
-
-
-static void
-clientHandleIMSReply(void *data, char *buf, ssize_t size)
-{
-    clientHttpRequest *http = data;
-    StoreEntry *entry = http->entry;
-    MemObject *mem;
-    const char *url = storeUrl(entry);
-    int unlink_request = 0;
-    StoreEntry *oldentry;
-    http_status status;
-    debug(33, 3) ("clientHandleIMSReply: %s, %ld bytes\n", url, (long int) size);
-    if (entry == NULL) {
-	return;
-    }
-    if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	return;
-    }
-    /* update size of the request */
-    http->reqsize = size + http->reqofs;
-    mem = entry->mem_obj;
-    status = mem->reply->sline.status;
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	debug(33, 3) ("clientHandleIMSReply: ABORTED '%s'\n", url);
-	/* We have an existing entry, but failed to validate it */
-	/* Its okay to send the old one anyway */
-	http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
-	storeUnregister(http->sc, entry, http);
-	storeUnlockObject(entry);
-	entry = http->entry = http->old_entry;
-	http->sc = http->old_sc;
-	http->reqbuf = http->norm_reqbuf;
-	http->reqofs = http->old_reqofs;
-	http->reqsize = http->old_reqsize;
-    } else if (STORE_PENDING == entry->store_status && 0 == status) {
-	debug(33, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", url);
-	if (size + http->reqofs >= HTTP_REQBUF_SZ) {
-	    /* will not get any bigger than that */
-	    debug(33, 3) ("clientHandleIMSReply: Reply is too large '%s', using old entry\n", url);
-	    /* use old entry, this repeats the code abovez */
-	    http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
-	    storeUnregister(http->sc, entry, http);
-	    storeUnlockObject(entry);
-	    entry = http->entry = http->old_entry;
-	    http->sc = http->old_sc;
-	    http->reqbuf = http->norm_reqbuf;
-	    http->reqofs = http->old_reqofs;
-	    http->reqsize = http->old_reqsize;
-	    /* continue */
-	} else {
-	    http->reqofs += size;
-	    storeClientCopy(http->sc, entry,
-		http->out.offset + http->reqofs,
-		HTTP_REQBUF_SZ - http->reqofs,
-		http->reqbuf + http->reqofs,
-		clientHandleIMSReply,
-		http);
-	    return;
-	}
-    } else if (clientGetsOldEntry(entry, http->old_entry, http->request)) {
-	/* We initiated the IMS request, the client is not expecting
-	 * 304, so put the good one back.  First, make sure the old entry
-	 * headers have been loaded from disk. */
-	oldentry = http->old_entry;
-	http->log_type = LOG_TCP_REFRESH_HIT;
-	if (oldentry->mem_obj->request == NULL) {
-	    oldentry->mem_obj->request = requestLink(mem->request);
-	    unlink_request = 1;
-	}
-	/* Don't memcpy() the whole reply structure here.  For example,
-	 * www.thegist.com (Netscape/1.13) returns a content-length for
-	 * 304's which seems to be the length of the 304 HEADERS!!! and
-	 * not the body they refer to.  */
-	httpReplyUpdateOnNotModified(oldentry->mem_obj->reply, mem->reply);
-	storeTimestampsSet(oldentry);
-	storeUnregister(http->sc, entry, http);
-	http->sc = http->old_sc;
-	storeUnlockObject(entry);
-	entry = http->entry = oldentry;
-	entry->timestamp = squid_curtime;
-	if (unlink_request) {
-	    requestUnlink(entry->mem_obj->request);
-	    entry->mem_obj->request = NULL;
-	}
-	http->reqbuf = http->norm_reqbuf;
-	http->reqofs = http->old_reqofs;
-	http->reqsize = http->old_reqsize;
-    } else {
-	/* the client can handle this reply, whatever it is */
-	http->log_type = LOG_TCP_REFRESH_MISS;
-	if (HTTP_NOT_MODIFIED == mem->reply->sline.status) {
-	    httpReplyUpdateOnNotModified(http->old_entry->mem_obj->reply,
-		mem->reply);
-	    storeTimestampsSet(http->old_entry);
-	    http->log_type = LOG_TCP_REFRESH_HIT;
-	}
-	storeUnregister(http->old_sc, http->old_entry, http);
-	storeUnlockObject(http->old_entry);
-    }
-    http->old_entry = NULL;	/* done with old_entry */
-    http->old_sc = NULL;
-    http->old_reqofs = 0;
-    http->old_reqsize = 0;
-    assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED));
-
-    clientSendMoreData(data, http->reqbuf, http->reqsize);
-}
-
-int
-modifiedSince(StoreEntry * entry, request_t * request)
-{
-    int object_length;
-    MemObject *mem = entry->mem_obj;
-    time_t mod_time = entry->lastmod;
-    debug(33, 3) ("modifiedSince: '%s'\n", storeUrl(entry));
-    if (mod_time < 0)
-	mod_time = entry->timestamp;
-    debug(33, 3) ("modifiedSince: mod_time = %ld\n", (long int) mod_time);
-    if (mod_time < 0)
-	return 1;
-    /* Find size of the object */
-    object_length = mem->reply->content_length;
-    if (object_length < 0)
-	object_length = contentLen(entry);
-    if (mod_time > request->ims) {
-	debug(33, 3) ("--> YES: entry newer than client\n");
-	return 1;
-    } else if (mod_time < request->ims) {
-	debug(33, 3) ("-->  NO: entry older than client\n");
-	return 0;
-    } else if (request->imslen < 0) {
-	debug(33, 3) ("-->  NO: same LMT, no client length\n");
-	return 0;
-    } else if (request->imslen == object_length) {
-	debug(33, 3) ("-->  NO: same LMT, same length\n");
-	return 0;
-    } else {
-	debug(33, 3) ("--> YES: same LMT, different length\n");
-	return 1;
-    }
-}
-
-void
-clientPurgeRequest(clientHttpRequest * http)
-{
-    StoreEntry *entry;
-    ErrorState *err = NULL;
-    HttpReply *r;
-    http_status status = HTTP_NOT_FOUND;
-    http_version_t version;
-    debug(33, 3) ("Config2.onoff.enable_purge = %d\n", Config2.onoff.enable_purge);
-    if (!Config2.onoff.enable_purge) {
-	http->log_type = LOG_TCP_DENIED;
-	err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN);
-	err->request = requestLink(http->request);
-	err->src_addr = http->conn->peer.sin_addr;
-	http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
-	errorAppendEntry(http->entry, err);
-	return;
-    }
-    /* Release both IP cache */
-    ipcacheInvalidate(http->request->host);
-
-    if (!http->flags.purging) {
-	/* Try to find a base entry */
-	http->flags.purging = 1;
-	entry = storeGetPublicByRequestMethod(http->request, METHOD_GET);
-	if (!entry)
-	    entry = storeGetPublicByRequestMethod(http->request, METHOD_HEAD);
-	if (entry) {
-	    /* Swap in the metadata */
-	    http->entry = entry;
-	    storeLockObject(http->entry);
-	    storeCreateMemObject(http->entry, http->uri, http->log_uri);
-	    http->entry->mem_obj->method = http->request->method;
-	    http->sc = storeClientListAdd(http->entry, http);
-	    http->log_type = LOG_TCP_HIT;
-	    http->reqofs = 0;
-	    storeClientCopy(http->sc, http->entry,
-		http->out.offset,
-		HTTP_REQBUF_SZ,
-		http->reqbuf,
-		clientCacheHit,
-		http);
-	    return;
-	}
-    }
-    http->log_type = LOG_TCP_MISS;
-    /* Release the cached URI */
-    entry = storeGetPublicByRequestMethod(http->request, METHOD_GET);
-    if (entry) {
-	debug(33, 4) ("clientPurgeRequest: GET '%s'\n",
-	    storeUrl(entry));
-	storeRelease(entry);
-	status = HTTP_OK;
-    }
-    entry = storeGetPublicByRequestMethod(http->request, METHOD_HEAD);
-    if (entry) {
-	debug(33, 4) ("clientPurgeRequest: HEAD '%s'\n",
-	    storeUrl(entry));
-	storeRelease(entry);
-	status = HTTP_OK;
-    }
-    /* And for Vary, release the base URI if none of the headers was included in the request */
-    if (http->request->vary_headers && !strstr(http->request->vary_headers, "=")) {
-	entry = storeGetPublic(urlCanonical(http->request), METHOD_GET);
-	if (entry) {
-	    debug(33, 4) ("clientPurgeRequest: Vary GET '%s'\n",
-		storeUrl(entry));
-	    storeRelease(entry);
-	    status = HTTP_OK;
-	}
-	entry = storeGetPublic(urlCanonical(http->request), METHOD_HEAD);
-	if (entry) {
-	    debug(33, 4) ("clientPurgeRequest: Vary HEAD '%s'\n",
-		storeUrl(entry));
-	    storeRelease(entry);
-	    status = HTTP_OK;
-	}
-    }
-    /*
-     * Make a new entry to hold the reply to be written
-     * to the client.
-     */
-    http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
-    httpReplyReset(r = http->entry->mem_obj->reply);
-    httpBuildVersion(&version, 1, 0);
-    httpReplySetHeaders(r, version, status, NULL, NULL, 0, 0, -1);
-    httpReplySwapOut(r, http->entry);
-    storeComplete(http->entry);
-}
-
-int
-checkNegativeHit(StoreEntry * e)
-{
-    if (!EBIT_TEST(e->flags, ENTRY_NEGCACHED))
-	return 0;
-    if (e->expires <= squid_curtime)
-	return 0;
-    if (e->store_status != STORE_OK)
-	return 0;
-    return 1;
-}
-
 static void
 clientUpdateCounters(clientHttpRequest * http)
 {
@@ -851,6 +265,12 @@
 	storeUnlockObject(e);
     }
     requestUnlink(http->request);
+    /* TODO: push refcount class through to head */
+    {
+      clientStreamNode *temp = http->stream_head;
+      cbdataReferenceDone (temp);
+      cbdataFree (http->stream_head);
+    }
     assert(http != http->next);
     assert(http->conn->chr != NULL);
     /* Unlink us from the clients request list */
@@ -897,124 +317,6 @@
 #endif
 }
 
-static void
-clientInterpretRequestHeaders(clientHttpRequest * http)
-{
-    request_t *request = http->request;
-    const HttpHeader *req_hdr = &request->header;
-    int no_cache = 0;
-    const char *str;
-    request->imslen = -1;
-    request->ims = httpHeaderGetTime(req_hdr, HDR_IF_MODIFIED_SINCE);
-    if (request->ims > 0)
-	request->flags.ims = 1;
-    if (httpHeaderHas(req_hdr, HDR_PRAGMA)) {
-	String s = httpHeaderGetList(req_hdr, HDR_PRAGMA);
-	if (strListIsMember(&s, "no-cache", ','))
-	    no_cache++;
-	stringClean(&s);
-    }
-    request->cache_control = httpHeaderGetCc(req_hdr);
-    if (request->cache_control)
-	if (EBIT_TEST(request->cache_control->mask, CC_NO_CACHE))
-	    no_cache++;
-    /* Work around for supporting the Reload button in IE browsers
-     * when Squid is used as an accelerator or transparent proxy,
-     * by turning accelerated IMS request to no-cache requests.
-     * Now knows about IE 5.5 fix (is actually only fixed in SP1, 
-     * but we can't tell whether we are talking to SP1 or not so 
-     * all 5.5 versions are treated 'normally').
-     */
-    if (Config.onoff.ie_refresh) {
-	if (http->flags.accel && request->flags.ims) {
-	    if ((str = httpHeaderGetStr(req_hdr, HDR_USER_AGENT))) {
-		if (strstr(str, "MSIE 5.01") != NULL)
-		    no_cache++;
-		else if (strstr(str, "MSIE 5.0") != NULL)
-		    no_cache++;
-		else if (strstr(str, "MSIE 4.") != NULL)
-		    no_cache++;
-		else if (strstr(str, "MSIE 3.") != NULL)
-		    no_cache++;
-	    }
-	}
-    }
-    if (no_cache) {
-#if HTTP_VIOLATIONS
-	if (Config.onoff.reload_into_ims)
-	    request->flags.nocache_hack = 1;
-	else if (refresh_nocache_hack)
-	    request->flags.nocache_hack = 1;
-	else
-#endif
-	    request->flags.nocache = 1;
-    }
-    /* ignore range header in non-GETs */
-    if (request->method == METHOD_GET) {
-	/*
-	 * Since we're not doing ranges atm, just set the flag if
-	 * the header exists, and then free the range header info
-	 * -- adrian
-	 */
-	request->range = httpHeaderGetRange(req_hdr);
-	if (request->range) {
-	    request->flags.range = 1;
-	    httpHdrRangeDestroy(request->range);
-	    request->range = NULL;
-	}
-    }
-    if (httpHeaderHas(req_hdr, HDR_AUTHORIZATION))
-	request->flags.auth = 1;
-    if (request->login[0] != '\0')
-	request->flags.auth = 1;
-    if (httpHeaderHas(req_hdr, HDR_VIA)) {
-	String s = httpHeaderGetList(req_hdr, HDR_VIA);
-	/*
-	 * ThisCache cannot be a member of Via header, "1.0 ThisCache" can.
-	 * Note ThisCache2 has a space prepended to the hostname so we don't
-	 * accidentally match super-domains.
-	 */
-	if (strListIsSubstr(&s, ThisCache2, ',')) {
-	    debugObj(33, 1, "WARNING: Forwarding loop detected for:\n",
-		request, (ObjPackMethod) & httpRequestPack);
-	    request->flags.loopdetect = 1;
-	}
-#if FORW_VIA_DB
-	fvdbCountVia(strBuf(s));
-#endif
-	stringClean(&s);
-    }
-#if USE_USERAGENT_LOG
-    if ((str = httpHeaderGetStr(req_hdr, HDR_USER_AGENT)))
-	logUserAgent(fqdnFromAddr(http->conn->log_addr), str);
-#endif
-#if USE_REFERER_LOG
-    if ((str = httpHeaderGetStr(req_hdr, HDR_REFERER)))
-	logReferer(fqdnFromAddr(http->conn->log_addr), str,
-	    http->log_uri);
-#endif
-#if FORW_VIA_DB
-    if (httpHeaderHas(req_hdr, HDR_X_FORWARDED_FOR)) {
-	String s = httpHeaderGetList(req_hdr, HDR_X_FORWARDED_FOR);
-	fvdbCountForw(strBuf(s));
-	stringClean(&s);
-    }
-#endif
-    if (request->method == METHOD_TRACE) {
-	request->max_forwards = httpHeaderGetInt(req_hdr, HDR_MAX_FORWARDS);
-    }
-    if (clientCachable(http))
-	request->flags.cachable = 1;
-    if (clientHierarchical(http))
-	request->flags.hierarchical = 1;
-    debug(33, 5) ("clientInterpretRequestHeaders: REQ_NOCACHE = %s\n",
-	request->flags.nocache ? "SET" : "NOT SET");
-    debug(33, 5) ("clientInterpretRequestHeaders: REQ_CACHABLE = %s\n",
-	request->flags.cachable ? "SET" : "NOT SET");
-    debug(33, 5) ("clientInterpretRequestHeaders: REQ_HIERARCHICAL = %s\n",
-	request->flags.hierarchical ? "SET" : "NOT SET");
-}
-
 /*
  * clientSetKeepaliveFlag() sets request->flags.proxy_keepalive.
  * This is the client-side persistent connection flag.  We need
@@ -1060,67 +362,6 @@
     /* NOT REACHED */
 }
 
-static int
-clientCachable(clientHttpRequest * http)
-{
-    request_t *req = http->request;
-    method_t method = req->method;
-    if (req->protocol == PROTO_HTTP)
-	return httpCachable(method);
-    /* FTP is always cachable */
-    if (req->protocol == PROTO_WAIS)
-	return 0;
-    if (method == METHOD_CONNECT)
-	return 0;
-    if (method == METHOD_TRACE)
-	return 0;
-    if (method == METHOD_PUT)
-	return 0;
-    if (method == METHOD_POST)
-	return 0;		/* XXX POST may be cached sometimes.. ignored for now */
-    if (req->protocol == PROTO_GOPHER)
-	return gopherCachable(req);
-    if (req->protocol == PROTO_CACHEOBJ)
-	return 0;
-    return 1;
-}
-
-/* Return true if we can query our neighbors for this object */
-static int
-clientHierarchical(clientHttpRequest * http)
-{
-    const char *url = http->uri;
-    request_t *request = http->request;
-    method_t method = request->method;
-    const wordlist *p = NULL;
-
-    /* IMS needs a private key, so we can use the hierarchy for IMS only
-     * if our neighbors support private keys */
-    if (request->flags.ims && !neighbors_do_private_keys)
-	return 0;
-    if (request->flags.auth)
-	return 0;
-    if (method == METHOD_TRACE)
-	return 1;
-    if (method != METHOD_GET)
-	return 0;
-    /* scan hierarchy_stoplist */
-    for (p = Config.hierarchy_stoplist; p; p = p->next)
-	if (strstr(url, p->key))
-	    return 0;
-    if (request->flags.loopdetect)
-	return 0;
-    if (request->protocol == PROTO_HTTP)
-	return httpCachable(method);
-    if (request->protocol == PROTO_GOPHER)
-	return gopherCachable(request);
-    if (request->protocol == PROTO_WAIS)
-	return 0;
-    if (request->protocol == PROTO_CACHEOBJ)
-	return 0;
-    return 1;
-}
-
 int
 isTcpHit(log_type code)
 {
@@ -1142,571 +383,76 @@
     return 0;
 }
 
+static int
+clientRequestBodyTooLarge(int clen)
+{
+    if (0 == Config.maxRequestBodySize)
+	return 0;		/* disabled */
+    if (clen < 0)
+	return 0;		/* unknown, bug? */
+    if (clen > Config.maxRequestBodySize)
+	return 1;		/* too large */
+    return 0;
+}
 
 /*
- * filters out unwanted entries from original reply header
- * adds extra entries if we have more info than origin server
- * adds Squid specific entries
- */
-static void
-clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep)
-{
-    HttpHeader *hdr = &rep->header;
-    int is_hit = isTcpHit(http->log_type);
-    request_t *request = http->request;
-#if DONT_FILTER_THESE
-    /* but you might want to if you run Squid as an HTTP accelerator */
-    /* httpHeaderDelById(hdr, HDR_ACCEPT_RANGES); */
-    httpHeaderDelById(hdr, HDR_ETAG);
-#endif
-    httpHeaderDelById(hdr, HDR_PROXY_CONNECTION);
-    /* here: Keep-Alive is a field-name, not a connection directive! */
-    httpHeaderDelByName(hdr, "Keep-Alive");
-    /* remove Set-Cookie if a hit */
-    if (is_hit)
-	httpHeaderDelById(hdr, HDR_SET_COOKIE);
-    /* handle Connection header */
-    if (httpHeaderHas(hdr, HDR_CONNECTION)) {
-	/* anything that matches Connection list member will be deleted */
-	String strConnection = httpHeaderGetList(hdr, HDR_CONNECTION);
-	const HttpHeaderEntry *e;
-	HttpHeaderPos pos = HttpHeaderInitPos;
-	/*
-	 * think: on-average-best nesting of the two loops (hdrEntry
-	 * and strListItem) @?@
-	 */
-	/*
-	 * maybe we should delete standard stuff ("keep-alive","close")
-	 * from strConnection first?
-	 */
-	while ((e = httpHeaderGetEntry(hdr, &pos))) {
-	    if (strListIsMember(&strConnection, strBuf(e->name), ','))
-		httpHeaderDelAt(hdr, pos);
-	}
-	httpHeaderDelById(hdr, HDR_CONNECTION);
-	stringClean(&strConnection);
-    }
-    /*
-     * Add a estimated Age header on cache hits.
-     */
-    if (is_hit) {
-	/*
-	 * Remove any existing Age header sent by upstream caches
-	 * (note that the existing header is passed along unmodified
-	 * on cache misses)
-	 */
-	httpHeaderDelById(hdr, HDR_AGE);
-	/*
-	 * This adds the calculated object age. Note that the details of the
-	 * age calculation is performed by adjusting the timestamp in
-	 * storeTimestampsSet(), not here.
-	 *
-	 * BROWSER WORKAROUND: IE sometimes hangs when receiving a 0 Age
-	 * header, so don't use it unless there is a age to report. Please
-	 * note that Age is only used to make a conservative estimation of
-	 * the objects age, so a Age: 0 header does not add any useful
-	 * information to the reply in any case.
-	 */
-	if (NULL == http->entry)
-	    (void) 0;
-	else if (http->entry->timestamp < 0)
-	    (void) 0;
-	else if (http->entry->timestamp < squid_curtime) {
-	    httpHeaderPutInt(hdr, HDR_AGE,
-		squid_curtime - http->entry->timestamp);
-	    /* Signal old objects.  NB: rfc 2616 is not clear, by implication, on 
-	     * whether we should do this to all responses, or only cache hits.
-	     * 14.46 states it ONLY applys for heuristically caclulated 
-	     * freshness values, 13.2.4 doesn't specify the same limitation.
-	     * We interpret RFC 2616 under the combination.
-	     */
-	    /* TODO: if maxage or s-maxage is present, don't do this 
-	     */
-	    if (squid_curtime - http->entry->timestamp >= 86400) {
-		char tempbuf[512];
-		snprintf (tempbuf, sizeof(tempbuf), "%s %s %s", "113", ThisCache,
-		    "This cache hit is still fresh and more than 1 day old");
-		httpHeaderPutStr(hdr, HDR_WARNING, tempbuf);
-	    }
-	}
-	
-    }
-    /* Handle authentication headers */
-    if (request->auth_user_request)
-	authenticateFixHeader(rep, request->auth_user_request, request, http->flags.accel, 0);
-    /* Append X-Cache */
-    httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
-	is_hit ? "HIT" : "MISS", getMyHostname());
-#if USE_CACHE_DIGESTS
-    /* Append X-Cache-Lookup: -- temporary hack, to be removed @?@ @?@ */
-    httpHeaderPutStrf(hdr, HDR_X_CACHE_LOOKUP, "%s from %s:%d",
-	http->lookup_type ? http->lookup_type : "NONE",
-	getMyHostname(), getMyPort());
-#endif
-    if (httpReplyBodySize(request->method, rep) < 0) {
-	debug(33, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n");
-	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,
-	request->flags.proxy_keepalive ? "keep-alive" : "close");
-#if ADD_X_REQUEST_URI
-    /*
-     * Knowing the URI of the request is useful when debugging persistent
-     * connections in a client; we cannot guarantee the order of http headers,
-     * but X-Request-URI is likely to be the very last header to ease use from a
-     * debugger [hdr->entries.count-1].
-     */
-    httpHeaderPutStr(hdr, HDR_X_REQUEST_URI,
-	http->entry->mem_obj->url ? http->entry->mem_obj->url : http->uri);
-#endif
-    httpHdrMangleList(hdr, request);
-}
-
-static HttpReply *
-clientBuildReply(clientHttpRequest * http, const char *buf, size_t size)
-{
-    HttpReply *rep = httpReplyCreate();
-    size_t k = headersEnd(buf, size);
-    if (k && httpReplyParse(rep, buf, k)) {
-	/* enforce 1.0 reply version */
-	httpBuildVersion(&rep->sline.version, 1, 0);
-	/* do header conversions */
-	clientBuildReplyHeader(http, rep);
-    } else {
-	/* parsing failure, get rid of the invalid reply */
-	httpReplyDestroy(rep);
-	rep = NULL;
-    }
-    return rep;
-}
-
-/*
- * clientCacheHit should only be called until the HTTP reply headers
- * have been parsed.  Normally this should be a single call, but
- * it might take more than one.  As soon as we have the headers,
- * we hand off to clientSendMoreData, clientProcessExpired, or
- * clientProcessMiss.
- */
-static void
-clientCacheHit(void *data, char *buf, ssize_t size)
-{
-    clientHttpRequest *http = data;
-    StoreEntry *e = http->entry;
-    MemObject *mem;
-    request_t *r = http->request;
-    debug(33, 3) ("clientCacheHit: %s, %d bytes\n", http->uri, (int) size);
-    if (http->entry == NULL) {
-	debug(33, 3) ("clientCacheHit: request aborted\n");
-	return;
-    } else if (size < 0) {
-	/* swap in failure */
-	debug(33, 3) ("clientCacheHit: swapin failure for %s\n", http->uri);
-	http->log_type = LOG_TCP_SWAPFAIL_MISS;
-	if ((e = http->entry)) {
-	    http->entry = NULL;
-	    storeUnregister(http->sc, e, http);
-	    http->sc = NULL;
-	    storeUnlockObject(e);
-	}
-	clientProcessMiss(http);
-	return;
-    }
-    assert(size > 0);
-    mem = e->mem_obj;
-    assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
-    /* update size of the request */
-    http->reqsize = size + http->reqofs;
-    if (mem->reply->sline.status == 0) {
-	/*
-	 * we don't have full reply headers yet; either wait for more or
-	 * punt to clientProcessMiss.
-	 */
-	if (e->mem_status == IN_MEMORY || e->store_status == STORE_OK) {
-	    clientProcessMiss(http);
-	} else if (size + http->reqofs >= HTTP_REQBUF_SZ && http->out.offset == 0) {
-	    clientProcessMiss(http);
-	} else {
-	    debug(33, 3) ("clientCacheHit: waiting for HTTP reply headers\n");
-	    http->reqofs += size;
-	    assert(http->reqofs <= HTTP_REQBUF_SZ);
-	    storeClientCopy(http->sc, e,
-		http->out.offset + http->reqofs,
-		HTTP_REQBUF_SZ,
-		http->reqbuf + http->reqofs,
-		clientCacheHit,
-		http);
-	}
-	return;
-    }
-    /*
-     * Got the headers, now grok them
-     */
-    assert(http->log_type == LOG_TCP_HIT);
-    switch (varyEvaluateMatch(e, r)) {
-    case VARY_NONE:
-	/* No variance detected. Continue as normal */
-	break;
-    case VARY_MATCH:
-	/* This is the correct entity for this request. Continue */
-	debug(33, 2) ("clientProcessHit: Vary MATCH!\n");
-	break;
-    case VARY_OTHER:
-	/* This is not the correct entity for this request. We need
-	 * to requery the cache.
-	 */
-	http->entry = NULL;
-	storeUnregister(http->sc, e, http);
-	http->sc = NULL;
-	storeUnlockObject(e);
-	/* Note: varyEvalyateMatch updates the request with vary information
-	 * so we only get here once. (it also takes care of cancelling loops)
-	 */
-	debug(33, 2) ("clientProcessHit: Vary detected!\n");
-	clientProcessRequest(http);
-	return;
-    case VARY_CANCEL:
-	/* varyEvaluateMatch found a object loop. Process as miss */
-	debug(33, 1) ("clientProcessHit: Vary object loop!\n");
-	clientProcessMiss(http);
-	return;
-    }
-    if (r->method == METHOD_PURGE) {
-	http->entry = NULL;
-	storeUnregister(http->sc, e, http);
-	http->sc = NULL;
-	storeUnlockObject(e);
-	clientPurgeRequest(http);
-	return;
-    }
-    if (checkNegativeHit(e)) {
-	http->log_type = LOG_TCP_NEGATIVE_HIT;
-	clientSendMoreData(data, buf, size);
-    } else if (r->method == METHOD_HEAD) {
-	/*
-	 * RFC 2068 seems to indicate there is no "conditional HEAD"
-	 * request.  We cannot validate a cached object for a HEAD
-	 * request, nor can we return 304.
-	 */
-	if (e->mem_status == IN_MEMORY)
-	    http->log_type = LOG_TCP_MEM_HIT;
-	clientSendMoreData(data, buf, size);
-    } else if (refreshCheckHTTP(e, r) && !http->flags.internal) {
-	debug(33, 5) ("clientCacheHit: in refreshCheck() block\n");
-	/*
-	 * We hold a stale copy; it needs to be validated
-	 */
-	/*
-	 * The 'need_validation' flag is used to prevent forwarding
-	 * loops between siblings.  If our copy of the object is stale,
-	 * then we should probably only use parents for the validation
-	 * request.  Otherwise two siblings could generate a loop if
-	 * both have a stale version of the object.
-	 */
-	r->flags.need_validation = 1;
-	if (e->lastmod < 0) {
-	    /*
-	     * Previous reply didn't have a Last-Modified header,
-	     * we cannot revalidate it.
-	     */
-	    http->log_type = LOG_TCP_MISS;
-	    clientProcessMiss(http);
-	} else if (r->flags.nocache) {
-	    /*
-	     * This did not match a refresh pattern that overrides no-cache
-	     * we should honour the client no-cache header.
-	     */
-	    http->log_type = LOG_TCP_CLIENT_REFRESH_MISS;
-	    clientProcessMiss(http);
-	} else if (r->protocol == PROTO_HTTP) {
-	    /*
-	     * Object needs to be revalidated
-	     * XXX This could apply to FTP as well, if Last-Modified is known.
-	     */
-	    http->log_type = LOG_TCP_REFRESH_MISS;
-	    clientProcessExpired(http);
-	} else {
-	    /*
-	     * We don't know how to re-validate other protocols. Handle
-	     * them as if the object has expired.
-	     */
-	    http->log_type = LOG_TCP_MISS;
-	    clientProcessMiss(http);
-	}
-    } else if (r->flags.ims) {
-	/*
-	 * Handle If-Modified-Since requests from the client
-	 */
-	if (mem->reply->sline.status != HTTP_OK) {
-	    debug(33, 4) ("clientCacheHit: Reply code %d != 200\n",
-		mem->reply->sline.status);
-	    http->log_type = LOG_TCP_MISS;
-	    clientProcessMiss(http);
-	} else if (modifiedSince(e, http->request)) {
-	    http->log_type = LOG_TCP_IMS_HIT;
-	    clientSendMoreData(data, buf, size);
-	} else {
-	    time_t timestamp = e->timestamp;
-	    MemBuf mb = httpPacked304Reply(e->mem_obj->reply);
-	    http->log_type = LOG_TCP_IMS_HIT;
-	    storeUnregister(http->sc, e, http);
-	    http->sc = NULL;
-	    storeUnlockObject(e);
-	    e = clientCreateStoreEntry(http, http->request->method, null_request_flags);
-	    /*
-	     * Copy timestamp from the original entry so the 304
-	     * reply has a meaningful Age: header.
-	     */
-	    e->timestamp = timestamp;
-	    http->entry = e;
-	    httpReplyParse(e->mem_obj->reply, mb.buf, mb.size);
-	    storeAppend(e, mb.buf, mb.size);
-	    memBufClean(&mb);
-	    storeComplete(e);
-	}
-    } else {
-	/*
-	 * plain ol' cache hit
-	 */
-	if (e->mem_status == IN_MEMORY)
-	    http->log_type = LOG_TCP_MEM_HIT;
-	else if (Config.onoff.offline)
-	    http->log_type = LOG_TCP_OFFLINE_HIT;
-	clientSendMoreData(data, buf, size);
-    }
-}
-
-
-static int
-clientReplyBodyTooLarge(HttpReply * rep, ssize_t clen)
-{
-    if (0 == rep->maxBodySize)
-	return 0;		/* disabled */
-    if (clen < 0)
-	return 0;		/* unknown */
-    if (clen > rep->maxBodySize)
-	return 1;		/* too large */
-    return 0;
-}
-
-static int
-clientRequestBodyTooLarge(int clen)
-{
-    if (0 == Config.maxRequestBodySize)
-	return 0;		/* disabled */
-    if (clen < 0)
-	return 0;		/* unknown, bug? */
-    if (clen > Config.maxRequestBodySize)
-	return 1;		/* too large */
-    return 0;
-}
-
-
-/* Responses with no body will not have a content-type header, 
- * which breaks the rep_mime_type acl, which
- * coincidentally, is the most common acl for reply access lists.
- * A better long term fix for this is to allow acl matchs on the various
- * status codes, and then supply a default ruleset that puts these 
- * codes before any user defines access entries. That way the user 
- * can choose to block these responses where appropriate, but won't get
- * mysterious breakages.
- */
-static int
-clientAlwaysAllowResponse(http_status sline)
-{
-    switch (sline) {
-    case HTTP_CONTINUE:
-    case HTTP_SWITCHING_PROTOCOLS:
-    case HTTP_PROCESSING:
-    case HTTP_NO_CONTENT:
-    case HTTP_NOT_MODIFIED:
-	return 1;
-	/* unreached */
-	break;
-    default:
-	return 0;
-    }
-}
-
-
-/*
- * accepts chunk of a http message in buf, parses prefix, filters headers and
- * such, writes processed message to the client's socket
+ * Write a chunk of data to a client socket. If the reply is present, send the reply headers down the wire too,
+ * and clean them up when finished.
+ * Pre-condition: 
+ *   The request is one backed by a connection, not an internal request.
+ *   data context is null
+ *   There are no more entries in the stream chain.
  */
 static void
-clientSendMoreData(void *data, char *retbuf, ssize_t retsize)
+clientSocketRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply *rep, const char *body_data, ssize_t body_size)
 {
-    clientHttpRequest *http = data;
-    StoreEntry *entry = http->entry;
-    ConnStateData *conn = http->conn;
-    int fd = conn->fd;
-    HttpReply *rep = NULL;
-    char *buf = http->reqbuf;
-    const char *body_buf = buf;
-    ssize_t size = http->reqofs + retsize;
-    ssize_t body_size = size;
-    MemBuf mb;
-    ssize_t check_size = 0;
-
-    debug(33, 5) ("clientSendMoreData: %s, %d bytes (%d new bytes)\n", http->uri, (int) size, retsize);
-    assert(size <= HTTP_REQBUF_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",
-	fd, storeUrl(entry), (long int) http->out.offset);
-    /* update size of the request */
-    http->reqsize = size;
-    if (conn->chr != http) {
-	/* there is another object in progress, defer this one */
-	debug(33, 2) ("clientSendMoreData: Deferring %s\n", storeUrl(entry));
-	return;
-    } else if (http->request->flags.reset_tcp) {
-	comm_reset_close(fd);
-	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);
-	return;
-    } else if (retsize < 0) {
-	/* call clientWriteComplete so the client socket gets closed */
-	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
-	return;
-    } else if (retsize == 0) {
-	/* call clientWriteComplete so the client socket gets closed */
+    int fd;
+    /* Test preconditions */
+    assert (node != NULL);
+    /* TODO: handle this rather than asserting - it should only ever happen if we cause an abort and the callback chain 
+     * loops back to here, so we can simply return. However, that itself shouldn't happen, so it stays as an assert for now. */
+    assert (cbdataReferenceValid (node));
+    assert (node->data == NULL);
+    assert (node->next == NULL);
+    assert (http->conn && http->conn->fd != -1);
+    fd = http->conn->fd;
+    /* EOF / Read error /  aborted entry */
+    if (rep == NULL && body_data == NULL && body_size == 0) {
 	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
 	return;
     }
-    if (http->out.offset == 0) {
-	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);
-	    }
-	}
-	rep = clientBuildReply(http, buf, size);
-	if (rep) {
-	    aclCheck_t *ch;
-	    int rv;
-	    httpReplyBodyBuildSize(http->request, rep, &Config.ReplyBodySize);
-	    if (clientReplyBodyTooLarge(rep, 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->entry = clientCreateStoreEntry(http, http->request->method,
-		    null_request_flags);
-		errorAppendEntry(http->entry, err);
-		httpReplyDestroy(rep);
-		return;
-	    }
-	    body_size = size - rep->hdr_sz;
-	    assert(body_size >= 0);
-	    body_buf = buf + rep->hdr_sz;
-	    debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n",
-		(int) body_size, rep->hdr_sz);
-	    ch = aclChecklistCreate(Config.accessList.reply, http->request, NULL);
-	    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 && rep->sline.status != HTTP_FORBIDDEN
-		&& !clientAlwaysAllowResponse(rep->sline.status)) {
-		/* the if above is slightly broken, but there is no way
-		 * to tell if this is a squid generated error page, or one from
-		 * upstream at this point. */
-		ErrorState *err;
-		err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN);
-		err->request = requestLink(http->request);
-		storeUnregister(http->sc, http->entry, http);
-		http->sc = NULL;
-		storeUnlockObject(http->entry);
-		http->entry = clientCreateStoreEntry(http, http->request->method,
-		    null_request_flags);
-		errorAppendEntry(http->entry, err);
-		httpReplyDestroy(rep);
-		return;
-	    }
-	} else if (size < HTTP_REQBUF_SZ && entry->store_status == STORE_PENDING) {
-	    /* wait for more to arrive */
-	    http->reqofs += retsize;
-	    assert(http->reqofs <= HTTP_REQBUF_SZ);
-	    storeClientCopy(http->sc, entry,
-		http->out.offset + http->reqofs,
-		HTTP_REQBUF_SZ - http->reqofs,
-		http->reqbuf + http->reqofs,
-		clientSendMoreData,
-		http);
-	    return;
-	}
-    } else {
+    /* trivial case */
+    if (http->out.offset != 0) {
+	assert(rep == NULL);
 	/* Avoid copying to MemBuf if we know "rep" is NULL, and we only have a body */
 	http->out.offset += body_size;
-	assert(rep == NULL);
-	comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL);
+	comm_write(fd, body_data, body_size, clientWriteBodyComplete, http, NULL);
 	/* NULL because clientWriteBodyComplete frees it */
 	return;
-    }
-    if (http->request->method == METHOD_HEAD) {
+    } else {
+	MemBuf mb;
+	/* write headers and/or body if any */
+	assert(rep || (body_data && body_size));
+	/* init mb; put status line and headers if any */
 	if (rep) {
-	    /* do not forward body for HEAD replies */
-	    body_size = 0;
-	    http->flags.done_copying = 1;
-	} 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;
-	}
-    }
-    /* write headers and/or body if any */
-    assert(rep || (body_buf && body_size));
-    /* init mb; put status line and headers if any */
-    if (rep) {
-	mb = httpReplyPack(rep);
-	http->out.offset += rep->hdr_sz;
-	check_size += rep->hdr_sz;
+	    mb = httpReplyPack(rep);
+	    http->out.offset += rep->hdr_sz;
 #if HEADERS_LOG
-	headersLog(0, 0, http->request->method, rep);
+	    headersLog(0, 0, http->request->method, rep);
 #endif
-	httpReplyDestroy(rep);
-	rep = NULL;
-    } else {
-	memBufDefInit(&mb);
-    }
-    if (body_buf && body_size) {
-	http->out.offset += body_size;
-	check_size += body_size;
-	memBufAppend(&mb, body_buf, body_size);
+	    httpReplyDestroy(rep);
+	    rep = NULL;
+	} else {
+	    memBufDefInit(&mb);
+	}
+	if (body_data && body_size) {
+	    http->out.offset += body_size;
+	    memBufAppend(&mb, body_data, body_size);
+	}
+	/* write */
+	comm_write_mbuf(fd, mb, clientWriteComplete, http);
+	/* if we don't do it, who will? */
     }
-    /* write */
-    comm_write_mbuf(fd, mb, clientWriteComplete, http);
-    /* if we don't do it, who will? */
 }
 
 /*
@@ -1794,73 +540,45 @@
     }
 }
 
+
+/* A write has just completed to the client, or we have just realised there is
+ * no more data to send.
+ */
 static void
 clientWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
 {
     clientHttpRequest *http = data;
     StoreEntry *entry = http->entry;
-    int done;
     http->out.size += size;
     debug(33, 5) ("clientWriteComplete: FD %d, sz %ld, err %d, off %ld, len %d\n",
 	fd, (long int) size, errflag, (long int) http->out.offset, entry ? objectLen(entry) : 0);
-    if (size > 0) {
+    if (size > 0 && fd > -1) {
 	kb_incr(&statCounter.client_http.kbytes_out, size);
 	if (isTcpHit(http->log_type))
 	    kb_incr(&statCounter.client_http.hit_kbytes_out, size);
     }
-#if SIZEOF_SIZE_T == 4
-    if (http->out.size > 0x7FFF0000) {
-	debug(33, 1) ("WARNING: closing FD %d to prevent counter overflow\n", fd);
-	debug(33, 1) ("\tclient %s\n", inet_ntoa(http->conn->peer.sin_addr));
-	debug(33, 1) ("\treceived %d bytes\n", (int) http->out.size);
-	debug(33, 1) ("\tURI %s\n", http->log_uri);
-	comm_close(fd);
-    } else
-#endif
-#if SIZEOF_OFF_T == 4
-    if (http->out.offset > 0x7FFF0000) {
-	debug(33, 1) ("WARNING: closing FD %d to prevent counter overflow\n", fd);
-	debug(33, 1) ("\tclient %s\n", inet_ntoa(http->conn->peer.sin_addr));
-	debug(33, 1) ("\treceived %d bytes (offset %d)\n", (int) http->out.size,
-	    (int) http->out.offset);
-	debug(33, 1) ("\tURI %s\n", http->log_uri);
-	comm_close(fd);
-    } else
-#endif
     if (errflag) {
 	/*
-	 * just close the socket, httpRequestFree will abort if needed
+	 * just close the socket, httpRequestFree will abort if needed.
+	 * errflag is only EVER set by the comms callbacks
 	 */
+	assert (fd != -1);
 	comm_close(fd);
-    } else if (NULL == entry) {
-	comm_close(fd);		/* yuk */
-    } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-	comm_close(fd);
-    } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) {
-	debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd);
-	/* We're finished case */
-	if (httpReplyBodySize(http->request->method, entry->mem_obj->reply) < 0) {
+	return;
+    }
+    switch (clientDetermineActionAfterWrite(fd, http, entry, size)){
+      case 0:
 	    debug(33, 5) ("clientWriteComplete: closing, content_length < 0\n");
-	    comm_close(fd);
-	} else if (!done) {
-	    debug(33, 5) ("clientWriteComplete: closing, !done\n");
-	    comm_close(fd);
-	} else if (clientGotNotEnough(http)) {
-	    debug(33, 5) ("clientWriteComplete: client didn't get all it expected\n");
-	    comm_close(fd);
-	} else if (http->request->flags.proxy_keepalive) {
-	    debug(33, 5) ("clientWriteComplete: FD %d Keeping Alive\n", fd);
 	    clientKeepaliveNextRequest(http);
-	} else {
-	    comm_close(fd);
-	}
-    } else if (clientReplyBodyTooLarge(entry->mem_obj->reply, http->out.offset)) {
-	comm_close(fd);
-    } else {
-	/* More data will be coming from primary server; register with 
-	 * storage manager. */
-	if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
-	    debug(33, 0) ("clientWriteComplete 2: ENTRY_ABORTED\n");
+	    return;
+      case 1: /* fallthru */
+      case 2: 
+	    if (fd != -1)
+		comm_close (fd);
+	    return;
+      case 3:
+	    /* More data will be coming from primary server; register with
+	     * storage manager. */
 	http->reqofs = 0;
 	storeClientCopy(http->sc, entry,
 	    http->out.offset,
@@ -1868,243 +586,11 @@
 	    http->reqbuf,
 	    clientSendMoreData,
 	    http);
+	break;
+      default:fatal ("Hit unreachable code in clientWriteComplete\n");
     }
 }
 
-/*
- * client issued a request with an only-if-cached cache-control directive;
- * we did not find a cached object that can be returned without
- *     contacting other servers;
- * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068]
- */
-static void
-clientProcessOnlyIfCachedMiss(clientHttpRequest * http)
-{
-    char *url = http->uri;
-    request_t *r = http->request;
-    ErrorState *err = NULL;
-    debug(33, 4) ("clientProcessOnlyIfCachedMiss: '%s %s'\n",
-	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->src_addr = http->conn->peer.sin_addr;
-    if (http->entry) {
-	storeUnregister(http->sc, http->entry, http);
-	http->sc = NULL;
-	storeUnlockObject(http->entry);
-    }
-    http->entry = clientCreateStoreEntry(http, r->method, null_request_flags);
-    errorAppendEntry(http->entry, err);
-}
-
-static log_type
-clientProcessRequest2(clientHttpRequest * http)
-{
-    request_t *r = http->request;
-    StoreEntry *e;
-    if (r->flags.cachable || r->flags.internal)
-	e = http->entry = storeGetPublicByRequest(r);
-    else
-	e = http->entry = NULL;
-    /* Release negatively cached IP-cache entries on reload */
-    if (r->flags.nocache)
-	ipcacheInvalidate(r->host);
-#if HTTP_VIOLATIONS
-    else if (r->flags.nocache_hack)
-	ipcacheInvalidate(r->host);
-#endif
-#if USE_CACHE_DIGESTS
-    http->lookup_type = e ? "HIT" : "MISS";
-#endif
-    if (NULL == e) {
-	/* this object isn't in the cache */
-	debug(33, 3) ("clientProcessRequest2: storeGet() MISS\n");
-	return LOG_TCP_MISS;
-    }
-    if (Config.onoff.offline) {
-	debug(33, 3) ("clientProcessRequest2: offline HIT\n");
-	http->entry = e;
-	return LOG_TCP_HIT;
-    }
-    if (http->redirect.status) {
-	/* force this to be a miss */
-	http->entry = NULL;
-	return LOG_TCP_MISS;
-    }
-    if (!storeEntryValidToSend(e)) {
-	debug(33, 3) ("clientProcessRequest2: !storeEntryValidToSend MISS\n");
-	http->entry = NULL;
-	return LOG_TCP_MISS;
-    }
-    if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) {
-	/* Special entries are always hits, no matter what the client says */
-	debug(33, 3) ("clientProcessRequest2: ENTRY_SPECIAL HIT\n");
-	http->entry = e;
-	return LOG_TCP_HIT;
-    }
-#if HTTP_VIOLATIONS
-    if (e->store_status == STORE_PENDING) {
-	if (r->flags.nocache || r->flags.nocache_hack) {
-	    debug(33, 3) ("Clearing no-cache for STORE_PENDING request\n\t%s\n",
-		storeUrl(e));
-	    r->flags.nocache = 0;
-	    r->flags.nocache_hack = 0;
-	}
-    }
-#endif
-    if (r->flags.nocache) {
-	debug(33, 3) ("clientProcessRequest2: no-cache REFRESH MISS\n");
-	http->entry = NULL;
-	return LOG_TCP_CLIENT_REFRESH_MISS;
-    }
-    /* We don't cache any range requests (for now!) -- adrian */
-    if (r->flags.range) {
-	http->entry = NULL;
-	return LOG_TCP_MISS;
-    }
-    debug(33, 3) ("clientProcessRequest2: default HIT\n");
-    http->entry = e;
-    return LOG_TCP_HIT;
-}
-
-static void
-clientProcessRequest(clientHttpRequest * http)
-{
-    char *url = http->uri;
-    request_t *r = http->request;
-    HttpReply *rep;
-    http_version_t version;
-    debug(33, 4) ("clientProcessRequest: %s '%s'\n",
-	RequestMethodStr[r->method],
-	url);
-    if (r->method == METHOD_CONNECT) {
-	http->log_type = LOG_TCP_MISS;
-	sslStart(http, &http->out.size, &http->al.http.code);
-	return;
-    } else if (r->method == METHOD_PURGE) {
-	clientPurgeRequest(http);
-	return;
-    } else if (r->method == METHOD_TRACE) {
-	if (r->max_forwards == 0) {
-	    http->entry = clientCreateStoreEntry(http, r->method, null_request_flags);
-	    storeReleaseRequest(http->entry);
-	    storeBuffer(http->entry);
-	    rep = httpReplyCreate();
-	    httpBuildVersion(&version, 1, 0);
-	    httpReplySetHeaders(rep, version, HTTP_OK, NULL, "text/plain",
-		httpRequestPrefixLen(r), 0, squid_curtime);
-	    httpReplySwapOut(rep, http->entry);
-	    httpReplyDestroy(rep);
-	    httpRequestSwapOut(r, http->entry);
-	    storeComplete(http->entry);
-	    return;
-	}
-	/* yes, continue */
-	http->log_type = LOG_TCP_MISS;
-    } else {
-	http->log_type = clientProcessRequest2(http);
-    }
-    debug(33, 4) ("clientProcessRequest: %s for '%s'\n",
-	log_tags[http->log_type],
-	http->uri);
-    http->out.offset = 0;
-    if (NULL != http->entry) {
-	storeLockObject(http->entry);
-	if (NULL == http->entry->mem_obj) {
-	    /*
-	     * This if-block exists because we don't want to clobber
-	     * a preexiting mem_obj->method value if the mem_obj
-	     * already exists.  For example, when a HEAD request
-	     * is a cache hit for a GET response, we want to keep
-	     * the method as GET.
-	     */
-	    storeCreateMemObject(http->entry, http->uri, http->log_uri);
-	    http->entry->mem_obj->method = r->method;
-	}
-	http->sc = storeClientListAdd(http->entry, http);
-#if DELAY_POOLS
-	delaySetStoreClient(http->sc, delayClient(http));
-#endif
-	assert(http->log_type == LOG_TCP_HIT);
-	http->reqofs = 0;
-	storeClientCopy(http->sc, http->entry,
-	    http->out.offset,
-	    HTTP_REQBUF_SZ,
-	    http->reqbuf,
-	    clientCacheHit,
-	    http);
-    } else {
-	/* MISS CASE, http->log_type is already set! */
-	clientProcessMiss(http);
-    }
-}
-
-/*
- * Prepare to fetch the object as it's a cache miss of some kind.
- */
-static void
-clientProcessMiss(clientHttpRequest * http)
-{
-    char *url = http->uri;
-    request_t *r = http->request;
-    ErrorState *err = NULL;
-    debug(33, 4) ("clientProcessMiss: '%s %s'\n",
-	RequestMethodStr[r->method], url);
-    /*
-     * We might have a left-over StoreEntry from a failed cache hit
-     * or IMS request.
-     */
-    if (http->entry) {
-	if (EBIT_TEST(http->entry->flags, ENTRY_SPECIAL)) {
-	    debug(33, 0) ("clientProcessMiss: miss on a special object (%s).\n", url);
-	    debug(33, 0) ("\tlog_type = %s\n", log_tags[http->log_type]);
-	    storeEntryDump(http->entry, 1);
-	}
-	storeUnregister(http->sc, http->entry, http);
-	http->sc = NULL;
-	storeUnlockObject(http->entry);
-	http->entry = NULL;
-    }
-    if (r->method == METHOD_PURGE) {
-	clientPurgeRequest(http);
-	return;
-    }
-    if (clientOnlyIfCached(http)) {
-	clientProcessOnlyIfCachedMiss(http);
-	return;
-    }
-    /*
-     * Deny loops when running in accelerator/transproxy mode.
-     */
-    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->src_addr = http->conn->peer.sin_addr;
-	http->entry = clientCreateStoreEntry(http, r->method, null_request_flags);
-	errorAppendEntry(http->entry, err);
-	return;
-    }
-    assert(http->out.offset == 0);
-    http->entry = clientCreateStoreEntry(http, r->method, r->flags);
-    if (http->redirect.status) {
-	HttpReply *rep = httpReplyCreate();
-#if LOG_TCP_REDIRECTS
-	http->log_type = LOG_TCP_REDIRECT;
-#endif
-	storeReleaseRequest(http->entry);
-	httpRedirectReply(rep, http->redirect.status, http->redirect.location);
-	httpReplySwapOut(rep, http->entry);
-	httpReplyDestroy(rep);
-	storeComplete(http->entry);
-	return;
-    }
-    if (http->flags.internal)
-	r->protocol = PROTO_INTERNAL;
-    fwdStart(http->conn->fd, http->entry, r);
-}
-
 static clientHttpRequest *
 parseHttpRequestAbort(ConnStateData * conn, const char *uri)
 {
@@ -2116,10 +602,78 @@
     http->uri = xstrdup(uri);
     http->log_uri = xstrndup(uri, MAX_URL);
     http->reqbuf = http->norm_reqbuf;
+    /* default socket stream terminator */
+    http->stream_head = NULL;
+    clientStreamInsertHead (&http->stream_head, clientSocketRecipient, NULL);
     dlinkAdd(http, &http->active, &ClientActiveRequests);
     return http;
 }
 
+/* Utility function to perform part of request parsing */
+static clientHttpRequest *
+clientParseHttpRequestLine (char *inbuf, size_t req_sz, ConnStateData * conn, method_t *method_p, char **url_p, http_version_t *http_ver_p)
+{
+    char *mstr = NULL;
+    char *url = NULL;
+    char *token = NULL;
+    char *t;
+    /* Barf on NULL characters in the headers */
+    if (strlen(inbuf) != req_sz) {
+	debug(33, 1) ("parseHttpRequest: Requestheader contains NULL characters\n");
+	return parseHttpRequestAbort(conn, "error:invalid-request");
+    }
+
+    /* Look for request method */
+    if ((mstr = strtok(inbuf, "\t ")) == NULL) {
+	debug(33, 1) ("parseHttpRequest: Can't get request method\n");
+	return parseHttpRequestAbort(conn, "error:invalid-request-method");
+    }
+    *method_p = urlParseMethod(mstr);
+    if (*method_p == METHOD_NONE) {
+	debug(33, 1) ("parseHttpRequest: Unsupported method '%s'\n", mstr);
+	return parseHttpRequestAbort(conn, "error:unsupported-request-method");
+    }
+    debug(33, 5) ("parseHttpRequest: Method is '%s'\n", mstr);
+
+    /* look for URL+HTTP/x.x */
+    if ((url = strtok(NULL, "\n")) == NULL) {
+        debug(33, 1) ("parseHttpRequest: Missing URL\n");
+        return parseHttpRequestAbort(conn, "error:missing-url");
+    }
+    while (xisspace(*url))
+        url++;
+    t = url + strlen(url);
+    assert(*t == '\0');
+    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);
+    *url_p = url;
+    if (token == NULL) {
+        debug(33, 3) ("parseHttpRequest: Missing HTTP identifier\n");
+#if RELAXED_HTTP_PARSER
+        httpBuildVersion(http_ver_p, 0, 9);      /* wild guess */
+#else
+        return parseHttpRequestAbort(conn, "error:missing-http-ident");
+#endif
+    } else {
+        if (sscanf(token + 5, "%d.%d", &http_ver_p->major, &http_ver_p->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_p->major, http_ver_p->minor);
+    }
+
+    /* everything was ok */
+    return NULL;
+}
+
 /*
  *  parseHttpRequest()
  * 
@@ -2132,19 +686,16 @@
     char **prefix_p, size_t * req_line_sz_p)
 {
     char *inbuf = NULL;
-    char *mstr = NULL;
     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 */
     size_t prefix_sz;		/* size of whole request (req-line + headers) */
     size_t url_sz;
     size_t req_sz;
-    method_t method;
-    clientHttpRequest *http = NULL;
+    clientHttpRequest *http;
 #if IPF_TRANSPARENT
     struct natlookup natLookup;
     static int natfd = -1;
@@ -2175,63 +726,11 @@
     xmemcpy(inbuf, conn->in.buf, req_sz);
     *(inbuf + req_sz) = '\0';
 
-    /* Barf on NULL characters in the headers */
-    if (strlen(inbuf) != req_sz) {
-	debug(33, 1) ("parseHttpRequest: Requestheader contains NULL characters\n");
-	xfree(inbuf);
-	return parseHttpRequestAbort(conn, "error:invalid-request");
-    }
-    /* 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");
-    }
-    method = urlParseMethod(mstr);
-    if (method == METHOD_NONE) {
-	debug(33, 1) ("parseHttpRequest: Unsupported method '%s'\n", mstr);
-	xfree(inbuf);
-	return parseHttpRequestAbort(conn, "error:unsupported-request-method");
-    }
-    debug(33, 5) ("parseHttpRequest: Method is '%s'\n", mstr);
-    *method_p = method;
-
-    /* look for URL+HTTP/x.x */
-    if ((url = strtok(NULL, "\n")) == NULL) {
-	debug(33, 1) ("parseHttpRequest: Missing URL\n");
-	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
+    /* Is there a legitimate first line to the headers ? */
+    if ((http = clientParseHttpRequestLine (inbuf, req_sz, conn, method_p, &url, &http_ver))) {
+	/* something wrong, abort */
 	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");
-	    xfree(inbuf);
-	    return parseHttpRequestAbort(conn, "error: invalid HTTP-ident");
-	}
-	debug(33, 6) ("parseHttpRequest: Client HTTP version %d.%d.\n", http_ver.major, http_ver.minor);
+	return http;
     }
 
     /*
@@ -2263,11 +762,16 @@
     http->start = current_time;
     http->req_sz = prefix_sz;
     http->reqbuf = http->norm_reqbuf;
+    /* default socket based stream terminator */
+    http->stream_head = NULL;
+    clientStreamInsertHead (&http->stream_head, clientSocketRecipient, NULL);
     *prefix_p = xmalloc(prefix_sz + 1);
     xmemcpy(*prefix_p, conn->in.buf, prefix_sz);
     *(*prefix_p + prefix_sz) = '\0';
     dlinkAdd(http, &http->active, &ClientActiveRequests);
 
+    /* XXX this function is still way to long. here is a natural point for further simplification */
+    
     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 */
@@ -2587,7 +1091,8 @@
 	    commSetTimeout(fd, Config.Timeout.lifetime, clientLifetimeTimeout, http);
 	    if (parser_return_code < 0) {
 		debug(33, 1) ("clientReadRequest: FD %d Invalid Request\n", fd);
-		err = errorCon(ERR_INVALID_REQ, HTTP_BAD_REQUEST);
+		err = clientBuildError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, NULL, &conn->peer.sin_addr,
+				       NULL);
 		err->request_hdrs = xstrdup(conn->in.buf);
 		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
 		errorAppendEntry(http->entry, err);
@@ -2596,9 +1101,8 @@
 	    }
 	    if ((request = urlParse(method, http->uri)) == NULL) {
 		debug(33, 5) ("Invalid URL: %s\n", http->uri);
-		err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST);
-		err->src_addr = conn->peer.sin_addr;
-		err->url = xstrdup(http->uri);
+		err = clientBuildError(ERR_INVALID_URL, HTTP_BAD_REQUEST, http->uri,
+				       &conn->peer.sin_addr, NULL);
 		http->al.http.code = err->http_status;
 		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
 		errorAppendEntry(http->entry, err);
@@ -2640,9 +1144,8 @@
 	    request->http_ver = http->http_ver;
 	    if (!urlCheckRequest(request) ||
 		httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) {
-		err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
-		err->src_addr = conn->peer.sin_addr;
-		err->request = requestLink(request);
+		err = clientBuildError(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED, NULL, &conn->peer.sin_addr,
+				       request);
 		request->flags.proxy_keepalive = 0;
 		http->al.http.code = err->http_status;
 		http->entry = clientCreateStoreEntry(http, request->method, null_request_flags);
@@ -2650,9 +1153,8 @@
 		break;
 	    }
 	    if (!clientCheckContentLength(request)) {
-		err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
-		err->src_addr = conn->peer.sin_addr;
-		err->request = requestLink(request);
+		err = clientBuildError(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED, NULL,
+				       &conn->peer.sin_addr, request);
 		http->al.http.code = err->http_status;
 		http->entry = clientCreateStoreEntry(http, request->method, null_request_flags);
 		errorAppendEntry(http->entry, err);
@@ -2666,8 +1168,8 @@
 		request->body_connection = conn;
 		/* Is it too large? */
 		if (clientRequestBodyTooLarge(request->content_length)) {
-		    err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE);
-		    err->request = requestLink(request);
+		    err = clientBuildError(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE, NULL, 
+				   &conn->peer.sin_addr, http->request);
 		    http->entry = clientCreateStoreEntry(http,
 			METHOD_NONE, null_request_flags);
 		    errorAppendEntry(http->entry, err);
@@ -2687,7 +1189,8 @@
 		    (int) conn->in.offset);
 		debug(33, 1) ("Config 'request_header_max_size'= %ld bytes.\n",
 		    (long int) Config.maxRequestHeaderSize);
-		err = errorCon(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE);
+		err = clientBuildError(ERR_TOO_BIG, HTTP_REQUEST_ENTITY_TOO_LARGE, NULL,
+				       &conn->peer.sin_addr, NULL);
 		http = parseHttpRequestAbort(conn, "error:request-too-large");
 		/* add to the client request queue */
 		for (H = &conn->chr; *H; H = &(*H)->next);
@@ -2844,8 +1347,7 @@
 	/*
 	 * Generate an error
 	 */
-	err = errorCon(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT);
-	err->url = xstrdup("N/A");
+	err = clientBuildError(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT, "N/A", &conn->peer.sin_addr, NULL);
 	/*
 	 * Normally we shouldn't call errorSend() in client_side.c, but
 	 * it should be okay in this case.  Presumably if we get here
@@ -3066,86 +1568,6 @@
 
 #endif /* USE_SSL */
 
-#define SENDING_BODY 0
-#define SENDING_HDRSONLY 1
-static int
-clientCheckTransferDone(clientHttpRequest * http)
-{
-    int sending = SENDING_BODY;
-    StoreEntry *entry = http->entry;
-    MemObject *mem;
-    http_reply *reply;
-    int sendlen;
-    if (entry == NULL)
-	return 0;
-    /*
-     * For now, 'done_copying' is used for special cases like
-     * Range and HEAD requests.
-     */
-    if (http->flags.done_copying)
-	return 1;
-    /*
-     * Handle STORE_OK objects.
-     * objectLen(entry) will be set proprely.
-     */
-    if (entry->store_status == STORE_OK) {
-	if (http->out.offset >= objectLen(entry))
-	    return 1;
-	else
-	    return 0;
-    }
-    /*
-     * Now, handle STORE_PENDING objects
-     */
-    mem = entry->mem_obj;
-    assert(mem != NULL);
-    assert(http->request != NULL);
-    reply = mem->reply;
-    if (reply->hdr_sz == 0)
-	return 0;		/* haven't found end of headers yet */
-    else if (reply->sline.status == HTTP_OK)
-	sending = SENDING_BODY;
-    else if (reply->sline.status == HTTP_NO_CONTENT)
-	sending = SENDING_HDRSONLY;
-    else if (reply->sline.status == HTTP_NOT_MODIFIED)
-	sending = SENDING_HDRSONLY;
-    else if (reply->sline.status < HTTP_OK)
-	sending = SENDING_HDRSONLY;
-    else if (http->request->method == METHOD_HEAD)
-	sending = SENDING_HDRSONLY;
-    else
-	sending = SENDING_BODY;
-    /*
-     * Figure out how much data we are supposed to send.
-     * If we are sending a body and we don't have a content-length,
-     * then we must wait for the object to become STORE_OK.
-     */
-    if (sending == SENDING_HDRSONLY)
-	sendlen = reply->hdr_sz;
-    else if (reply->content_length < 0)
-	return 0;
-    else
-	sendlen = reply->content_length + reply->hdr_sz;
-    /*
-     * Now that we have the expected length, did we send it all?
-     */
-    if (http->out.offset < sendlen)
-	return 0;
-    else
-	return 1;
-}
-
-static int
-clientGotNotEnough(clientHttpRequest * http)
-{
-    int cl = httpReplyBodySize(http->request->method, http->entry->mem_obj->reply);
-    int hs = http->entry->mem_obj->reply->hdr_sz;
-    assert(cl >= 0);
-    if (http->out.offset < cl + hs)
-	return 1;
-    return 0;
-}
-
 /*
  * This function is designed to serve a fairly specific purpose.
  * Occasionally our vBNS-connected caches can talk to each other, but not
Index: squid/src/errorpage.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/errorpage.c,v
retrieving revision 1.21
retrieving revision 1.21.6.1
diff -u -r1.21 -r1.21.6.1
--- squid/src/errorpage.c	19 Jul 2002 00:01:05 -0000	1.21
+++ squid/src/errorpage.c	5 Sep 2002 10:28:20 -0000	1.21.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: errorpage.c,v 1.21 2002/07/19 00:01:05 squidadm Exp $
+ * $Id: errorpage.c,v 1.21.6.1 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 4     Error Generation
  * AUTHOR: Duane Wessels
@@ -41,7 +41,8 @@
  */
 
 #include "squid.h"
-
+#include "HttpReply.h"
+#include "HttpRequest.h"
 
 /* local types */
 
@@ -315,7 +316,6 @@
      */
     authenticateFixHeader(rep, err->auth_user_request, err->request, 0, 1);
     httpReplySwapOut(rep, entry);
-    httpReplyAbsorb(mem->reply, rep);
     EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
     storeBufferFlush(entry);
     storeComplete(entry);
Index: squid/src/forward.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/forward.c,v
retrieving revision 1.16
retrieving revision 1.16.6.1
diff -u -r1.16 -r1.16.6.1
--- squid/src/forward.c	21 Jun 2002 13:00:28 -0000	1.16
+++ squid/src/forward.c	5 Sep 2002 10:28:20 -0000	1.16.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: forward.c,v 1.16 2002/06/21 13:00:28 squidadm Exp $
+ * $Id: forward.c,v 1.16.6.1 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 17    Request Forwarding
  * AUTHOR: Duane Wessels
@@ -35,6 +35,7 @@
 
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 static PSC fwdStartComplete;
 static void fwdDispatch(FwdState *);
@@ -339,6 +340,7 @@
 	ctimeout = fs->peer->connect_timeout > 0 ? fs->peer->connect_timeout
 	    : Config.Timeout.peer_connect;
     } else if (fwdState->request->flags.accelerated &&
+	!fwdState->request->flags.internalclient &&
 	Config.Accel.single_host && Config.Accel.host) {
 	host = Config.Accel.host;
 	port = Config.Accel.port;
Index: squid/src/ftp.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/ftp.c,v
retrieving revision 1.26
retrieving revision 1.26.2.1
diff -u -r1.26 -r1.26.2.1
--- squid/src/ftp.c	27 Aug 2002 21:46:11 -0000	1.26
+++ squid/src/ftp.c	5 Sep 2002 10:28:20 -0000	1.26.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ftp.c,v 1.26 2002/08/27 21:46:11 squidadm Exp $
+ * $Id: ftp.c,v 1.26.2.1 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 9     File Transfer Protocol (FTP)
  * AUTHOR: Harvest Derived
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
+#include "HttpReply.h"
 
 static const char *const crlf = "\r\n";
 static char cbuf[1024];
@@ -1088,7 +1090,7 @@
 		ftpState->user, request->port);
 	}
 	/* create reply */
-	reply = entry->mem_obj->reply;
+	reply = httpReplyCreate ();
 	assert(reply != NULL);
 	/* create appropriate reply */
 	ftpAuthRequired(reply, request, realm);
@@ -2505,7 +2507,7 @@
     const char *filename = NULL;
     const char *t = NULL;
     StoreEntry *e = ftpState->entry;
-    http_reply *reply = e->mem_obj->reply;
+    http_reply *reply;
     http_version_t version;
 
     if (ftpState->flags.http_header_sent)
@@ -2532,7 +2534,7 @@
 	}
     }
     storeBuffer(e);
-    httpReplyReset(reply);
+    reply = httpReplyCreate();
     /* set standard stuff */
     if (ftpState->restarted_offset) {
 	/* Partial reply */
@@ -2554,7 +2556,9 @@
 	httpHeaderPutStr(&reply->header, HDR_CONTENT_ENCODING, mime_enc);
     httpReplySwapOut(reply, e);
     storeBufferFlush(e);
+#if BROKENCODE
     reply->hdr_sz = e->mem_obj->inmem_hi;
+#endif
     storeTimestampsSet(e);
     if (ftpState->flags.authenticated) {
 	/*
Index: squid/src/gopher.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/gopher.c,v
retrieving revision 1.17.2.1
retrieving revision 1.17.2.2
diff -u -r1.17.2.1 -r1.17.2.2
--- squid/src/gopher.c	3 Sep 2002 08:31:33 -0000	1.17.2.1
+++ squid/src/gopher.c	5 Sep 2002 10:28:20 -0000	1.17.2.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: gopher.c,v 1.17.2.1 2002/09/03 08:31:33 rbcollins Exp $
+ * $Id: gopher.c,v 1.17.2.2 2002/09/05 10:28:20 rbcollins Exp $
  *
  * DEBUG: section 10    Gopher
  * AUTHOR: Harvest Derived
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 /* gopher type code from rfc. Anawat. */
 #define GOPHER_FILE         '0'
Index: squid/src/http.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/http.c,v
retrieving revision 1.21.6.2
retrieving revision 1.21.6.3
diff -u -r1.21.6.2 -r1.21.6.3
--- squid/src/http.c	3 Sep 2002 08:31:34 -0000	1.21.6.2
+++ squid/src/http.c	5 Sep 2002 10:28:21 -0000	1.21.6.3
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.c,v 1.21.6.2 2002/09/03 08:31:34 rbcollins Exp $
+ * $Id: http.c,v 1.21.6.3 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
  * AUTHOR: Harvest Derived
@@ -39,6 +39,8 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
 #include "HttpStrategy.h"
 
 static const char *const crlf = "\r\n";
@@ -217,8 +219,8 @@
 static int
 httpCachableReply(HttpStateData * httpState)
 {
-    HttpReply *rep = httpState->entry->mem_obj->reply;
-    HttpHeader *hdr = &rep->header;
+    HttpReply const *rep = httpState->entry->mem_obj->reply;
+    HttpHeader const *hdr = &rep->header;
     const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
     const char *v;
     if (EBIT_TEST(cc_mask, CC_PRIVATE))
@@ -326,7 +328,7 @@
  * Returns false if the variance cannot be stored
  */
 const char *
-httpMakeVaryMark(request_t * request, HttpReply * reply)
+httpMakeVaryMark(request_t * request, HttpReply const * reply)
 {
     String vary, hdr;
     const char *pos = NULL;
@@ -387,7 +389,9 @@
     StoreEntry *entry = httpState->entry;
     int room;
     size_t hdr_len;
-    HttpReply *reply = entry->mem_obj->reply;
+    /* Creates a blank header. If this routine is made incremental, this will
+     * not do */
+    HttpReply *reply = httpReplyCreate();
     Ctx ctx;
     debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
 	storeKeyText(entry->hash.key));
@@ -404,6 +408,7 @@
 	debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr);
 	httpState->reply_hdr_state += 2;
 	reply->sline.status = HTTP_INVALID_HEADER;
+	storeEntryReplaceObject (entry, reply);
 	return;
     }
     t = httpState->reply_hdr + hdr_len;
@@ -480,6 +485,10 @@
 #if HEADERS_LOG
     headersLog(1, 0, httpState->request->method, reply);
 #endif
+    /* TODO: we need our own reply * in the httpState, as we probably don't want to replace 
+     * the storeEntry with interim headers
+     */
+    storeEntryReplaceObject (entry, reply);
 }
 
 static int
@@ -487,7 +496,7 @@
 {
     /* return 1 if we got the last of the data on a persistent connection */
     MemObject *mem = httpState->entry->mem_obj;
-    HttpReply *reply = mem->reply;
+    HttpReply const *reply = mem->reply;
     int clen;
     debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
     /*
@@ -640,7 +649,8 @@
 		    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
 	    }
 	}
-	storeAppend(entry, buf, len);
+	if (len > entry->mem_obj->reply->hdr_sz)
+	    storeAppend(entry, buf+entry->mem_obj->reply->hdr_sz, len - entry->mem_obj->reply->hdr_sz);
 	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
 	    /*
 	     * the above storeAppend() call could ABORT this entry,
Index: squid/src/icp_v2.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/icp_v2.c,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -r1.6 -r1.6.2.1
--- squid/src/icp_v2.c	9 Aug 2002 21:46:02 -0000	1.6
+++ squid/src/icp_v2.c	5 Sep 2002 10:28:21 -0000	1.6.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: icp_v2.c,v 1.6 2002/08/09 21:46:02 squidadm Exp $
+ * $Id: icp_v2.c,v 1.6.2.1 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 12    Internet Cache Protocol
  * AUTHOR: Duane Wessels
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 static void icpLogIcp(struct in_addr, log_type, int, const char *, int);
 static void icpHandleIcpV2(int, struct sockaddr_in, char *, int);
Index: squid/src/icp_v3.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/icp_v3.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -r1.5 -r1.5.2.1
--- squid/src/icp_v3.c	9 Aug 2002 21:46:02 -0000	1.5
+++ squid/src/icp_v3.c	5 Sep 2002 10:28:21 -0000	1.5.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: icp_v3.c,v 1.5 2002/08/09 21:46:02 squidadm Exp $
+ * $Id: icp_v3.c,v 1.5.2.1 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 12    Internet Cache Protocol
  * AUTHOR: Duane Wessels
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 /* Currently Harvest cached-2.x uses ICP_VERSION_3 */
 void
Index: squid/src/internal.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/internal.c,v
retrieving revision 1.9
retrieving revision 1.9.10.1
diff -u -r1.9 -r1.9.10.1
--- squid/src/internal.c	11 Apr 2002 22:30:30 -0000	1.9
+++ squid/src/internal.c	5 Sep 2002 10:28:21 -0000	1.9.10.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: internal.c,v 1.9 2002/04/11 22:30:30 squidadm Exp $
+ * $Id: internal.c,v 1.9.10.1 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 76    Internal Squid Object handling
  * AUTHOR: Duane, Alex, Henrik
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
+#include "HttpReply.h"
 
 /* called when we "miss" on an internal object;
  * generate known dynamic objects, 
@@ -50,13 +52,15 @@
     if (0 == strcmp(upath, "/squid-internal-dynamic/netdb")) {
 	netdbBinaryExchange(entry);
     } else if (0 == strcmp(upath, "/squid-internal-periodic/store_digest")) {
+	HttpReply *reply;
 #if USE_CACHE_DIGESTS
 	const char *msgbuf = "This cache is currently building its digest.\n";
 #else
 	const char *msgbuf = "This cache does not suport Cache Digests.\n";
 #endif
 	httpBuildVersion(&version, 1, 0);
-	httpReplySetHeaders(entry->mem_obj->reply,
+	reply = httpReplyCreate();
+	httpReplySetHeaders(reply,
 	    version,
 	    HTTP_NOT_FOUND,
 	    "Not Found",
@@ -64,7 +68,7 @@
 	    strlen(msgbuf),
 	    squid_curtime,
 	    -2);
-	httpReplySwapOut(entry->mem_obj->reply, entry);
+	httpReplySwapOut(reply, entry);
 	storeAppend(entry, msgbuf, strlen(msgbuf));
 	storeComplete(entry);
     } else {
Index: squid/src/main.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/main.c,v
retrieving revision 1.36
retrieving revision 1.36.2.1
diff -u -r1.36 -r1.36.2.1
--- squid/src/main.c	8 Aug 2002 19:41:58 -0000	1.36
+++ squid/src/main.c	5 Sep 2002 10:28:21 -0000	1.36.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.c,v 1.36 2002/08/08 19:41:58 squidadm Exp $
+ * $Id: main.c,v 1.36.2.1 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
 
 /* for error reporting from xmalloc and friends */
 extern void (*failure_notify) (const char *);
Index: squid/src/mime.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/mime.c,v
retrieving revision 1.11.38.1
retrieving revision 1.11.38.2
diff -u -r1.11.38.1 -r1.11.38.2
--- squid/src/mime.c	3 Sep 2002 08:31:34 -0000	1.11.38.1
+++ squid/src/mime.c	5 Sep 2002 10:28:21 -0000	1.11.38.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: mime.c,v 1.11.38.1 2002/09/03 08:31:34 rbcollins Exp $
+ * $Id: mime.c,v 1.11.38.2 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 25    MIME Parsing
  * AUTHOR: Harvest Derived
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
 
 #define GET_HDR_SZ 1024
 
@@ -430,7 +432,7 @@
     storeSetPublicKey(e);
     storeBuffer(e);
     e->mem_obj->request = requestLink(urlParse(METHOD_GET, url));
-    httpReplyReset(reply = e->mem_obj->reply);
+    reply = httpReplyCreate();
     httpBuildVersion(&version, 1, 0);
     httpReplySetHeaders(reply, version, HTTP_OK, NULL,
 	type, (int) sb.st_size, sb.st_mtime, -1);
@@ -438,7 +440,6 @@
     httpHdrCcSetMaxAge(reply->cache_control, 86400);
     httpHeaderPutCc(&reply->header, reply->cache_control);
     httpReplySwapOut(reply, e);
-    reply->hdr_sz = e->mem_obj->inmem_hi;	/* yuk */
     /* read the file into the buffer and append it to store */
     buf = memAllocate(MEM_4K_BUF);
     while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
Index: squid/src/neighbors.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/neighbors.c,v
retrieving revision 1.19
retrieving revision 1.19.2.1
diff -u -r1.19 -r1.19.2.1
--- squid/src/neighbors.c	28 Aug 2002 21:45:44 -0000	1.19
+++ squid/src/neighbors.c	5 Sep 2002 10:28:21 -0000	1.19.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: neighbors.c,v 1.19 2002/08/28 21:45:44 squidadm Exp $
+ * $Id: neighbors.c,v 1.19.2.1 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 15    Neighbor Routines
  * AUTHOR: Harvest Derived
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 /* count mcast group peers every 15 minutes */
 #define MCAST_COUNT_RATE 900
Index: squid/src/net_db.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/net_db.c,v
retrieving revision 1.15
retrieving revision 1.15.6.1
diff -u -r1.15 -r1.15.6.1
--- squid/src/net_db.c	26 Jun 2002 17:28:32 -0000	1.15
+++ squid/src/net_db.c	5 Sep 2002 10:28:21 -0000	1.15.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: net_db.c,v 1.15 2002/06/26 17:28:32 squidadm Exp $
+ * $Id: net_db.c,v 1.15.6.1 2002/09/05 10:28:21 rbcollins Exp $
  *
  * DEBUG: section 38    Network Measurement Database
  * AUTHOR: Duane Wessels
@@ -42,6 +42,7 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
 
 #if USE_ICMP
 #define	NETDB_REQBUF_SZ	4096
@@ -986,7 +987,7 @@
 void
 netdbBinaryExchange(StoreEntry * s)
 {
-    http_reply *reply = s->mem_obj->reply;
+    http_reply *reply = httpReplyCreate();
     http_version_t version;
 #if USE_ICMP
     netdbEntry *n;
@@ -996,7 +997,6 @@
     char *buf;
     struct in_addr addr;
     storeBuffer(s);
-    httpReplyReset(reply);
     httpBuildVersion(&version, 1, 0);
     httpReplySetHeaders(reply, version, HTTP_OK, "OK",
 	NULL, -1, squid_curtime, -2);
@@ -1039,10 +1039,10 @@
     storeBufferFlush(s);
     memFree(buf, MEM_4K_BUF);
 #else
-    httpReplyReset(reply);
     httpBuildVersion(&version, 1, 0);
     httpReplySetHeaders(reply, version, HTTP_BAD_REQUEST, "Bad Request",
 	NULL, -1, squid_curtime, -2);
+    httpReplySwapOut(reply, s);
     storeAppendPrintf(s, "NETDB support not compiled into this Squid cache.\n");
 #endif
     storeComplete(s);
Index: squid/src/peer_select.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/peer_select.c,v
retrieving revision 1.15
retrieving revision 1.15.6.1
diff -u -r1.15 -r1.15.6.1
--- squid/src/peer_select.c	23 Jun 2002 14:57:13 -0000	1.15
+++ squid/src/peer_select.c	5 Sep 2002 10:28:22 -0000	1.15.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: peer_select.c,v 1.15 2002/06/23 14:57:13 squidadm Exp $
+ * $Id: peer_select.c,v 1.15.6.1 2002/09/05 10:28:22 rbcollins Exp $
  *
  * DEBUG: section 44    Peer Selection Algorithm
  * AUTHOR: Duane Wessels
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 const char *hier_strings[] =
 {
Index: squid/src/protos.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/protos.h,v
retrieving revision 1.59
retrieving revision 1.59.6.1
diff -u -r1.59 -r1.59.6.1
--- squid/src/protos.h	20 Jul 2002 12:33:16 -0000	1.59
+++ squid/src/protos.h	5 Sep 2002 10:28:22 -0000	1.59.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.59 2002/07/20 12:33:16 squidadm Exp $
+ * $Id: protos.h,v 1.59.6.1 2002/09/05 10:28:22 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -125,6 +125,8 @@
 extern int cbdataReferenceValid(const void *p);
 extern cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
 
+/* client_side.c - FD related client side routines */
+
 extern void clientdbInit(void);
 extern void clientdbUpdate(struct in_addr, log_type, protocol_t, size_t);
 extern int clientdbCutoffDenied(struct in_addr);
@@ -134,10 +136,8 @@
 
 extern void clientAccessCheck(void *);
 extern void clientAccessCheckDone(int, void *);
-extern int modifiedSince(StoreEntry *, request_t *);
 extern char *clientConstructTraceEcho(clientHttpRequest *);
 extern void clientPurgeRequest(clientHttpRequest *);
-extern int checkNegativeHit(StoreEntry *);
 extern void clientOpenListenSockets(void);
 extern void clientHttpConnectionsClose(void);
 extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags);
@@ -145,6 +145,19 @@
 extern void clientReadBody(request_t * req, char *buf, size_t size, CBCB * callback, void *data);
 extern int clientAbortBody(request_t * req);
 
+/* client_side_request.c - client side request related routines (pure logic) */
+extern int clientDetermineActionAfterWrite(int fd, clientHttpRequest const *http, StoreEntry *entry, size_t size);
+extern STCB clientSendMoreData;
+extern ErrorState *clientBuildError (err_type, http_status, char const *, struct in_addr *, request_t *);
+extern int clientBeginRequest (method_t, char const *, CSR *, void *, HttpHeader const *);
+
+/* client_side_reply.c - client side reply related routines (pure logic, no comms) */
+extern int clientCheckTransferDone(clientHttpRequest const *);
+
+/* clientStream.c */
+extern void clientStreamInsertHead (clientStreamNode **, CSR *, void *);
+extern clientStreamNode *clientStreamNew (CSR *, void *);
+
 extern int commSetNonBlocking(int fd);
 extern int commUnsetNonBlocking(int fd);
 extern void commSetCloseOnExec(int fd);
@@ -313,7 +326,7 @@
 extern int httpAnonHdrDenied(http_hdr_type hdr_id);
 extern void httpBuildRequestHeader(request_t *, request_t *, StoreEntry *, HttpHeader *, int, http_state_flags);
 extern void httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor);
-extern const char *httpMakeVaryMark(request_t * request, HttpReply * reply);
+extern const char *httpMakeVaryMark(request_t * request, HttpReply const * reply);
 
 /* ETag */
 extern int etagParseInit(ETag * etag, const char *str);
@@ -472,54 +485,6 @@
 extern int httpMsgIsPersistent(http_version_t http_ver, const HttpHeader * hdr);
 extern int httpMsgIsolateHeaders(const char **parse_start, const char **blk_start, const char **blk_end);
 
-/* Http Reply */
-extern void httpReplyInitModule(void);
-/* create/destroy */
-extern HttpReply *httpReplyCreate(void);
-extern void httpReplyDestroy(HttpReply * rep);
-/* reset: clean, then init */
-extern void httpReplyReset(HttpReply * rep);
-/* absorb: copy the contents of a new reply to the old one, destroy new one */
-extern void httpReplyAbsorb(HttpReply * rep, HttpReply * new_rep);
-/* parse returns -1,0,+1 on error,need-more-data,success */
-extern int httpReplyParse(HttpReply * rep, const char *buf, ssize_t);
-extern void httpReplyPackInto(const HttpReply * rep, Packer * p);
-/* ez-routines */
-/* mem-pack: returns a ready to use mem buffer with a packed reply */
-extern MemBuf httpReplyPack(const HttpReply * rep);
-/* swap: create swap-based packer, pack, destroy packer */
-extern void httpReplySwapOut(const HttpReply * rep, StoreEntry * e);
-/* set commonly used info with one call */
-extern void httpReplySetHeaders(HttpReply * rep, http_version_t ver, http_status status,
-    const char *reason, const char *ctype, int clen, time_t lmt, time_t expires);
-/* do everything in one call: init, set, pack, clean, return MemBuf */
-extern MemBuf httpPackedReply(http_version_t ver, http_status status, const char *ctype,
-    int clen, time_t lmt, time_t expires);
-/* construct 304 reply and pack it into MemBuf, return MemBuf */
-extern MemBuf httpPacked304Reply(const HttpReply * rep);
-/* update when 304 reply is received for a cached object */
-extern void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep);
-/* header manipulation */
-extern int httpReplyContentLen(const HttpReply * rep);
-extern const char *httpReplyContentType(const HttpReply * rep);
-extern time_t httpReplyExpires(const HttpReply * rep);
-extern int httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type);
-extern void httpRedirectReply(HttpReply *, http_status, const char *);
-extern int httpReplyBodySize(method_t, HttpReply *);
-extern void httpReplyBodyBuildSize(request_t *, HttpReply *, dlink_list *);
-
-/* Http Request */
-extern request_t *requestCreate(method_t, protocol_t, const char *urlpath);
-extern void requestDestroy(request_t *);
-extern request_t *requestLink(request_t *);
-extern void requestUnlink(request_t *);
-extern int httpRequestParseHeader(request_t * req, const char *parse_start);
-extern void httpRequestSwapOut(const request_t * req, StoreEntry * e);
-extern void httpRequestPack(const request_t * req, Packer * p);
-extern int httpRequestPrefixLen(const request_t * req);
-extern int httpRequestHdrAllowed(const HttpHeaderEntry * e, String * strConnection);
-extern int httpRequestHdrAllowedByName(http_hdr_type id);
-
 extern void icmpOpen(void);
 extern void icmpClose(void);
 extern void icmpPing(struct in_addr to);
@@ -808,12 +773,10 @@
 extern void pconnHistCount(int, int);
 extern int stat5minClientRequests(void);
 extern double stat5minCPUUsage(void);
-extern const char *storeEntryFlags(const StoreEntry *);
 extern double statRequestHitRatio(int minutes);
 extern double statRequestHitMemoryRatio(int minutes);
 extern double statRequestHitDiskRatio(int minutes);
 extern double statByteHitRatio(int minutes);
-extern int storeEntryLocked(const StoreEntry *);
 
 
 /* StatHist */
@@ -899,6 +862,7 @@
 extern void storeExpireNow(StoreEntry *);
 extern void storeReleaseRequest(StoreEntry *);
 extern void storeConfigure(void);
+extern int storeCheckNegativeHit(StoreEntry *);
 extern void storeNegativeCache(StoreEntry *);
 extern void storeFreeMemory(void);
 extern int expiresMoreThan(time_t, time_t);
@@ -926,11 +890,14 @@
 extern void storeSetPrivateKey(StoreEntry *);
 extern int objectLen(const StoreEntry * e);
 extern int contentLen(const StoreEntry * e);
-extern HttpReply *storeEntryReply(StoreEntry *);
+extern HttpReply const *storeEntryReply(StoreEntry *);
 extern int storeTooManyDiskFilesOpen(void);
 extern void storeEntryReset(StoreEntry *);
 extern void storeHeapPositionUpdate(StoreEntry *, SwapDir *);
 extern void storeSwapFileNumberSet(StoreEntry * e, sfileno filn);
+extern int storeEntryLocked(const StoreEntry *);
+extern const char *storeEntryFlags(const StoreEntry *);
+extern void storeEntryReplaceObject(StoreEntry *, HttpReply *);
 extern void storeFsInit(void);
 extern void storeFsDone(void);
 extern void storeFsAdd(const char *, STSETUP *);
Index: squid/src/ssl.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/ssl.c,v
retrieving revision 1.15
retrieving revision 1.15.6.1
diff -u -r1.15 -r1.15.6.1
--- squid/src/ssl.c	20 Jul 2002 12:33:16 -0000	1.15
+++ squid/src/ssl.c	5 Sep 2002 10:28:22 -0000	1.15.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ssl.c,v 1.15 2002/07/20 12:33:16 squidadm Exp $
+ * $Id: ssl.c,v 1.15.6.1 2002/09/05 10:28:22 rbcollins Exp $
  *
  * DEBUG: section 26    Secure Sockets Layer Proxy
  * AUTHOR: Duane Wessels
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 typedef struct {
     char *url;
Index: squid/src/store.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store.c,v
retrieving revision 1.17
retrieving revision 1.17.2.1
diff -u -r1.17 -r1.17.2.1
--- squid/src/store.c	15 Aug 2002 18:14:04 -0000	1.17
+++ squid/src/store.c	5 Sep 2002 10:28:22 -0000	1.17.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store.c,v 1.17 2002/08/15 18:14:04 squidadm Exp $
+ * $Id: store.c,v 1.17.2.1 2002/09/05 10:28:22 rbcollins Exp $
  *
  * DEBUG: section 20    Storage Manager
  * AUTHOR: Harvest Derived
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
 
 #define REBUILD_TIMESTAMP_DELTA_MAX 2
 
@@ -160,7 +162,7 @@
      * still have mem->clients set if mem->fd == -1
      */
     assert(mem->fd == -1 || mem->clients.head == NULL);
-    httpReplyDestroy(mem->reply);
+    httpReplyDestroy((HttpReply *)mem->reply);
     requestUnlink(mem->request);
     mem->request = NULL;
     ctx_exit(ctx);		/* must exit before we free mem->url */
@@ -428,10 +430,12 @@
 	    String vary;
 	    pe = storeCreateEntry(mem->url, mem->log_url, request->flags, request->method);
 	    httpBuildVersion(&version, 1, 0);
-	    httpReplySetHeaders(pe->mem_obj->reply, version, HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
+	    /* We are allowed to do this typecast */
+	    httpReplySetHeaders((HttpReply *)pe->mem_obj->reply, version, HTTP_OK, "Internal marker object", "x-squid-internal/vary", -1, -1, squid_curtime + 100000);
 	    vary = httpHeaderGetList(&mem->reply->header, HDR_VARY);
 	    if (strBuf(vary)) {
-		httpHeaderPutStr(&pe->mem_obj->reply->header, HDR_VARY, strBuf(vary));
+		/* Again, we own this structure layout */
+		httpHeaderPutStr((HttpHeader *)&pe->mem_obj->reply->header, HDR_VARY, strBuf(vary));
 		stringClean(&vary);
 	    }
 #if X_ACCELERATOR_VARY
@@ -442,7 +446,13 @@
 	    }
 #endif
 	    storeSetPublicKey(pe);
-	    httpReplySwapOut(pe->mem_obj->reply, pe);
+	    /* TODO: remove this when the metadata is separated */
+	      {
+		Packer p;
+		packerToStoreInit(&p, pe);
+		httpReplyPackHeadersInto(pe->mem_obj->reply, &p);
+		packerClean(&p);
+	      }
 	    storeBufferFlush(pe);
 	    storeTimestampsSet(pe);
 	    storeComplete(pe);
@@ -1039,6 +1049,18 @@
     return mem->inmem_lo == 0;
 }
 
+int
+storeCheckNegativeHit(StoreEntry * e)
+{
+    if (!EBIT_TEST(e->flags, ENTRY_NEGCACHED))
+        return 0;
+    if (e->expires <= squid_curtime)
+        return 0;
+    if (e->store_status != STORE_OK)
+        return 0;
+    return 1;
+}
+
 void
 storeNegativeCache(StoreEntry * e)
 {
@@ -1263,7 +1285,7 @@
     return e->mem_obj->object_sz - e->mem_obj->reply->hdr_sz;
 }
 
-HttpReply *
+HttpReply const *
 storeEntryReply(StoreEntry * e)
 {
     if (NULL == e)
@@ -1281,11 +1303,40 @@
     assert(mem->swapout.sio == NULL);
     stmemFree(&mem->data_hdr);
     mem->inmem_hi = mem->inmem_lo = 0;
-    httpReplyDestroy(mem->reply);
-    mem->reply = httpReplyCreate();
+    /* SHould we check for clients? */
+    httpReplyReset((HttpReply *)mem->reply);
     e->expires = e->lastmod = e->timestamp = -1;
 }
 
+/* Replace a store entry with 
+ * a new reply. This eats the reply.
+ */
+void
+storeEntryReplaceObject(StoreEntry * e, HttpReply * rep)
+{
+    MemObject *mem = e->mem_obj;
+    HttpReply *myrep;
+    Packer p;
+    debug(20, 3) ("storeEntryReplaceObject: %s\n", storeUrl(e));
+    if (!mem) {
+	debug (20,0)("Attempt to replace object with no in-memory representation\n");
+	return;
+    }
+    /* TODO: check that there is at most 1 store client ? */
+    myrep = (HttpReply *)mem->reply; /* we are allowed to do this */
+    /* move info to the mem_obj->reply */
+    httpReplyAbsorb(myrep, rep);
+
+    /* TODO: when we store headers serparately remove the header portion */
+    /* TODO: mark the length of the headers ? */
+    /* We ONLY want the headers */
+    packerToStoreInit(&p, e);
+    httpReplyPackHeadersInto(mem->reply, &p);
+    myrep->hdr_sz = e->mem_obj->inmem_hi;  /* yuk */
+    httpBodyPackInto(&mem->reply->body, &p);
+    packerClean(&p);
+}
+
 /*
  * storeFsInit
  *
Index: squid/src/store_client.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_client.c,v
retrieving revision 1.13
retrieving revision 1.13.8.1
diff -u -r1.13 -r1.13.8.1
--- squid/src/store_client.c	21 Apr 2002 21:56:26 -0000	1.13
+++ squid/src/store_client.c	5 Sep 2002 10:28:22 -0000	1.13.8.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_client.c,v 1.13 2002/04/21 21:56:26 squidadm Exp $
+ * $Id: store_client.c,v 1.13.8.1 2002/09/05 10:28:22 rbcollins Exp $
  *
  * DEBUG: section 20    Storage Manager Client-Side Interface
  * AUTHOR: Duane Wessels
@@ -34,9 +34,13 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
 
 /*
  * NOTE: 'Header' refers to the swapfile metadata header.
+ *       'OBJHeader' refers to the object header, with cannonical
+ *       processed object headers (which may derive from FTP/HTTP etc
+ *       upstream protocols/
  *       'Body' refers to the swapfile body, which is the full
  *        HTTP reply (including HTTP headers and body).
  */
@@ -369,7 +373,10 @@
     assert(sc->callback != NULL);
     debug(20, 3) ("storeClientReadBody: len %d\n", (int) len);
     if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
-	httpReplyParse(mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, len));
+	/* Our structure ! */
+	if (!httpReplyParse((HttpReply *)mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, len))) {
+	    debug (20,0)("Could not parse headers from on disk object\n");
+	}
     storeClientCallback(sc, len);
 }
 
@@ -474,8 +481,11 @@
 	    (int) copy_sz);
 	xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz);
 	if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
-	    httpReplyParse(mem->reply, sc->copy_buf,
-		headersEnd(sc->copy_buf, copy_sz));
+	    /* Our structure ! */
+	    if (!httpReplyParse((HttpReply *)mem->reply, sc->copy_buf,
+		headersEnd(sc->copy_buf, copy_sz))) {
+		debug (20,0)("could not parse headers from on disk structure!\n");
+	    }
 	storeClientCallback(sc, copy_sz);
 	return;
     }
Index: squid/src/store_log.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/store_log.c,v
retrieving revision 1.7
retrieving revision 1.7.38.1
diff -u -r1.7 -r1.7.38.1
--- squid/src/store_log.c	18 Oct 2001 20:52:11 -0000	1.7
+++ squid/src/store_log.c	5 Sep 2002 10:28:22 -0000	1.7.38.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: store_log.c,v 1.7 2001/10/18 20:52:11 squidadm Exp $
+ * $Id: store_log.c,v 1.7.38.1 2002/09/05 10:28:22 rbcollins Exp $
  *
  * DEBUG: section 20    Storage Manager Logging Functions
  * AUTHOR: Duane Wessels
@@ -50,7 +50,7 @@
 storeLog(int tag, const StoreEntry * e)
 {
     MemObject *mem = e->mem_obj;
-    HttpReply *reply;
+    HttpReply const *reply;
     if (NULL == storelog)
 	return;
 #if UNUSED_CODE
Index: squid/src/structs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/structs.h,v
retrieving revision 1.64.2.2
retrieving revision 1.64.2.3
diff -u -r1.64.2.2 -r1.64.2.3
--- squid/src/structs.h	3 Sep 2002 08:31:35 -0000	1.64.2.2
+++ squid/src/structs.h	5 Sep 2002 10:28:23 -0000	1.64.2.3
@@ -1,6 +1,6 @@
 
 /*
- * $Id: structs.h,v 1.64.2.2 2002/09/03 08:31:35 rbcollins Exp $
+ * $Id: structs.h,v 1.64.2.3 2002/09/05 10:28:23 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -1048,6 +1048,12 @@
     HierarchyLogEntry hier;
 };
 
+struct _clientStreamNode {
+    CSR *func;
+    void *data;
+    clientStreamNode *next;
+};
+
 struct _clientHttpRequest {
     ConnStateData *conn;
     request_t *request;		/* Parsed URL ... */
@@ -1091,6 +1097,7 @@
     char *reqbuf;
     int reqofs;
     int reqsize;
+    clientStreamNode *stream_head;
 };
 
 struct _ConnStateData {
@@ -1507,7 +1514,8 @@
 	mem_node *memnode;	/* which node we're currently paging out */
 	storeIOState *sio;
     } swapout;
-    HttpReply *reply;
+    /* Read only - this reply must be preserved by store clients */
+    HttpReply const *reply; /* The original reply. possibly with updated metadata. */
     request_t *request;
     struct timeval start_ping;
     IRCB *ping_reply_callback;
@@ -1623,6 +1631,7 @@
 #endif
     unsigned int accelerated:1;
     unsigned int internal:1;
+    unsigned int internalclient:1;
     unsigned int body_sent:1;
     unsigned int reset_tcp:1;
 };
Index: squid/src/typedefs.h
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v
retrieving revision 1.27
retrieving revision 1.27.6.1
diff -u -r1.27 -r1.27.6.1
--- squid/src/typedefs.h	23 Jun 2002 13:38:04 -0000	1.27
+++ squid/src/typedefs.h	5 Sep 2002 10:28:23 -0000	1.27.6.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: typedefs.h,v 1.27 2002/06/23 13:38:04 squidadm Exp $
+ * $Id: typedefs.h,v 1.27.6.1 2002/09/05 10:28:23 rbcollins Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -31,6 +31,8 @@
  *
  */
 
+#include "squid.h"
+
 #ifndef SQUID_TYPEDEFS_H
 #define SQUID_TYPEDEFS_H
 
@@ -106,6 +108,7 @@
 typedef struct _HttpReply HttpReply;
 typedef struct _HttpStateData HttpStateData;
 typedef struct _icpUdpData icpUdpData;
+typedef struct _clientStreamNode clientStreamNode;
 typedef struct _clientHttpRequest clientHttpRequest;
 typedef struct _ConnStateData ConnStateData;
 typedef struct _ConnCloseHelperData ConnCloseHelperData;
@@ -197,6 +200,10 @@
 typedef struct _delaySpec delaySpec;
 #endif
 
+/* client_side.c callbacks and callforwards */
+/* client stream recipient */
+typedef void CSR (clientStreamNode *, clientHttpRequest *, HttpReply *, const char *, ssize_t);
+
 typedef void CWCB(int fd, char *, size_t size, int flag, void *data);
 typedef void CNCB(int fd, int status, void *);
 
Index: squid/src/url.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/url.c,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -r1.10 -r1.10.2.1
--- squid/src/url.c	24 Aug 2002 02:06:24 -0000	1.10
+++ squid/src/url.c	5 Sep 2002 10:28:23 -0000	1.10.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: url.c,v 1.10 2002/08/24 02:06:24 squidadm Exp $
+ * $Id: url.c,v 1.10.2.1 2002/09/05 10:28:23 rbcollins Exp $
  *
  * DEBUG: section 23    URL Parsing
  * AUTHOR: Duane Wessels
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 const char *RequestMethodStr[] =
 {
Index: squid/src/urn.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/urn.c,v
retrieving revision 1.16.2.1
retrieving revision 1.16.2.2
diff -u -r1.16.2.1 -r1.16.2.2
--- squid/src/urn.c	3 Sep 2002 08:31:35 -0000	1.16.2.1
+++ squid/src/urn.c	5 Sep 2002 10:28:24 -0000	1.16.2.2
@@ -1,6 +1,6 @@
 
 /*
- * $Id: urn.c,v 1.16.2.1 2002/09/03 08:31:35 rbcollins Exp $
+ * $Id: urn.c,v 1.16.2.2 2002/09/05 10:28:24 rbcollins Exp $
  *
  * DEBUG: section 52    URN Parsing
  * AUTHOR: Kostas Anagnostakis
@@ -34,6 +34,8 @@
  */
 
 #include "squid.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
 
 #define	URN_REQBUF_SZ	4096
 
@@ -174,6 +176,7 @@
 	return u1->rtt - u2->rtt;
 }
 
+/* TODO: use the clientStream support for this */
 static void
 urnHandleReply(void *data, char *unused_buf, ssize_t size)
 {
@@ -229,17 +232,20 @@
     }
     s = buf + k;
     assert(urlres_e->mem_obj->reply);
-    httpReplyParse(urlres_e->mem_obj->reply, buf, k);
-    debug(52, 3) ("mem->reply exists, code=%d.\n",
-	urlres_e->mem_obj->reply->sline.status);
-    if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
+    rep = httpReplyCreate ();
+    httpReplyParse(rep, buf, k);
+    debug(52, 3) ("reply exists, code=%d.\n",
+	rep->sline.status);
+    if (rep->sline.status != HTTP_OK) {
 	debug(52, 3) ("urnHandleReply: failed.\n");
 	err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
 	err->request = requestLink(urnState->request);
 	err->url = xstrdup(storeUrl(e));
 	errorAppendEntry(e, err);
+	httpReplyDestroy(rep);
 	goto error;
     }
+    httpReplyDestroy(rep);
     while (xisspace(*s))
 	s++;
     urls = urnParseReply(s, urnState->request->method);
@@ -283,8 +289,7 @@
 	"Generated by %s@%s\n"
 	"</ADDRESS>\n",
 	full_appname_string, getMyHostname());
-    rep = e->mem_obj->reply;
-    httpReplyReset(rep);
+    rep = httpReplyCreate();
     httpBuildVersion(&version, 1, 0);
     httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL,
 	"text/html", mb.size, 0, squid_curtime);
Index: squid/src/wais.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/wais.c,v
retrieving revision 1.8
retrieving revision 1.8.38.1
diff -u -r1.8 -r1.8.38.1
--- squid/src/wais.c	24 Oct 2001 09:42:14 -0000	1.8
+++ squid/src/wais.c	5 Sep 2002 10:28:24 -0000	1.8.38.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: wais.c,v 1.8 2001/10/24 09:42:14 squidadm Exp $
+ * $Id: wais.c,v 1.8.38.1 2002/09/05 10:28:24 rbcollins Exp $
  *
  * DEBUG: section 24    WAIS Relay
  * AUTHOR: Harvest Derived
@@ -34,6 +34,7 @@
  */
 
 #include "squid.h"
+#include "HttpRequest.h"
 
 typedef struct {
     int fd;
Index: squid/src/whois.c
===================================================================
RCS file: /cvsroot/squid-sf//squid/src/whois.c,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -u -r1.9 -r1.9.2.1
--- squid/src/whois.c	22 Aug 2002 12:30:09 -0000	1.9
+++ squid/src/whois.c	5 Sep 2002 10:28:24 -0000	1.9.2.1
@@ -1,6 +1,6 @@
 
 /*
- * $Id: whois.c,v 1.9 2002/08/22 12:30:09 squidadm Exp $
+ * $Id: whois.c,v 1.9.2.1 2002/09/05 10:28:24 rbcollins Exp $
  *
  * DEBUG: section 75    WHOIS protocol
  * AUTHOR: Duane Wessels, Kostas Anagnostakis
@@ -97,8 +97,12 @@
     debug(75, 3) ("whoisReadReply: FD %d read %d bytes\n", fd, len);
     debug(75, 5) ("{%s}\n", buf);
     if (len > 0) {
-	if (0 == mem->inmem_hi)
-	    mem->reply->sline.status = HTTP_OK;
+	if (0 == mem->inmem_hi) {
+	    assert (0);
+	    /* I haven't coded for this yet. Lets see where it occurs */
+	    /* TODO: FIXME */
+	    /* ->reply->sline.status = HTTP_OK; */
+	}
 	fd_bytes(fd, len, FD_READ);
 	kb_incr(&statCounter.server.all.kbytes_in, len);
 	kb_incr(&statCounter.server.http.kbytes_in, len);
