--------------------- 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 : ""); - debug(33, 5) ("Proxy Auth Message = %s\n", - proxy_auth_msg ? proxy_auth_msg : ""); - /* - * NOTE: get page_id here, based on AclMatchedName because - * if USE_DELAY_POOLS is enabled, then AclMatchedName gets - * clobbered in the clientCreateStoreEntry() call - * just below. Pedro Ribeiro - */ - page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName); - http->log_type = LOG_TCP_DENIED; - http->entry = clientCreateStoreEntry(http, http->request->method, - null_request_flags); - if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) { - if (!http->flags.accel) { - /* Proxy authorisation needed */ - status = HTTP_PROXY_AUTHENTICATION_REQUIRED; - } else { - /* WWW authorisation needed */ - status = HTTP_UNAUTHORIZED; - } - if (page_id == ERR_NONE) - page_id = ERR_CACHE_ACCESS_DENIED; - } else { - status = HTTP_FORBIDDEN; - if (page_id == ERR_NONE) - page_id = ERR_ACCESS_DENIED; - } - err = errorCon(page_id, status); - err->request = requestLink(http->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" "\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);