📄 httpheader.c
字号:
/* * $Id: HttpHeader.c,v 1.61.2.1 1999/02/12 19:38:18 wessels Exp $ * * DEBUG: section 55 HTTP Header * AUTHOR: Alex Rousskov * * 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. * */#include "squid.h"/* * On naming conventions: * * HTTP/1.1 defines message-header as * * message-header = field-name ":" [ field-value ] CRLF * field-name = token * field-value = *( field-content | LWS ) * * HTTP/1.1 does not give a name name a group of all message-headers in a message. * Squid 1.1 seems to refer to that group _plus_ start-line as "headers". * * HttpHeader is an object that represents all message-headers in a message. * HttpHeader does not manage start-line. * * HttpHeader is implemented as a collection of header "entries". * An entry is a (field_id, field_name, field_value) triplet. *//* * local constants and vars *//* * A table with major attributes for every known field. * We calculate name lengths and reorganize this array on start up. * After reorganization, field id can be used as an index to the table. */static const HttpHeaderFieldAttrs HeadersAttrs[] ={ {"Accept", HDR_ACCEPT, ftStr}, {"Accept-Charset", HDR_ACCEPT_CHARSET, ftStr}, {"Accept-Encoding", HDR_ACCEPT_ENCODING, ftStr}, {"Accept-Language", HDR_ACCEPT_LANGUAGE, ftStr}, {"Accept-Ranges", HDR_ACCEPT_RANGES, ftStr}, {"Age", HDR_AGE, ftInt}, {"Allow", HDR_ALLOW, ftStr}, {"Authorization", HDR_AUTHORIZATION, ftStr}, /* for now */ {"Cache-Control", HDR_CACHE_CONTROL, ftPCc}, {"Connection", HDR_CONNECTION, ftStr}, {"Content-Base", HDR_CONTENT_BASE, ftStr}, {"Content-Encoding", HDR_CONTENT_ENCODING, ftStr}, {"Content-Language", HDR_CONTENT_LANGUAGE, ftStr}, {"Content-Length", HDR_CONTENT_LENGTH, ftInt}, {"Content-Location", HDR_CONTENT_LOCATION, ftStr}, {"Content-MD5", HDR_CONTENT_MD5, ftStr}, /* for now */ {"Content-Range", HDR_CONTENT_RANGE, ftPContRange}, {"Content-Type", HDR_CONTENT_TYPE, ftStr}, {"Date", HDR_DATE, ftDate_1123}, {"ETag", HDR_ETAG, ftETag}, {"Expires", HDR_EXPIRES, ftDate_1123}, {"From", HDR_FROM, ftStr}, {"Host", HDR_HOST, ftStr}, {"If-Match", HDR_IF_MATCH, ftStr}, /* for now */ {"If-Modified-Since", HDR_IF_MODIFIED_SINCE, ftDate_1123}, {"If-None-Match", HDR_IF_NONE_MATCH, ftStr}, /* for now */ {"If-Range", HDR_IF_RANGE, ftDate_1123_or_ETag}, {"Last-Modified", HDR_LAST_MODIFIED, ftDate_1123}, {"Link", HDR_LINK, ftStr}, {"Location", HDR_LOCATION, ftStr}, {"Max-Forwards", HDR_MAX_FORWARDS, ftInt}, {"Mime-Version", HDR_MIME_VERSION, ftStr}, /* for now */ {"Pragma", HDR_PRAGMA, ftStr}, {"Proxy-Authenticate", HDR_PROXY_AUTHENTICATE, ftStr}, {"Proxy-Authorization", HDR_PROXY_AUTHORIZATION, ftStr}, {"Proxy-Connection", HDR_PROXY_CONNECTION, ftStr}, {"Public", HDR_PUBLIC, ftStr}, {"Range", HDR_RANGE, ftPRange}, {"Referer", HDR_REFERER, ftStr}, {"Request-Range", HDR_REQUEST_RANGE, ftPRange}, /* usually matches HDR_RANGE */ {"Retry-After", HDR_RETRY_AFTER, ftStr}, /* for now (ftDate_1123 or ftInt!) */ {"Server", HDR_SERVER, ftStr}, {"Set-Cookie", HDR_SET_COOKIE, ftStr}, {"Title", HDR_TITLE, ftStr}, {"Upgrade", HDR_UPGRADE, ftStr}, /* for now */ {"User-Agent", HDR_USER_AGENT, ftStr}, {"Vary", HDR_VARY, ftStr}, /* for now */ {"Via", HDR_VIA, ftStr}, /* for now */ {"Warning", HDR_WARNING, ftStr}, /* for now */ {"WWW-Authenticate", HDR_WWW_AUTHENTICATE, ftStr}, {"X-Cache", HDR_X_CACHE, ftStr}, {"X-Cache-Lookup", HDR_X_CACHE_LOOKUP, ftStr}, {"X-Forwarded-For", HDR_X_FORWARDED_FOR, ftStr}, {"X-Request-URI", HDR_X_REQUEST_URI, ftStr}, {"X-Squid-Error", HDR_X_SQUID_ERROR, ftStr}, {"Other:", HDR_OTHER, ftStr} /* ':' will not allow matches */};static HttpHeaderFieldInfo *Headers = NULL;/* * headers with field values defined as #(values) in HTTP/1.1 * Headers that are currently not recognized, are commented out. */static HttpHeaderMask ListHeadersMask; /* set run-time using ListHeadersArr */static http_hdr_type ListHeadersArr[] ={ HDR_ACCEPT, HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE, HDR_ACCEPT_RANGES, HDR_ALLOW, HDR_CACHE_CONTROL, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONNECTION, HDR_IF_MATCH, HDR_IF_NONE_MATCH, HDR_LINK, HDR_PRAGMA, /* HDR_TRANSFER_ENCODING, */ HDR_UPGRADE, HDR_VARY, HDR_VIA, /* HDR_WARNING, */ HDR_WWW_AUTHENTICATE, /* HDR_EXPECT, HDR_TE, HDR_TRAILER */ HDR_X_FORWARDED_FOR};/* general-headers */static http_hdr_type GeneralHeadersArr[] ={ HDR_CACHE_CONTROL, HDR_CONNECTION, HDR_DATE, HDR_PRAGMA, /* HDR_TRANSFER_ENCODING, */ HDR_UPGRADE, /* HDR_TRAILER, */ HDR_VIA};/* entity-headers */static http_hdr_type EntityHeadersArr[] ={ HDR_ALLOW, HDR_CONTENT_BASE, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH, HDR_CONTENT_LOCATION, HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_ETAG, HDR_EXPIRES, HDR_LAST_MODIFIED, HDR_LINK, HDR_OTHER};static HttpHeaderMask ReplyHeadersMask; /* set run-time using ReplyHeaders */static http_hdr_type ReplyHeadersArr[] ={ HDR_ACCEPT, HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE, HDR_ACCEPT_RANGES, HDR_AGE, HDR_LOCATION, HDR_MAX_FORWARDS, HDR_MIME_VERSION, HDR_PUBLIC, HDR_RETRY_AFTER, HDR_SERVER, HDR_SET_COOKIE, HDR_VARY, HDR_WARNING, HDR_PROXY_CONNECTION, HDR_X_CACHE, HDR_X_CACHE_LOOKUP, HDR_X_REQUEST_URI, HDR_X_SQUID_ERROR};static HttpHeaderMask RequestHeadersMask; /* set run-time using RequestHeaders */static http_hdr_type RequestHeadersArr[] ={ HDR_AUTHORIZATION, HDR_FROM, HDR_HOST, HDR_IF_MATCH, HDR_IF_MODIFIED_SINCE, HDR_IF_NONE_MATCH, HDR_IF_RANGE, HDR_MAX_FORWARDS, HDR_PROXY_CONNECTION, HDR_PROXY_AUTHORIZATION, HDR_RANGE, HDR_REFERER, HDR_REQUEST_RANGE, HDR_USER_AGENT, HDR_X_FORWARDED_FOR};/* header accounting */static HttpHeaderStat HttpHeaderStats[] ={ {"all"},#if USE_HTCP {"HTCP reply"},#endif {"request"}, {"reply"}};static int HttpHeaderStatCount = countof(HttpHeaderStats);static int HeaderEntryParsedCount = 0;/* * local routines */#define assert_eid(id) assert((id) >= 0 && (id) < HDR_ENUM_END)static HttpHeaderEntry *httpHeaderEntryCreate(http_hdr_type id, const char *name, const char *value);static void httpHeaderEntryDestroy(HttpHeaderEntry * e);static HttpHeaderEntry *httpHeaderEntryParseCreate(const char *field_start, const char *field_end);static void httpHeaderNoteParsedEntry(http_hdr_type id, String value, int error);static void httpHeaderStatInit(HttpHeaderStat * hs, const char *label);static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e);/* * Module initialization routines */voidhttpHeaderInitModule(){ int i; /* check that we have enough space for masks */ assert(8 * sizeof(HttpHeaderMask) >= HDR_ENUM_END); /* all headers must be described */ assert(countof(HeadersAttrs) == HDR_ENUM_END); if (!Headers) Headers = httpHeaderBuildFieldsInfo(HeadersAttrs, HDR_ENUM_END); /* create masks */ httpHeaderMaskInit(&ListHeadersMask, 0); httpHeaderCalcMask(&ListHeadersMask, (const int *) ListHeadersArr, countof(ListHeadersArr)); httpHeaderMaskInit(&ReplyHeadersMask, 0); httpHeaderCalcMask(&ReplyHeadersMask, (const int *) ReplyHeadersArr, countof(ReplyHeadersArr)); httpHeaderCalcMask(&ReplyHeadersMask, (const int *) GeneralHeadersArr, countof(GeneralHeadersArr)); httpHeaderCalcMask(&ReplyHeadersMask, (const int *) EntityHeadersArr, countof(EntityHeadersArr)); httpHeaderMaskInit(&RequestHeadersMask, 0); httpHeaderCalcMask(&RequestHeadersMask, (const int *) RequestHeadersArr, countof(RequestHeadersArr)); httpHeaderCalcMask(&RequestHeadersMask, (const int *) GeneralHeadersArr, countof(GeneralHeadersArr)); httpHeaderCalcMask(&RequestHeadersMask, (const int *) EntityHeadersArr, countof(EntityHeadersArr)); /* init header stats */ assert(HttpHeaderStatCount == hoReply + 1); for (i = 0; i < HttpHeaderStatCount; i++) httpHeaderStatInit(HttpHeaderStats + i, HttpHeaderStats[i].label); HttpHeaderStats[hoRequest].owner_mask = &RequestHeadersMask; HttpHeaderStats[hoReply].owner_mask = &ReplyHeadersMask;#if USE_HTCP HttpHeaderStats[hoHtcpReply].owner_mask = &ReplyHeadersMask;#endif /* init dependent modules */ httpHdrCcInitModule(); /* register with cache manager */ cachemgrRegister("http_headers", "HTTP Header Statistics", httpHeaderStoreReport, 0, 1);}voidhttpHeaderCleanModule(){ httpHeaderDestroyFieldsInfo(Headers, HDR_ENUM_END); Headers = NULL; httpHdrCcCleanModule();}static voidhttpHeaderStatInit(HttpHeaderStat * hs, const char *label){ assert(hs); assert(label); memset(hs, 0, sizeof(HttpHeaderStat)); hs->label = label; statHistEnumInit(&hs->hdrUCountDistr, 32); /* not a real enum */ statHistEnumInit(&hs->fieldTypeDistr, HDR_ENUM_END); statHistEnumInit(&hs->ccTypeDistr, CC_ENUM_END);}/* * HttpHeader Implementation */voidhttpHeaderInit(HttpHeader * hdr, http_hdr_owner_type owner){ assert(hdr); assert(owner > hoNone && owner <= hoReply); debug(55, 7) ("init-ing hdr: %p owner: %d\n", hdr, owner); memset(hdr, 0, sizeof(*hdr)); hdr->owner = owner; arrayInit(&hdr->entries);}voidhttpHeaderClean(HttpHeader * hdr){ HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; assert(hdr); assert(hdr->owner > hoNone && hdr->owner <= hoReply); debug(55, 7) ("cleaning hdr: %p owner: %d\n", hdr, hdr->owner); statHistCount(&HttpHeaderStats[hdr->owner].hdrUCountDistr, hdr->entries.count); HttpHeaderStats[hdr->owner].destroyedCount++; HttpHeaderStats[hdr->owner].busyDestroyedCount += hdr->entries.count > 0; while ((e = httpHeaderGetEntry(hdr, &pos))) { /* tmp hack to try to avoid coredumps */ if (e->id < 0 || e->id >= HDR_ENUM_END) { debug(55, 0) ("httpHeaderClean BUG: entry[%d] is invalid (%d). Ignored.\n", pos, e->id); } else { statHistCount(&HttpHeaderStats[hdr->owner].fieldTypeDistr, e->id); /* yes, this destroy() leaves us in an incosistent state */ httpHeaderEntryDestroy(e); } } arrayClean(&hdr->entries);}/* append entries (also see httpHeaderUpdate) */voidhttpHeaderAppend(HttpHeader * dest, const HttpHeader * src){ const HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; assert(src && dest); assert(src != dest); debug(55, 7) ("appending hdr: %p += %p\n", dest, src); while ((e = httpHeaderGetEntry(src, &pos))) { httpHeaderAddEntry(dest, httpHeaderEntryClone(e)); }}/* use fresh entries to replace old ones */voidhttpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask){ const HttpHeaderEntry *e; HttpHeaderPos pos = HttpHeaderInitPos; assert(old && fresh); assert(old != fresh); debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh); while ((e = httpHeaderGetEntry(fresh, &pos))) { /* deny bad guys (ok to check for HDR_OTHER) here */ if (denied_mask && CBIT_TEST(*denied_mask, e->id)) continue; httpHeaderDelByName(old, strBuf(e->name)); httpHeaderAddEntry(old, httpHeaderEntryClone(e)); }}/* just handy in parsing: resets and returns false */int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -