--------------------- PatchSet 8934 Date: 2007/02/20 09:29:42 Author: adri Branch: storework-cutaway Tag: (none) Log: Start cutting away the http caching logic from client_side.c Members: src/client_side.c:1.168.4.2->1.168.4.3 Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.168.4.2 retrieving revision 1.168.4.3 diff -u -r1.168.4.2 -r1.168.4.3 --- squid/src/client_side.c 18 Feb 2007 16:54:57 -0000 1.168.4.2 +++ squid/src/client_side.c 20 Feb 2007 09:29:42 -0000 1.168.4.3 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.168.4.2 2007/02/18 16:54:57 hno Exp $ + * $Id: client_side.c,v 1.168.4.3 2007/02/20 09:29:42 adri Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -123,8 +123,6 @@ 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); #if USE_IDENT static IDCB clientIdentDone; #endif @@ -142,7 +140,6 @@ static void clientPackTermBound(String boundary, MemBuf * mb); 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); @@ -162,7 +159,6 @@ #if USE_SSL static void httpsAcceptSSL(ConnStateData * connState, SSL_CTX * sslContext); #endif -static int modifiedSince(StoreEntry *, request_t *); static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags); static inline int clientNatLookup(ConnStateData * conn); @@ -667,367 +663,6 @@ clientProcessRequest(http); } -static void -clientProcessExpired(void *data) -{ - clientHttpRequest *http = data; - char *url = http->uri; - StoreEntry *entry = NULL; - int hit = 0; - const char *etag; - debug(33, 3) ("clientProcessExpired: '%s'\n", http->uri); - /* Can't validate non-200 responses */ - if (http->entry->mem_obj->reply->sline.status != HTTP_OK) { - debug(33, 3) ("clientProcessExpired: not a 200 OK response. Fall back on cache miss\n"); - clientProcessMiss(http); - } - /* Need either Last-Modified or ETag to build a conditional */ - if (http->entry->lastmod < 0 && !httpHeaderHas(&http->entry->mem_obj->reply->header, HDR_ETAG)) { - debug(33, 3) ("clientProcessExpired: no validator present. Fall back on cache miss\n"); - clientProcessMiss(http); - } - /* - * 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; - if (http->entry->mem_obj && http->entry->mem_obj->ims_entry) { - entry = http->entry->mem_obj->ims_entry; - debug(33, 5) ("clientProcessExpired: collapsed request\n"); - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - debug(33, 1) ("clientProcessExpired: collapsed request ABORTED!\n"); - entry = NULL; - } else if (http->entry->mem_obj->refresh_timestamp + 30 < squid_curtime) { - debug(33, 1) ("clientProcessExpired: collapsed request STALE!\n"); - entry = NULL; - } - if (entry) { - storeLockObject(entry); - hit = 1; - } else { - storeUnlockObject(http->entry->mem_obj->ims_entry); - http->entry->mem_obj->ims_entry = NULL; - } - } - if (!entry) { - entry = storeCreateEntry(url, http->request->flags, http->request->method); - if (http->entry->mem_obj) { - http->entry->mem_obj->refresh_timestamp = squid_curtime; - if (Config.onoff.collapsed_forwarding) { - http->entry->mem_obj->ims_entry = entry; - storeLockObject(http->entry->mem_obj->ims_entry); - } - } - } - /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */ - http->sc = storeClientRegister(entry, http); -#if DELAY_POOLS - /* delay_id is already set on original store client */ - delaySetStoreClient(http->sc, delayClient(http)); -#endif - if (http->old_entry->lastmod > 0) - http->request->lastmod = http->old_entry->lastmod; - else - http->request->lastmod = -1; - debug(33, 5) ("clientProcessExpired: lastmod %ld\n", (long int) entry->lastmod); - http->entry = entry; - http->out.offset = 0; - etag = httpHeaderGetStr(&http->old_entry->mem_obj->reply->header, HDR_ETAG); - if (etag) - http->request->etag = xstrdup(etag); - if (!hit) - 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, http->readbuf, - 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 ETag matches the clients If-None-Match, then return - * the servers 304 reply - */ - if (httpHeaderHas(&new_entry->mem_obj->reply->header, HDR_ETAG) && - httpHeaderHas(&request->header, HDR_IF_NONE_MATCH)) { - const char *etag = httpHeaderGetStr(&new_entry->mem_obj->reply->header, HDR_ETAG); - String etags = httpHeaderGetList(&request->header, HDR_IF_NONE_MATCH); - int etag_match = strListIsMember(&etags, etag, ','); - stringClean(&etags); - if (etag_match) { - debug(33, 5) ("clientGetsOldEntry: NO, client If-None-Match\n"); - 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; - int recopy = 1; - http_status status; - debug(33, 3) ("clientHandleIMSReply: %s, %ld bytes\n", url, (long int) size); - if (http->old_entry && http->old_entry->mem_obj && http->old_entry->mem_obj->ims_entry) { - storeUnlockObject(http->old_entry->mem_obj->ims_entry); - http->old_entry->mem_obj->ims_entry = NULL; - } - if (entry == NULL) { - return; - } - if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - 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; - storeClientUnregister(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; - storeClientUnregister(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; - } - if (mem->reply->sline.status == HTTP_NOT_MODIFIED) { - /* 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); - } - storeClientUnregister(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->flags.hit = 0; - 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; - } - storeClientUnregister(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, - clientSendMoreHeaderData, - http); - } else { - clientSendMoreHeaderData(data, buf, size); - } -} - -static int -modifiedSince(StoreEntry * entry, request_t * request) -{ - squid_off_t object_length; - MemObject *mem = entry->mem_obj; - time_t mod_time = entry->lastmod; - debug(33, 3) ("modifiedSince: '%s'\n", storeUrl(entry)); - 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; - } -} - -static 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, http->orig_request); - 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) { - if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) { - http->log_type = LOG_TCP_DENIED; - err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, http->request); - http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); - errorAppendEntry(http->entry, err); - return; - } - /* Swap in the metadata */ - http->entry = entry; - storeLockObject(http->entry); - storeCreateMemObject(http->entry, http->uri); - http->entry->mem_obj->method = http->request->method; - http->sc = storeClientRegister(http->entry, http); - http->log_type = LOG_TCP_HIT; - storeClientCopy(http->sc, http->entry, - http->out.offset, - http->out.offset, - CLIENT_SOCK_SZ, http->readbuf, - 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; - } - /* - * 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) { @@ -1933,9 +1568,6 @@ clientHttpRequest *http = data; StoreEntry *e = http->entry; MemObject *mem; - request_t *r = http->request; - int is_modified = -1; - int stale; debug(33, 3) ("clientCacheHit: %s, %d bytes\n", http->uri, (int) size); http->flags.hit = 0; if (http->entry == NULL) { @@ -1978,153 +1610,7 @@ } return; } - /* - * Got the headers, now grok them - */ - assert(http->log_type == LOG_TCP_HIT); - if (r->method == METHOD_PURGE) { - http->entry = NULL; - storeClientUnregister(http->sc, e, http); - http->sc = NULL; - storeUnlockObject(e); - clientPurgeRequest(http); - return; - } - http->flags.hit = 1; - if (EBIT_TEST(e->flags, ENTRY_NEGCACHED)) { - if (checkNegativeHit(e) -#if HTTP_VIOLATIONS - && !r->flags.nocache_hack -#endif - ) { - http->log_type = LOG_TCP_NEGATIVE_HIT; - clientSendMoreHeaderData(data, buf, size); - } else { - http->log_type = LOG_TCP_MISS; - clientProcessMiss(http); - } - return; - } - if (httpHeaderHas(&r->header, HDR_IF_MATCH)) { - const char *rep_etag = httpHeaderGetStr(&e->mem_obj->reply->header, HDR_ETAG); - int has_etag = 0; - if (rep_etag) { - String req_etags = httpHeaderGetList(&http->request->header, HDR_IF_MATCH); - has_etag = strListIsMember(&req_etags, rep_etag, ','); - stringClean(&req_etags); - } - if (!has_etag) { - /* The entity tags does not match. This cannot be a hit for this object. - * Query the origin to see what should be done. - */ - http->log_type = LOG_TCP_MISS; - clientProcessMiss(http); - return; - } - } - if (httpHeaderHas(&r->header, HDR_IF_NONE_MATCH)) { - String req_etags; - const char *rep_etag = httpHeaderGetStr(&e->mem_obj->reply->header, HDR_ETAG); - int has_etag; - 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); - return; - } - if (rep_etag) { - req_etags = httpHeaderGetList(&http->request->header, HDR_IF_NONE_MATCH); - has_etag = strListIsMember(&req_etags, rep_etag, ','); - stringClean(&req_etags); - if (has_etag) { - debug(33, 4) ("clientCacheHit: If-None-Match matches\n"); - if (is_modified == -1) - is_modified = 0; - } else { - debug(33, 4) ("clientCacheHit: If-None-Match mismatch\n"); - is_modified = 1; - } - } - } - if (r->flags.ims && mem->reply->sline.status == HTTP_OK) { - if (modifiedSince(e, http->request)) { - debug(33, 4) ("clientCacheHit: If-Modified-Since modified\n"); - is_modified = 1; - } else { - debug(33, 4) ("clientCacheHit: If-Modified-Since not modified\n"); - if (is_modified == -1) - is_modified = 0; - } - } - stale = refreshCheckHTTPStale(e, r); - if (stale == 0) { - debug(33, 2) ("clientProcessHit: HIT\n"); - } else if (stale == -1 && Config.refresh_stale_window > 0 && e->mem_obj->refresh_timestamp + Config.refresh_stale_window > squid_curtime) { - debug(33, 2) ("clientProcessHit: refresh_stale HIT\n"); - http->log_type = LOG_TCP_STALE_HIT; - stale = 0; - } else if (stale && http->flags.internal) { - debug(33, 2) ("clientProcessHit: internal HIT\n"); - stale = 0; - } else if (stale && Config.onoff.offline) { - debug(33, 2) ("clientProcessHit: offline HIT\n"); - http->log_type = LOG_TCP_OFFLINE_HIT; - stale = 0; - } - if (stale) { - 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 (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 { - clientProcessExpired(http); - } - return; - } - if (is_modified == 0) { - time_t timestamp = e->timestamp; - MemBuf mb = httpPacked304Reply(e->mem_obj->reply); - http->log_type = LOG_TCP_IMS_HIT; - storeClientUnregister(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); - return; - } - /* - * plain ol' cache hit - */ - if (e->store_status != STORE_OK) - http->log_type = LOG_TCP_MISS; - else if (http->log_type == LOG_TCP_HIT && e->mem_status == IN_MEMORY) - http->log_type = LOG_TCP_MEM_HIT; - clientSendMoreHeaderData(data, buf, size); + clientProcessMiss(http); } /* put terminating boundary for multiparts */ @@ -3129,9 +2615,6 @@ #endif 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->log_type = LOG_TCP_HIT; @@ -3211,10 +2694,6 @@ storeUnlockObject(http->entry); http->entry = NULL; } - if (r->method == METHOD_PURGE) { - clientPurgeRequest(http); - return; - } if (clientOnlyIfCached(http)) { clientProcessOnlyIfCachedMiss(http); return;