📄 http.c
字号:
/* * $Id: http.c,v 1.346.2.7 1999/04/27 22:14:09 wessels Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from the * Internet community. Development is led by Duane Wessels of the * National Laboratory for Applied Network Research and funded by the * National Science Foundation. Squid is Copyrighted (C) 1998 by * Duane Wessels and the University of California San Diego. Please * see the COPYRIGHT file for full details. Squid incorporates * software developed and/or copyrighted by other sources. Please see * the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * *//* * Anonymizing patch by lutz@as-node.jena.thur.de * have a look into http-anon.c to get more informations. */#include "squid.h"static const char *const crlf = "\r\n";static CWCB httpSendComplete;static CWCB httpSendRequestEntry;static CWCB httpSendRequestEntryDone;static PF httpReadReply;static void httpSendRequest(HttpStateData *);static PF httpStateFree;static PF httpTimeout;static void httpCacheNegatively(StoreEntry *);static void httpMakePrivate(StoreEntry *);static void httpMakePublic(StoreEntry *);static int httpCachableReply(HttpStateData *);static void httpMaybeRemovePublic(StoreEntry *, http_status);static voidhttpStateFree(int fd, void *data){ HttpStateData *httpState = data;#if DELAY_POOLS delayClearNoDelay(fd);#endif if (httpState == NULL) return; storeUnlockObject(httpState->entry); if (httpState->reply_hdr) { memFree(httpState->reply_hdr, MEM_8K_BUF); httpState->reply_hdr = NULL; } requestUnlink(httpState->request); requestUnlink(httpState->orig_request); httpState->request = NULL; httpState->orig_request = NULL; cbdataFree(httpState);}inthttpCachable(method_t method){ /* GET and HEAD are cachable. Others are not. */ if (method != METHOD_GET && method != METHOD_HEAD) return 0; /* else cachable */ return 1;}static voidhttpTimeout(int fd, void *data){ HttpStateData *httpState = data; StoreEntry *entry = httpState->entry; debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry)); if (entry->store_status == STORE_PENDING) { if (entry->mem_obj->inmem_hi == 0) { fwdFail(httpState->fwd, errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT)); } } comm_close(fd);}/* This object can be cached for a long time */static voidhttpMakePublic(StoreEntry * entry){ if (EBIT_TEST(entry->flags, ENTRY_CACHABLE)) storeSetPublicKey(entry);}/* This object should never be cached at all */static voidhttpMakePrivate(StoreEntry * entry){ storeExpireNow(entry); storeReleaseRequest(entry); /* delete object when not used */ /* storeReleaseRequest clears ENTRY_CACHABLE flag */}/* This object may be negatively cached */static voidhttpCacheNegatively(StoreEntry * entry){ storeNegativeCache(entry); if (EBIT_TEST(entry->flags, ENTRY_CACHABLE)) storeSetPublicKey(entry);}static voidhttpMaybeRemovePublic(StoreEntry * e, http_status status){ int remove = 0; StoreEntry *pe; if (!EBIT_TEST(e->flags, KEY_PRIVATE)) return; switch (status) { case HTTP_OK: case HTTP_NON_AUTHORITATIVE_INFORMATION: case HTTP_MULTIPLE_CHOICES: case HTTP_MOVED_PERMANENTLY: case HTTP_MOVED_TEMPORARILY: case HTTP_FORBIDDEN: case HTTP_NOT_FOUND: case HTTP_METHOD_NOT_ALLOWED: case HTTP_GONE: remove = 1; break;#if WORK_IN_PROGRESS case HTTP_UNAUTHORIZED: remove = 1; break;#endif default: remove = 0; break; } if (!remove) return; assert(e->mem_obj); if ((pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method)) != NULL) { assert(e != pe); storeRelease(pe); } if (e->mem_obj->method == METHOD_GET) { /* A fresh GET should eject old HEAD objects */ if ((pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD)) != NULL) { assert(e != pe); storeRelease(pe); } }}static inthttpCachableReply(HttpStateData * httpState){ HttpReply *rep = httpState->entry->mem_obj->reply; HttpHeader *hdr = &rep->header; const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0; const char *v; if (EBIT_TEST(cc_mask, CC_PRIVATE)) return 0; if (EBIT_TEST(cc_mask, CC_NO_CACHE)) return 0; if (EBIT_TEST(cc_mask, CC_NO_STORE)) return 0; if (httpState->request->flags.auth) { /* * Responses to requests with authorization may be cached * only if a Cache-Control: public reply header is present. * RFC 2068, sec 14.9.4 */ if (!EBIT_TEST(cc_mask, CC_PUBLIC)) return 0; } /* * We don't properly deal with Vary features yet, so we can't * cache these */ if (httpHeaderHas(hdr, HDR_VARY)) return 0; /* Pragma: no-cache in _replies_ is not documented in HTTP, * but servers like "Active Imaging Webcast/2.0" sure do use it */ if (httpHeaderHas(hdr, HDR_PRAGMA)) { String s = httpHeaderGetList(hdr, HDR_PRAGMA); const int no_cache = strListIsMember(&s, "no-cache", ','); stringClean(&s); if (no_cache) return 0; } /* * The "multipart/x-mixed-replace" content type is used for * continuous push replies. These are generally dynamic and * probably should not be cachable */ if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE))) if (!strncasecmp(v, "multipart/x-mixed-replace", 25)) return 0; switch (httpState->entry->mem_obj->reply->sline.status) { /* Responses that are cacheable */ case HTTP_OK: case HTTP_NON_AUTHORITATIVE_INFORMATION: case HTTP_MULTIPLE_CHOICES: case HTTP_MOVED_PERMANENTLY: case HTTP_GONE: /* * Don't cache objects that need to be refreshed on next request, * unless we know how to refresh it. */ if (!refreshIsCachable(httpState->entry)) return 0; /* don't cache objects from peers w/o LMT, Date, or Expires */ /* check that is it enough to check headers @?@ */ if (rep->date > -1) return 1; else if (rep->last_modified > -1) return 1; else if (!httpState->peer) return 1; /* @?@ (here and 302): invalid expires header compiles to squid_curtime */ else if (rep->expires > -1) return 1; else return 0; /* NOTREACHED */ break; /* Responses that only are cacheable if the server says so */ case HTTP_MOVED_TEMPORARILY: if (rep->expires > -1) return 1; else return 0; /* NOTREACHED */ break; /* Errors can be negatively cached */ case HTTP_NO_CONTENT: case HTTP_USE_PROXY: case HTTP_BAD_REQUEST: case HTTP_FORBIDDEN: case HTTP_NOT_FOUND: case HTTP_METHOD_NOT_ALLOWED: case HTTP_REQUEST_URI_TOO_LARGE: case HTTP_INTERNAL_SERVER_ERROR: case HTTP_NOT_IMPLEMENTED: case HTTP_BAD_GATEWAY: case HTTP_SERVICE_UNAVAILABLE: case HTTP_GATEWAY_TIMEOUT: return -1; /* NOTREACHED */ break; /* Some responses can never be cached */ case HTTP_PARTIAL_CONTENT: /* Not yet supported */ case HTTP_SEE_OTHER: case HTTP_NOT_MODIFIED: case HTTP_UNAUTHORIZED: case HTTP_PROXY_AUTHENTICATION_REQUIRED: case HTTP_INVALID_HEADER: /* Squid header parsing error */ default: /* Unknown status code */ return 0; /* NOTREACHED */ break; } /* NOTREACHED */}/* rewrite this later using new interfaces @?@ */voidhttpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size){ char *t = NULL; StoreEntry *entry = httpState->entry; int room; int hdr_len; HttpReply *reply = entry->mem_obj->reply; debug(11, 3) ("httpProcessReplyHeader: key '%s'\n", storeKeyText(entry->key)); if (httpState->reply_hdr == NULL) httpState->reply_hdr = memAllocate(MEM_8K_BUF); if (httpState->reply_hdr_state == 0) { hdr_len = strlen(httpState->reply_hdr); room = 8191 - hdr_len; strncat(httpState->reply_hdr, buf, room < size ? room : size); hdr_len += room < size ? room : size; if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) { debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr); httpState->reply_hdr_state += 2; reply->sline.status = HTTP_INVALID_HEADER; return; } t = httpState->reply_hdr + hdr_len; /* headers can be incomplete only if object still arriving */ if (!httpState->eof) { size_t k = headersEnd(httpState->reply_hdr, 8192); if (0 == k) return; /* headers not complete */ t = httpState->reply_hdr + k; } *t = '\0'; httpState->reply_hdr_state++; } if (httpState->reply_hdr_state == 1) { const Ctx ctx = ctx_enter(entry->mem_obj->url); httpState->reply_hdr_state++; debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n", httpState->reply_hdr); /* Parse headers into reply structure */ /* what happens if we fail to parse here? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -