--------------------- PatchSet 2174 Date: 2001/05/01 09:02:51 Author: rbcollins Branch: newhttp Tag: (none) Log: broker basics in place, trace source established, chunking working Members: src/HttpRequest.c:1.1.1.3.8.2.4.2->1.1.1.3.8.2.4.2.2.1 src/broker.c:1.1.2.1->1.1.2.2 src/client_side.c:1.1.1.3.4.1.4.15.2.34.2.2->1.1.1.3.4.1.4.15.2.34.2.3 src/filters.c:1.1.2.13.2.1->1.1.2.13.2.2 src/protos.h:1.1.1.3.8.11.2.20.2.1->1.1.1.3.8.11.2.20.2.2 Index: squid/src/HttpRequest.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/HttpRequest.c,v retrieving revision 1.1.1.3.8.2.4.2 retrieving revision 1.1.1.3.8.2.4.2.2.1 diff -u -r1.1.1.3.8.2.4.2 -r1.1.1.3.8.2.4.2.2.1 --- squid/src/HttpRequest.c 27 Apr 2001 14:38:37 -0000 1.1.1.3.8.2.4.2 +++ squid/src/HttpRequest.c 1 May 2001 09:02:51 -0000 1.1.1.3.8.2.4.2.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpRequest.c,v 1.1.1.3.8.2.4.2 2001/04/27 14:38:37 rbcollins Exp $ + * $Id: HttpRequest.c,v 1.1.1.3.8.2.4.2.2.1 2001/05/01 09:02:51 rbcollins Exp $ * * DEBUG: section 73 HTTP Request * AUTHOR: Duane Wessels @@ -109,6 +109,21 @@ packerClean(&p); } +/* creates membuf using httpRequestPack */ +MemBuf +HttpRequestPackMemBuf(const request_t * req) +{ + MemBuf mb; + Packer p; + assert(req); + + memBufDefInit(&mb); + packerToMemInit(&p, &mb); + httpRequestPack(req, &p); + packerClean(&p); + return mb; +} + /* packs request-line and headers, appends terminator */ void httpRequestPack(const request_t * req, Packer * p) Index: squid/src/broker.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/broker.c,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- squid/src/broker.c 1 May 2001 00:59:02 -0000 1.1.2.1 +++ squid/src/broker.c 1 May 2001 09:02:51 -0000 1.1.2.2 @@ -1,6 +1,6 @@ /* - * $Id: broker.c,v 1.1.2.1 2001/05/01 00:59:02 rbcollins Exp $ + * $Id: broker.c,v 1.1.2.2 2001/05/01 09:02:51 rbcollins Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Robert Collins @@ -50,8 +50,25 @@ clientHttpRequest needs to be expanded to a brokerRequest. +broker client->server flow +1. check for cacheability +2. check for a server protocol handler that matches. (combine protocol:method) + */ +typedef struct _protocolmodule protocolmodule; + +struct _protocolmodule { + protocolmodule *next; + char * namestr; + /* called when the headers start flowing in response to the request */ + DATAFILTER_HDR *clientstart; +}; + +CBDATA_TYPE (protocolmodule); +static protocolmodule *protocol_list = NULL; + + typedef struct _brokerstate { HttpReply *rep; clientHttpRequest *request; @@ -62,8 +79,110 @@ } brokerstate; CBDATA_TYPE(brokerstate); +void brokerModuleUnlink(void *data); + +/* module support code: register servers and clients */ +/* filter framework */ +void +brokerRegisterModule(const char *namestr, DATAFILTER_HDR *clientstart) +{ + protocolmodule *new; + CBDATA_INIT_TYPE_FREECB(protocolmodule, brokerModuleUnlink); + + debug(83, 4) ("brokerRegisterModule: Registering protocol '%s'\n", namestr); + /* find the current count */ + new=protocol_list; + while (new) { + /* + * don't allow double additions. FIXME: this should be a debug and + * abort action, to allow for dynamic registration mistakes + */ + assert(strcmp(new->namestr, namestr) != 0); + new=new->next; + } + /* add the filter (to the head) */ + new=cbdataAlloc(protocolmodule); + memset(new, 0, sizeof(protocolmodule)); + new->next=protocol_list; + protocol_list=new; + new->namestr=xstrdup(namestr); + new->clientstart=clientstart; +} + +/* + * deregister a module - remove all config details + * + * XXX: we cannot unload the code from memory without turning this + * into a callback scenario because filters may be in use for arbitrary + * periods of time - until the current requests finish + */ +void +brokerDeregisterModule(const char *namestr) +{ + protocolmodule *protocol,*temp; + + debug(83, 4) ("brokerDeregisterModule: Deregistering protocol '%s'\n", + namestr); + protocol = protocol_list; + temp = protocol_list; + while (protocol) { + temp = protocol; + protocol = protocol->next; + if (strcmp(temp->namestr, namestr) == 0) { + if (temp == protocol_list) + protocol_list = protocol; + cbdataFree(temp); + protocol=NULL; + } + } +} + +void +brokerModuleUnlink(void *data) +{ + protocolmodule *protocol, *self=data; + + protocol=protocol_list; + assert(data); + debug(83, 4) ("protocolModuleUnlink: unlinking '%s'\n", self->namestr); + /* special case: removing head */ + if (protocol == self) { + protocol_list = self->next; + protocol = NULL; + } + while (protocol && (protocol->next != self)) + protocol = protocol->next; + if (protocol && (protocol->next == self)) + protocol->next = self->next; + safe_free(self->namestr); + /* cbdata does the actual Mempoolfree */ +} + +protocolmodule * +protocolByName(const char *namestr) +{ + protocolmodule *protocol=protocol_list; + + while (protocol) { + /* + * The strlen is semi-bogus (it doesn't prevent you from + * protocol->namestr from being "too" long..) + * + * The correct abuse here would be to make protocol->namestr a fixed + * char array and have something like MAXFILTERNAMELEN.. + * -- adrian + */ + if (strncasecmp(namestr, protocol->namestr, + strlen(protocol->namestr)) == 0) + return protocol; + protocol=protocol->next; + } + return NULL; +} +static void broker_clientProcessRequest(brokerstate *BrokerState); + static aclCheck_t * brokerClientChecklistCreate(const acl_access * acl, const clientHttpRequest * http) { @@ -90,15 +209,124 @@ brokerCheckNoCacheDone(int answer, void *data) { brokerstate *BrokerState = data; - FILTER_list *temp_filter = BrokerState->filters->node.next->data; - unsigned int rvflags; +// FILTER_list *temp_filter = BrokerState->filters->node.next->data; +// unsigned int rvflags; clientHttpRequest *http = BrokerState->data; http->request->flags.cachable = answer; http->acl_checklist = NULL; - rvflags = temp_filter->filter_hdr(BrokerState->rep, BrokerState->request, BrokerState->filter_list, temp_filter, BrokerState->flags, temp_filter->data); +// rvflags = temp_filter->filter_hdr(BrokerState->rep, BrokerState->request, BrokerState->filter_list, temp_filter, BrokerState->flags, temp_filter->data); /* FIXME: maybe we rmeove here, maybe not :] */ +// cbdataUnlock(BrokerState); + broker_clientProcessRequest(BrokerState); +} + +/* data for this is the http struct. It doesn't need to be though */ + +DATAFILTER_FILTERHEADER(http_trace_hdr) +{ + FILTER_list *temp_filter=filters->node.next->data; + unsigned int rvflags; + http_version_t version; + clientHttpRequest *http=data; + /* we are a source. confirm it the hard way */ + assert(filter_list->head->data==filters); + rep = httpReplyCreate(); + httpBuildVersion(&version, 1, 0); + /* the below _may_ be wrong: prefix length but we use the parsed headers */ + httpReplySetHeaders(rep, version, HTTP_OK, NULL, "text/plain", + httpRequestPrefixLen(request->request), 0, squid_curtime); + rvflags = temp_filter->filter_hdr(rep,request,filter_list,temp_filter, flags, temp_filter->data); + debug (3,3)("http_trace_hdr got rvflags of %0x\n",rvflags); + return rvflags; +} + +DATAFILTER_FILTER(http_trace_body) +{ + FILTER_list *temp_filter=filters->node.next->data; + unsigned int rvflags; + clientHttpRequest *http=data; + request_t *request=http->request; + MemBuf mb; + /* we are a source. confirm it the hard way */ + assert(filter_list->head->data==filters); + /* now send the body component */ + mb = HttpRequestPackMemBuf(request); + rvflags = temp_filter->filter(mb.buf, mb.size, 0 ,filter_list,temp_filter, flags | FILTER_EOF, temp_filter->data); + return rvflags | FILTER_EOF; +} + + +static void +broker_clientProcessRequest(brokerstate *BrokerState) +{ + FILTER_list *temp_filter = NULL; +// = BrokerState->filters->node.next->data; + unsigned int rvflags; + clientHttpRequest *http = BrokerState->data; + char *url = http->uri; + request_t *r = http->request; + int fd = http->conn->fd; + HttpReply *rep; + http_version_t version; + +// /* we must be the last filter at this point */ +// assert(temp_filter==NULL); + debug(33, 4) ("clientProcessRequest: %s '%s'\n", + RequestMethodStr[r->method], url); + if (r->method == METHOD_CONNECT) { + http->log_type = LOG_TCP_MISS; + sslStart(fd, url, r, &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) { + /* set the source and start the flow */ + filterChainAdd(&http->repfilters, http_trace_body,http_trace_hdr,NULL,http); + temp_filter=http->repfilters.head->data; + rvflags=temp_filter->filter_hdr(NULL, http, &http->repfilters, temp_filter,0, temp_filter->data); + + debug (33,3)("Process request got flags %0x from rep_header\n", rvflags); + if (!(rvflags & (FILTER_ABORT | FILTER_EOF))) { + rvflags=temp_filter->filter(NULL,0,0,&http->repfilters, temp_filter, + 0,temp_filter->data); + debug (33,3)("Process request got flags %0x from rep_filter\n", rvflags); + } + + cbdataUnlock(BrokerState); + 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) { + /* not a miss, or attaching to a in process entry */ + storeLockObject(http->entry); + 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(r)); +#endif +/* storeClientCopy(http->sc, http->entry, + http->out.offset, + http->out.offset, + CLIENT_SOCK_SZ, + memAllocate(MEM_CLIENT_SOCK_BUF), + clientCacheHit, + http); +*/ } else { + /* MISS CASE, http->log_type is already set! */ + // clientProcessMiss(http); + } cbdataUnlock(BrokerState); -// clientProcessRequest(http); } unsigned int broker_ClientEntry_hdr (HttpReply *rep, clientHttpRequest *request, dlink_list * filter_list,FILTER_list * filters, unsigned int flags, void *data) @@ -113,6 +341,7 @@ BrokerState->flags=flags; BrokerState->data=data; cbdataLock(BrokerState); + if (Config.accessList.noCache && request->request->flags.cachable) { request->acl_checklist = brokerClientChecklistCreate(Config.accessList.noCache, request); aclNBCheck(request->acl_checklist, brokerCheckNoCacheDone, BrokerState); Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.1.1.3.4.1.4.15.2.34.2.2 retrieving revision 1.1.1.3.4.1.4.15.2.34.2.3 diff -u -r1.1.1.3.4.1.4.15.2.34.2.2 -r1.1.1.3.4.1.4.15.2.34.2.3 --- squid/src/client_side.c 1 May 2001 00:59:02 -0000 1.1.1.3.4.1.4.15.2.34.2.2 +++ squid/src/client_side.c 1 May 2001 09:02:51 -0000 1.1.1.3.4.1.4.15.2.34.2.3 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.34.2.2 2001/05/01 00:59:02 rbcollins Exp $ + * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.34.2.3 2001/05/01 09:02:51 rbcollins Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -79,6 +79,7 @@ /* Local functions */ static CWCB clientWriteComplete; +static CWCB newclientWriteComplete; static CWCB clientWriteBodyComplete; static PF clientReadRequest; static PF connStateFree; @@ -93,8 +94,6 @@ static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, size_t *); static void clientRedirectStart(void *data); 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 *); @@ -108,7 +107,6 @@ static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); static void clientPackTermBound(String boundary, MemBuf * mb); static DATAFILTER_HDR clientInterpretRequestHeaders; -static void clientProcessRequest(clientHttpRequest *); static void clientProcessExpired(void *data); static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http); static int clientCachable(clientHttpRequest * http); @@ -122,8 +120,11 @@ static DATAFILTER_HDR clientTemp; +#if HEADERS_LOG static DATAFILTER_HDR clientHeadersLog; +#endif static DATAFILTER_HDR clientfdnote; +static DATAFILTER_HDR httplocalmethods; static int checkAccelOnly(clientHttpRequest * http) @@ -387,38 +388,6 @@ clientCheckNoCache(http); */ } -#if 0 -static void -clientCheckNoCache(clientHttpRequest * http) -{ - accessstate *AccessState = NULL; - CBDATA_INIT_TYPE(accessstate); - AccessState = cbdataAlloc(accessstate); - AccessState->rep=rep; - AccessState->request=request; - AccessState->filter_list=filter_list; - AccessState->filters=filters; - AccessState->flags=flags; - AccessState->data=data; - cbdataLock(AccessState); - 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); -} -#endif - static void clientProcessExpired(void *data) { @@ -1394,6 +1363,10 @@ static DATAFILTER_HDR clientWriteReplyHeaders; static DATAFILTER clientDoCommWriteMemBuf; static DATAFILTER_HDR clientDoCommWriteHeaders; +static DATAFILTER_HDR newClientWH; +static DATAFILTER newClientW; +static DATAFILTER http_client_body; +static DATAFILTER_HDR http_client_hdr; void clientTEReplyheader(clientHttpRequest * http, HttpReply * rep, dlink_list *filter_list) { @@ -1570,6 +1543,7 @@ } +/* this is a source task. (building the canonical reply */ static HttpReply * clientBuildReply(clientHttpRequest * http, const char *buf, size_t size) { @@ -1682,7 +1656,7 @@ * so we only get here once. (it also takes care of cancelling loops) */ debug(33, 2) ("clientProcessHit: Vary detected!\n"); - clientProcessRequest(http); +// FIXME clientProcessRequest(http); return; case VARY_CANCEL: /* varyEvaluateMatch found a object loop. Process as miss */ @@ -2790,105 +2764,6 @@ } -static void clientDoProcessRequest(clientHttpRequest * http); - -static void -clientProcessRequest(clientHttpRequest * http) -{ - /* this function _should_ use some heuristics combined with - ACL's to determine what filters go onto what request, - for both the request and response data streams. - For now, it puts the common filters inm and #ifdef's - any weird ones for the user to compile in. - */ - /* if needed, use this function and a RH function to do blocking checks for what - * filters are needed. call clientDoProcessRequest when done - */ -#if 0 - FILTER_list *temp_filter; - /* this is correct: but currently we have no guaranteed filters. It's possible - * that we should insert the request filters now, and the reply filters when we - * start getting data - but I haven't gone down that much though yet :-/ - */ - if (!http->repfilters.head) { - /* Terminating filter: performs the actual write. */ - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientDoCommWrite; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAdd(temp_filter, &temp_filter->node, &http->repfilters); - } - if (!http->reqfilters.head) { - } -#endif - clientDoProcessRequest(http); -} - - -static void -clientDoProcessRequest(clientHttpRequest * http) -{ - char *url = http->uri; - request_t *r = http->request; - int fd = http->conn->fd; - 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(fd, url, r, &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) { - /* not a miss, or attaching to a in process entry */ - storeLockObject(http->entry); - 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(r)); -#endif - storeClientCopy(http->sc, http->entry, - http->out.offset, - http->out.offset, - CLIENT_SOCK_SZ, - memAllocate(MEM_CLIENT_SOCK_BUF), - 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. */ @@ -3335,10 +3210,14 @@ filterChainAddTail(&http->reqfilters, identity_body, clientHeadersLog, NULL,http); #endif filterChainAddTail(&http->reqfilters, identity_body, clientfdnote, NULL,http); -// filterChainAddTail(&http->reqfilters, identity_body, clientTemp, NULL,http); -// filterChainAddTail(&http->reqfilters, identity_body, clientTemp, NULL,http); + filterChainAddTail(&http->reqfilters, identity_body, httplocalmethods, NULL, http); filterChainAddTail(&http->reqfilters, identity_body, broker_ClientEntry_hdr, NULL,http); - filterChainAddTail(&http->reqfilters, identity_body, clientTemp, NULL,http); + + /* this is the entry point for the reply to write data to the socket */ + filterChainAddTail(&http->repfilters, http_client_body, http_client_hdr, NULL,http); +// filterChainAddTail(&http->repfilters, newClientW, newClientWH, NULL,http); + + @@ -3370,11 +3249,327 @@ return rvflags; } +/* handle local only methods - that is methods that don't apply to generic protocols + * or to the broker/store interface + * - there are none today however. + * this is a request-only filter. + */ +DATAFILTER_FILTERHEADER(httplocalmethods) { + FILTER_list *temp_filter=filters->node.next->data; + unsigned int rvflags; + clientHttpRequest *http=data; + request_t *r = http->request; + http_version_t version; + + rvflags = temp_filter->filter_hdr(rep,request,filter_list,temp_filter, flags, temp_filter->data); + dlinkDelete(&filters->node, filter_list); + xfree(filters); + return rvflags; +} + DATAFILTER_FILTERHEADER(clientTemp) { FILTER_list *temp_filter=filters->node.next->data; unsigned int rvflags; clientHttpRequest *http=data; - clientProcessRequest(http); + rvflags = temp_filter->filter_hdr(rep,request,filter_list,temp_filter, flags, temp_filter->data); + return rvflags; +} + + +/* this is the default entry point to client side functions */ +DATAFILTER_FILTER(http_client_body) +{ + FILTER_list *temp_filter=filters->node.next->data; + unsigned int rvflags; + clientHttpRequest *http=data; + fatal("Unreachable code !!!\n"); + rvflags = temp_filter->filter(buf, len, offset,filter_list,temp_filter, flags, temp_filter->data); + return rvflags; +} + +/* this is the first time we see whats coming down at us from the source */ +/* Note: if this is cancelled we clean up gracefully, that means we still call most + * things. + * However, if FILTER_ABORT is set, we are not guaranteed valid headers... + * so be prepared! + */ +DATAFILTER_FILTERHEADER(http_client_hdr) +{ + FILTER_list *temp_filter; + unsigned int rvflags; + clientHttpRequest *http=data; + HttpHeader *hdr = &rep->header; + int is_hit = isTcpHit(http->log_type); + if (!rep) + /* the source hasn't created a reply for us. */ + /* this should _never_ happen */ + fatal("NO REPLY \n"); + /* Errors: we need a clean way to replace the source and it's related filters. + * a) two filter chains. + * b) some funky cold medina. + */ + if (clientReplyBodyTooLarge(rep->content_length)) + fatal("Body too large\n"); + + #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 + /* this code is mich simpler than the old clientBuildReplyHeader because we assume + * A) only relevant headers are given to us. The server side functions are responsible + * for that. + * B) only fresh headers are provided. + */ + if (is_hit) + httpHeaderDelById(hdr, HDR_SET_COOKIE); + + /* Add user requested filters. */ + filterBuildChain(Config.reply_filters, &http->repfilters, http, rep, http->request); + + /* Handle Ranges (Note that these are _after_ the user specified filters. This means + * that if those filters inconsistently alter data length, we're screwed + */ +// filterChainAddTail(&http->repfilters, newClientRangeHdr, newClientRangeBody, NULL, http); + + /* handle TE */ + clientTEReplyheader(http,rep, &http->repfilters); + + /* + * 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); + } + + /* Handle authentication headers */ + if (request->request->auth_user_request) + authenticateFixHeader(rep, request->request->auth_user_request, request->request, http->flags.accel); + +#if 0 +/* this stuff does not belong here! - its a) not http specific and b) not client side + * driven + */ + /* 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(), ntohs(Config.Sockaddr.http->s.sin_port)); +#endif +#endif + if ((httpReplyBodySize(request->request->method, rep)) < 0 && !(request->request->flags.te_encoding)) { + debug(33, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n"); + request->request->flags.proxy_keepalive = 0; + } else if ((httpReplyBodySize(request->request->method, rep)) < 0 && (request->request->flags.te_encoding)) + debug(33, 3) ("clientBuildReplyHeader: can keep-alive, unknown body size with te\n"); + /* Signal keep-alive if needed */ + httpHeaderPutStr(hdr, http->flags.accel ? HDR_CONNECTION : HDR_PROXY_CONNECTION, + request->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->request); + + + /* And add the IO filters */ + filterChainAddTail(&http->repfilters, newClientW, newClientWH, NULL,http); + /* process what we've just setup */ + temp_filter=filters->node.next->data; + /* but we're not needed anymore */ + dlinkDelete(&filters->node, filter_list); + xfree(filters); + rvflags = temp_filter->filter_hdr(rep,request,filter_list,temp_filter, flags, temp_filter->data); + return rvflags; +} + +static void +newclientWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data) +{ + clientHttpRequest *http = data; + StoreEntry *entry = http->entry; + int done, stuckdatasize,free_te; + char *stuck_data; + MemBuf mb; + + stuckdatasize = 0; + http->out.size += size; + http->flags.reply_write_in_progress=0; + /* objectlen as the test is broken becuase it records headers in the length + * calculation + */ + debug(33, 5) ("newclientWriteComplete: FD %d, sz %d, err %d, off %d, len %d\n", + fd, size, errflag, (int) http->out.offset, entry ? objectLen(entry) : 0); + if (size > 0) { + kb_incr(&statCounter.client_http.kbytes_out, size); + if (isTcpHit(http->log_type)) + kb_incr(&statCounter.client_http.hit_kbytes_out, size); + } + if (errflag) { + /* This is a socket error on the client socket. + * just close the socket, httpRequestFree will abort if needed + */ + comm_close(fd); + return; + } + if (http->mb.size) { + /* there is queued data in the membuffer. + * write it. + */ + debug(33,8)("newclientWriteComplete: Pushing queued data\n"); + http->flags.reply_write_in_progress=1; + comm_write_mbuf(http->conn->fd, http->mb, newclientWriteComplete, http); + /* zero the membuf - the data is untouched */ + memBufDefInit(&http->mb); + return; + } else if (http->flags.done_copying) { + debug(33, 5) ("newclientWriteComplete: FD %d transfer is DONE\n", fd); + /* why are we finished? */ + if (http->request->flags.proxy_keepalive) { + debug(33, 5) ("newclientWriteComplete: FD %d Keeping Alive\n", fd); + clientKeepaliveNextRequest(http); + } else { + comm_close(fd); + } + return; + } else if (clientReplyBodyTooLarge((int) http->out.offset)) { + comm_close(fd); + return; + } + + /* call the "I want more data function". Probably the head of the reply function + * data filter, with no buffer. + */ + // http-> +} + +DATAFILTER_FILTER(newClientW) { + clientHttpRequest *http = data; + MemBuf mb; + memBufDefInit(&mb); + + /* allocate a membuf, put the data from range and te into it, and call comm_write + * membuf + */ + + /* the more efficient longterm design (say there are no ranges, and no te.. + * storeClientCopy doesn't copy the data (maybe there's another PIA call? + * we just write the buffer and when the write completes it auto frees. + * I wonder if membuffers could do that. Then + * It'd be trivial - if a later filter wants the original buffer, it just locks + * it. Hmmm. + */ + + /* we are the last of the mohicans */ + assert(filters->node.next==NULL); + assert((buf && len) || (flags & (FILTER_EOF | FILTER_ABORT))); + + debug (33,8)("clientDoCommWriteMemBuf: buf %p len %d flags %d\n",buf,len,flags); + if (!buf || !len) { + /* No new data to write */ + /* if not EOF, then some error occured upstream... abort here TODO */ + clientWriteComplete(http->conn->fd, NULL, 0, 0, http); + /* TODO: when we start buffer blocks here, this is where we flush the buffer */ + /* Why? calling clientWriteComplete flushes the buffer too */ + return 0; + + } + /* there is data to write. Concept: buffer 4K/client sock buf/ whatever here + * and only call TCP/IP layer when EOF or a larger amount is present ??? */ + + if (flags & FILTER_EOF) + http->flags.done_copying=1; + + if (!http->flags.reply_write_in_progress) { + http->flags.reply_write_in_progress=1; + memBufAppend(&mb, buf, len); + comm_write_mbuf(http->conn->fd, mb, newclientWriteComplete, http); + } else { + /* queue the data to the http membuffer */ + if (!http->mb.buf) + memBufDefInit(&http->mb); + memBufAppend(&http->mb, buf, len); + } +// comm_write(http->conn->fd, buf, len, clientWriteBodyComplete, http, NULL); + return 0; +} + +DATAFILTER_FILTERHEADER(newClientWH) { + clientHttpRequest *http = data; + MemBuf mb; +// size_t len; + +// memBufDefInit(&mb); + + /* allocate a membuf, put the data from range and te into it, and call comm_write + * membuf + */ + + /* the more efficient longterm design (say there are no ranges, and no te.. + * storeClientCopy doesn't copy the data (maybe there's another PIA call? + * we just write the buffer and when the write completes it auto frees. + * I wonder if membuffers could do that. Then + * It'd be trivial - if a later filter wants the original buffer, it just locks + * it. Hmmm. + */ + + /* we are the last of the mohicans */ + assert(filters->node.next==NULL); + + debug (33,1)("new client ** ** WriteHeaders: reply %p flags %d\n",rep,flags); + /* there is data to write. Concept: buffer 4K/client sock buf/ whatever here + * and only call TCP/IP layer when EOF or a larger amount is present ??? */ + + mb = httpReplyPack(rep); + + if (flags & FILTER_EOF) + http->flags.done_copying=1; + + if (!http->flags.reply_write_in_progress) { + http->flags.reply_write_in_progress=1; + /* FIXME: just call commWrite */ + comm_write_mbuf(http->conn->fd, mb, newclientWriteComplete, http); + } else { /* FIXME: just call commWrite */ + /* queue the data to the http membuffer */ + if (!http->mb.buf) + memBufDefInit(&http->mb); + memBufAppend(&http->mb, mb.buf, mb.size); + memBufClean(&mb); + } +// comm_write(http->conn->fd, buf, len, clientWriteBodyComplete, http, NULL); return 0; } Index: squid/src/filters.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/filters.c,v retrieving revision 1.1.2.13.2.1 retrieving revision 1.1.2.13.2.2 diff -u -r1.1.2.13.2.1 -r1.1.2.13.2.2 --- squid/src/filters.c 1 May 2001 00:02:41 -0000 1.1.2.13.2.1 +++ squid/src/filters.c 1 May 2001 09:02:51 -0000 1.1.2.13.2.2 @@ -1,6 +1,6 @@ /* - * $Id: filters.c,v 1.1.2.13.2.1 2001/05/01 00:02:41 rbcollins Exp $ + * $Id: filters.c,v 1.1.2.13.2.2 2001/05/01 09:02:51 rbcollins Exp $ * * DEBUG: section 83 Content Processing Filters * AUTHOR: Robert Collins @@ -275,7 +275,7 @@ * identity filter function: does nothing with the headers */ unsigned int -identity_header(HttpReply *rep, request_t *request, +identity_header(HttpReply *rep, clientHttpRequest *request, dlink_list * filter_list,FILTER_list * filters, unsigned int flags, void *data) { Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.1.1.3.8.11.2.20.2.1 retrieving revision 1.1.1.3.8.11.2.20.2.2 diff -u -r1.1.1.3.8.11.2.20.2.1 -r1.1.1.3.8.11.2.20.2.2 --- squid/src/protos.h 1 May 2001 00:02:41 -0000 1.1.1.3.8.11.2.20.2.1 +++ squid/src/protos.h 1 May 2001 09:02:51 -0000 1.1.1.3.8.11.2.20.2.2 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.1.1.3.8.11.2.20.2.1 2001/05/01 00:02:41 rbcollins Exp $ + * $Id: protos.h,v 1.1.1.3.8.11.2.20.2.2 2001/05/01 09:02:51 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -459,6 +459,9 @@ 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 Request */ +extern MemBuf HttpRequestPackMemBuf(const request_t *); + /* Http Reply */ extern void httpReplyInitModule(void); /* create/destroy */