--------------------- PatchSet 2234 Date: 2001/05/07 23:09:15 Author: rbcollins Branch: newhttp Tag: (none) Log: remove old non-client side (ie store or server side) code Members: src/client_side.c:1.1.1.3.4.1.4.15.2.34.2.6->1.1.1.3.4.1.4.15.2.34.2.7 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.6 retrieving revision 1.1.1.3.4.1.4.15.2.34.2.7 diff -u -r1.1.1.3.4.1.4.15.2.34.2.6 -r1.1.1.3.4.1.4.15.2.34.2.7 --- squid/src/client_side.c 4 May 2001 14:39:35 -0000 1.1.1.3.4.1.4.15.2.34.2.6 +++ squid/src/client_side.c 7 May 2001 23:09:15 -0000 1.1.1.3.4.1.4.15.2.34.2.7 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.34.2.6 2001/05/04 14:39:35 rbcollins Exp $ + * $Id: client_side.c,v 1.1.1.3.4.1.4.15.2.34.2.7 2001/05/07 23:09:15 rbcollins Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -84,7 +84,6 @@ /* Local functions */ -static CWCB clientWriteComplete; static CWCB newclientWriteComplete; static CWCB clientWriteBodyComplete; static PF clientReadRequest; @@ -92,10 +91,7 @@ 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 *, size_t *); static STCB clientHandleIMSReply; @@ -105,8 +101,6 @@ static IDCB clientIdentDone; #endif static int clientOnlyIfCached(clientHttpRequest * http); -static STCB clientSendMoreData; -static STCB clientCacheHit; static void clientSetKeepaliveFlag(clientHttpRequest *); static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); static void clientPackTermBound(String boundary, MemBuf * mb); @@ -239,9 +233,9 @@ #if DELAY_POOLS delaySetStoreClient(h->sc, delayClient(h->request)); #endif - storeClientCopy(h->sc, e, 0, 0, CLIENT_SOCK_SZ, +/* storeClientCopy(h->sc, e, 0, 0, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, h); - return e; + */ return e; } void @@ -327,344 +321,6 @@ } 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; - /* - * 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->callback_data == http); - 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->request)); -#endif - http->request->lastmod = http->old_entry->lastmod; - debug(33, 5) ("clientProcessExpired: lastmod %d\n", (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"); - storeClientCopy(http->sc, entry, - http->out.offset, - http->out.offset, - CLIENT_SOCK_SZ, - memAllocate(MEM_CLIENT_SOCK_BUF), - 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 %d\n", - (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, size_t offset, unsigned int flags) -{ - clientHttpRequest *http = data; - StoreEntry *entry = http->entry; - MemObject *mem; - const char *url = storeUrl(entry); - int unlink_request = 0; - StoreEntry *oldentry; - int recopy = 1; - http_status status; - debug(33, 3) ("clientHandleIMSReply: %s, %d bytes\n", url, (int) size); - if (entry == NULL) { - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } - if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } - 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; - } else if (STORE_PENDING == entry->store_status && 0 == status) { - debug(33, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", url); - if (size >= CLIENT_SOCK_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; - /* continue */ - } else { - storeClientCopy(http->sc, entry, - http->out.offset + size, - http->out.offset, - CLIENT_SOCK_SZ, - buf, - 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. */ - /* RBC: Note that 304's are NOT ALLOWED a BODY. */ - 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; - } - } 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); - recopy = 0; - } - http->old_entry = NULL; /* done with old_entry */ - http->old_sc = NULL; - assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED)); - if (recopy) { - storeClientCopy(http->sc, entry, - http->out.offset, - http->out.offset, - CLIENT_SOCK_SZ, - buf, - clientSendMoreData, - http); - } else { - clientSendMoreData(data, buf, size, offset, flags); - } -} - -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 = %d\n", (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; - } -} - -/* this is a server side protocol - part of the store. - * - */ -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; - storeClientCopy(http->sc, http->entry, - http->out.offset, - http->out.offset, - CLIENT_SOCK_SZ, - memAllocate(MEM_CLIENT_SOCK_BUF), - 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) { int svc_time = tvSubMsec(http->start, current_time); @@ -1347,374 +1003,6 @@ te_build_encode_xlate_list(&http->request->header, hdr, filter_list, http->request->http_ver, &http->request->flags); } -/* - * 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; - - /* add the header check & forward filter */ - filterChainAdd(&http->repfilters,identity_body, clientWriteReplyHeaders, NULL,http); - - -#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); - - /* http.c currently does _not_ clean the headers properly before they - * hit the store. Clean them here before we process our downstream layout - */ - - /* 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); - } - - filterBuildChain(Config.reply_filters, &http->repfilters, http, rep, http->request); - - /* Handle Ranges */ - if (request->range) - clientBuildRangeHeader(http, rep); - - /* 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->auth_user_request) - authenticateFixHeader(rep, request->auth_user_request, request, http->flags.accel); - /* 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 - if ((httpReplyBodySize(request->method, rep)) < 0 && !(request->flags.te_encoding)) { - debug(33, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n"); - request->flags.proxy_keepalive = 0; - } else if ((httpReplyBodySize(request->method, rep)) < 0 && (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->flags.proxy_keepalive ? "keep-alive" : "close"); -#if CODEFORADDINGCONNECTIONVARS - s_te = httpHeaderGetList(hdr, HDR_CONNECTION); - strListAdd(&s_te, "Transfer-Encoding", ','); - httpHeaderDelById(hdr, HDR_CONNECTION); - httpHeaderPutStr(hdr, HDR_CONNECTION, strBuf(s_te)); - stringClean(&s_te); -#endif - -#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); - - -} - -/* this is a source task. (building the canonical reply */ -static HttpReply * -clientBuildReply(clientHttpRequest * http, const char *buf, size_t size) -{ - HttpReply *rep = httpReplyCreate(); - /* why are we parsing this again ? */ - /* we should be given a oldreply with the upstream headers already parsed, - * connection header processed, etc etc */ - size_t k = headersEnd(buf, size); - if (k && httpReplyParse(rep, buf, k)) { - /* enforce 1.0 reply version */ - httpBuildVersion(&rep->sline.version, 1, 1); - /* build reply header & install filters */ - clientBuildReplyHeader(http, rep); - /* add the terminating filter */ - filterChainAddTail(&http->repfilters,clientDoCommWriteMemBuf,clientDoCommWriteHeaders, NULL,http); - } else { - /* parsing failure, get rid of the invalid reply */ - httpReplyDestroy(rep); - rep = NULL; - /* if we were going to do ranges, backoff */ - if (http->request->range) { - /* this will fail and destroy request->range */ - clientBuildRangeHeader(http, rep); - } - } - 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, size_t offset, unsigned int flags) -{ - 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) { - memFree(buf, MEM_CLIENT_SOCK_BUF); - debug(33, 3) ("clientCacheHit: request aborted\n"); - return; - } else if (size < 0) { - /* swap in failure */ - memFree(buf, MEM_CLIENT_SOCK_BUF); - 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)); - 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) { - memFree(buf, MEM_CLIENT_SOCK_BUF); - clientProcessMiss(http); - } else if (size == CLIENT_SOCK_SZ && http->out.offset == 0) { - memFree(buf, MEM_CLIENT_SOCK_BUF); - clientProcessMiss(http); - } else { - debug(33, 3) ("clientCacheHit: waiting for HTTP reply headers\n"); - storeClientCopy(http->sc, e, - http->out.offset + size, - http->out.offset, - CLIENT_SOCK_SZ, - buf, - 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. - */ - memFree(buf, MEM_CLIENT_SOCK_BUF); - 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"); -// FIXME clientProcessRequest(http); - return; - case VARY_CANCEL: - /* varyEvaluateMatch found a object loop. Process as miss */ - debug(33, 1) ("clientProcessHit: Vary object loop!\n"); - memFree(buf, MEM_CLIENT_SOCK_BUF); - clientProcessMiss(http); - return; - } - if (r->method == METHOD_PURGE) { - memFree(buf, MEM_CLIENT_SOCK_BUF); - 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, offset, flags); - } 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, offset, flags); - } 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); - } - memFree(buf, MEM_CLIENT_SOCK_BUF); - } 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); - memFree(buf, MEM_CLIENT_SOCK_BUF); - 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, offset, flags); - } else { - time_t timestamp = e->timestamp; - MemBuf mb = httpPacked304Reply(e->mem_obj->reply); - http->log_type = LOG_TCP_IMS_HIT; - memFree(buf, MEM_CLIENT_SOCK_BUF); - 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, 0); - 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, offset, flags); - } -} - /* put terminating boundary for multiparts */ static void clientPackTermBound(String boundary, MemBuf * mb) @@ -1969,114 +1257,6 @@ return rvflags; } -DATAFILTER_FILTER(clientDoCommWriteMemBuf) { - 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, clientWriteComplete, 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; -} - - -/* write the headers. Yes this is the same code as above. It is the same code for - * two reasons: - * - * 1: I haven't stripped it back yet. - * 2: pipelining may require buffering the headers - * It is the same code for Three, yes Three reasons - * 3: we don't recieve a header_t struct yet, so there's no reason to be different. - * When we do get that struct, this will create the headers to send to the client, - * But otherwise be the same - */ -DATAFILTER_FILTERHEADER(clientDoCommWriteHeaders) { - 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,8)("clientDoCommWriteHeaders: 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, clientWriteComplete, http); - } else { /* FIXME: just call commWrite */ - /* 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; -} - - /* 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. @@ -2104,285 +1284,6 @@ } -/* - * accepts chunk of a http message in buf, parses prefix, filters headers and - * such, calls filter init routines, and then calls the filters. - */ -static void -clientSendMoreData(void *data, char *buf, ssize_t size, size_t offset, unsigned int flags) -{ - clientHttpRequest *http = data; - StoreEntry *entry = http->entry; - ConnStateData *conn = http->conn; - int fd = conn->fd; - HttpReply *rep = NULL; - const char *body_buf = buf; - int body_size = size; - unsigned int filter_flags=0; - MemBuf mb; - ssize_t check_size = 0; - debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); - assert(size <= CLIENT_SOCK_SZ); - assert(http->request != NULL); - dlinkDelete(&http->active, &ClientActiveRequests); - dlinkAdd(http, &http->active, &ClientActiveRequests); - debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d \n", - fd, storeUrl(entry), (int) http->out.offset); - - /* RBC There is a problem with all this logic: - * when we are sending encoded data, receiving no data does not imply - * that we have no data to send. IFF WriteComplete sends the final TE code - * then this is ok - */ - if (clientCheckTransferDone(http)) - filter_flags |= FILTER_EOF; - - if (conn->chr != http) { - /* there is another object in progress, defer this one */ - debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - /* call clientWriteComplete so the client socket gets closed */ - /* broken for TE - we can simply send a chunk-length of 0, and - * a trailer error (I think). */ - - /* TODO borken for filters too. call the filter chain with NULL, and - * FILTER_READ_ERROR - */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } else if (size < 0) { - /* call clientWriteComplete so the client socket gets closed */ - /* TODO as above */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } else if (size == 0) { - if (http->repfilters.head != NULL) { - FILTER_list *temp_filter; - temp_filter=http->repfilters.head->data; - temp_filter->filter(NULL, 0, http->out.offset, &http->repfilters, temp_filter, filter_flags | FILTER_EOF, temp_filter->data); - } else - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - memFree(buf, MEM_CLIENT_SOCK_BUF); - return; - } - /* test if we have actually receieved the full headers yet */ - if (http->out.offset == 0) { - FILTER_list *temp_filter; - /* this test can go when filters are stable */ - assert(http->repfilters.head==NULL); - 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 && clientReplyBodyTooLarge(rep->content_length)) { - /* the following two list removals deal - * wuth resetting the dynamically attached code modules - * so the error doesn't get handled twice! - */ - ErrorState *err; - filterCleanChain(&http->repfilters); - 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; - } else if (rep) { - aclCheck_t *ch; - int rv; - body_size = size - rep->hdr_sz; - assert(body_size >= 0); - body_buf = buf + rep->hdr_sz; - http->range_iter.prefix_size = rep->hdr_sz; - debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n", - body_size, rep->hdr_sz); - ch = aclChecklistCreate(Config.accessList.reply, http->request, NULL); - ch->reply = rep; - rv = aclCheckFast(Config.accessList.reply, ch); - 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"); - debug(1,1)("content type: '%s'\n",rep->content_type.buf); - 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. */ - /* 304 responses are their because they don't have a - * content-type header, which breaks the rep_mime_type acl, which - * coincidentally, is the most common acl for reply access lists - */ - ErrorState *err; - /* reset the dynamically attached code modules - * so the error doesn't get handled twice! - */ - filterCleanChain(&http->repfilters); - debug(33,8)("********* DENYING ACCESSS ************\n"); - assert(http->repfilters.head==NULL); - 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; - } - aclChecklistFree(ch); - } else if (size < CLIENT_SOCK_SZ && entry->store_status == STORE_PENDING) { - /* wait for more to arrive */ - /* so we can build the headers */ - debug(1,1)("**************** THIS SHOULDN'T BE REACHED ***************\n"); - storeClientCopy(http->sc, entry, - http->out.offset + size, - http->out.offset, - CLIENT_SOCK_SZ, - buf, - clientSendMoreData, - http); - return; - } - /* setup reply filters */ -#if 0 - /* this can't be done until the process for locking/freeing buffers - * is looked into - */ - if (!http->request->range && !(http->request->flags.te_encoding)) { - /* Terminating filter: performs the actual write. */ - /* this one writes directly through, no membuffer involved */ - temp_filter=xmalloc(sizeof(FILTER_list)); - temp_filter->filter=clientDoCommWrite; - temp_filter->data=http; - /* cbDataLock(http); ? */ - dlinkAddTail(temp_filter, &temp_filter->node, &http->repfilters); - } else -#endif - /* reset range iterator */ - http->range_iter.pos = HttpHdrRangeInitPos; - - /* for HEAD, mark EOF now. */ - if (http->request->method == METHOD_HEAD) { - 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... - */ - - /* Because clientBuildReply has failed, we haven't performed - * any anonymising of headers/sanity checks/content checks. - * thats not good :/. - * So we abort the request - */ - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - memFree(buf, MEM_CLIENT_SOCK_BUF); - } - } - - /* write headers and/or body if any */ - assert(rep || (body_buf && body_size)); - /* init mb; put status line and headers if any */ - /* rep is only created when out offset ==0 */ - mb = httpReplyPack(rep); - /* offset is actually the seek position in the input data stream */ - http->out.offset = rep->hdr_sz; - check_size += rep->hdr_sz; -#if HEADERS_LOG - headersLog(0, 0, http->request->method, rep); -#endif - httpReplyDestroy(rep); - rep = NULL; - /* send the headers on. Yes this isn't the absolute most efficient - * method, but the write function at the end of the chain is able to combine - * the data pushed through the filters if needed for tcp efficiency - */ - assert(http->repfilters.head); - temp_filter=http->repfilters.head->data; - temp_filter->filter(mb.buf, mb.size, -1, &http->repfilters, temp_filter, filter_flags, temp_filter->data); - memBufFreeFunc(&mb); - - } - /* we can't avoid this to use TE. Tuff. - * Later on we can consider: decode in store object, then pass here - * so end clients that don't support TE aren't performance affected - * For now, because I'm lazy, I'm just disabling this - */ -#if hardtodowithfilters_butfilterswhenshortcuttingshouldbethesame - } else if (!http->request->range && !(http->request->flags.te_encoding)) { - /* Avoid copying to MemBuf for non-range requests */ - /* Note, if we're here, then 'rep' is known to be NULL */ - debug(33,8)("clientSendMoreData: writing through - no te taking place \n"); - http->out.offset += body_size; - comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); - /* NULL because clientWriteBodyComplete frees it */ - return; - } -#endif - /* call the reply filters we've set up */ - if (body_size) { - FILTER_list *temp_filter; - /* this being first may confuse ranges... but it should be here - it is the offset into the store for the next read */ - http->out.offset+=body_size; - if (clientCheckTransferDone(http)) - filter_flags |= FILTER_EOF; - assert(http->repfilters.head != NULL); - temp_filter=http->repfilters.head->data; - temp_filter->filter(body_buf, body_size, http->out.offset-body_size, &http->repfilters, temp_filter, filter_flags, temp_filter->data); -#if 0 - http->out.offset+=body_size; -#endif - } - /* free the buffer - the filters have copied data out if they are going to */ - /* ideally, the buffer passed to us is freed by the calling function - when it no longer needs it, rather than the calling function making n buffers - for n clients - */ - memFree(buf, MEM_CLIENT_SOCK_BUF); - -} - - -/* - * clientWriteBodyComplete is called for MEM_CLIENT_SOCK_BUF's - * written directly to the client socket, versus copying to a MemBuf - * and going through comm_write_mbuf. Most non-range responses after - * the headers probably go through here. - */ -static void -clientWriteBodyComplete(int fd, char *buf, size_t size, int errflag, void *data) -{ - /* - * NOTE: clientWriteComplete doesn't currently use its "buf" - * (second) argument, so we pass in NULL. - */ - clientWriteComplete(fd, NULL, size, errflag, data); - memFree(buf, MEM_CLIENT_SOCK_BUF); -} - static void clientKeepaliveNextRequest(clientHttpRequest * http) { @@ -2426,137 +1327,14 @@ if (0 == storeClientCopyPending(http->sc, entry, http)) { if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) debug(33, 0) ("clientKeepaliveNextRequest: ENTRY_ABORTED\n"); - storeClientCopy(http->sc, entry, +/* storeClientCopy(http->sc, entry, http->out.offset, http->out.offset, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, http); - } - } -} - -static void -clientWriteComplete(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) ("clientWriteComplete: 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) { - /* - * just close the socket, httpRequestFree will abort if needed - */ - comm_close(fd); - /* what does NULL=entry really test for XXX */ - } else if (NULL == entry) { - comm_close(fd); /* yuk */ - } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - comm_close(fd); - } else if (http->mb.size) { - /* there is queued data in the membuffer. - * write it. - */ - debug(33,8)("clientWriteComplete: Pushing queued data\n"); - http->flags.reply_write_in_progress=1; - comm_write_mbuf(http->conn->fd, http->mb, clientWriteComplete, http); - /* zero the membuf - the data is untouched */ - memBufDefInit(&http->mb); - return; - } else if ((done = clientCheckTransferDone(http)) != 0 || (size == 0)) { -#if 0 - (size == 0 && !(http->oldte_rv & TE_BUFFERING_OUTPUT))) { -#endif - debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd); - /* why are we finished? */ -#if 0 - debug(33,8) ("clientWriteComplete: done %d size %d tetest %d\n",done,size,http->oldte_rv & TE_BUFFERING_OUTPUT); -#endif - -#if 0 - /* We're finished case */ - http->oldte_rv = free_te = perform_te (http->te_translations,NULL,0, - &stuck_data, &stuckdatasize); - if (stuckdatasize > 0) - { - debug(33,1) ("%s:0:%d\n",http->log_uri,stuckdatasize); - if (!http->flags.reply_write_in_progress) { - http->out.offset += stuckdatasize; - http->flags.reply_write_in_progress=1; - memBufDefInit(&mb); - memBufAppend(&mb, stuck_data, stuckdatasize); - comm_write_mbuf(fd, mb, clientWriteComplete, http); - } else { - /* queue the data to the http membuffer */ - if (!http->mb.buf) - memBufDefInit(&http->mb); - memBufAppend(&http->mb, stuck_data, stuckdatasize); - } - - if (free_te & TE_BUFFER_ALLOCATED) - xfree (stuck_data); - return; - } - if (free_te & TE_CHUNK_A) /* signal from dochunk() that - data has been chunked */ - { - http->flags.done_copying = 1; - } -#endif - /* we're finished, but the filters haven't been given a termination case */ - if (http->repfilters.head != NULL && size>0 && !http->flags.done_copying && (http->entry->mem_obj->reply->content_length < 0)) { - FILTER_list *temp_filter; - temp_filter=http->repfilters.head->data; - temp_filter->filter(NULL, 0, 0, &http->repfilters, temp_filter, FILTER_EOF, temp_filter->data); - return; - } - - if (httpReplyBodySize(http->request->method, entry->mem_obj->reply) < 0 && !(http->request->flags.te_encoding)) { - 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); - /* only test for correct body size if !done && te encoding -> done is te aware */ - } else if (!(http->request->flags.te_encoding) && 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((int) 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"); - storeClientCopy(http->sc, entry, - http->out.offset, - http->out.offset, - CLIENT_SOCK_SZ, - memAllocate(MEM_CLIENT_SOCK_BUF), - clientSendMoreData, - http); +*/ } } } @@ -2623,71 +1401,6 @@ return 1; } -/* - * 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) { @@ -3410,7 +2123,7 @@ 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); + newclientWriteComplete(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; @@ -4084,6 +2797,8 @@ static int clientCheckTransferDone(clientHttpRequest * http) { +/* this code defies easy abstraction. Come back to it */ +#if 0 int sending = SENDING_BODY; StoreEntry *entry = http->entry; MemObject *mem; @@ -4145,20 +2860,10 @@ if (http->out.offset < sendlen) return 0; else +#endif 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