From: rousskov <> Date: Thu, 5 Mar 1998 07:01:07 +0000 (+0000) Subject: - gb_t additions to .h monsters X-Git-Tag: SQUID_3_0_PRE1~3927 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7faf2bdbd107159360e994049bb7fdc2a153f37f;p=thirdparty%2Fsquid.git - gb_t additions to .h monsters - Renamed HttpScc object into HttpHdrCc - Moved HttpHdrCc from HttpHeader.c to HttpHdrCc.c - Moved "commonly used" routines from HttpHeader.c to HttpHeaderTools.c. All this was done to prepare for addition of HttpHdrRange. --- diff --git a/src/HttpHdrCc.cc b/src/HttpHdrCc.cc new file mode 100644 index 0000000000..7bb44cecfd --- /dev/null +++ b/src/HttpHdrCc.cc @@ -0,0 +1,193 @@ + +/* + * $Id: HttpHdrCc.cc,v 1.1 1998/03/05 00:01:07 rousskov Exp $ + * + * DEBUG: section 65 HTTP Cache Control 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. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "squid.h" + +/* this table is used for parsing server cache control header */ +static field_attrs_t CcAttrs[CC_ENUM_END] = +{ + {"public", CC_PUBLIC}, + {"private", CC_PRIVATE}, + {"no-cache", CC_NO_CACHE}, + {"no-store", CC_NO_STORE}, + {"no-transform", CC_NO_TRANSFORM}, + {"must-revalidate", CC_MUST_REVALIDATE}, + {"proxy-revalidate", CC_PROXY_REVALIDATE}, + {"max-age", CC_MAX_AGE} +}; + + +/* counters */ +static int CcPasredCount = 0; + + +/* module initialization */ + +void +httpHdrCcInitModule() +{ + httpHeaderInitAttrTable((field_attrs_t *) CcAttrs, CC_ENUM_END); +} + +/* implementation */ + +HttpHdrCc * +httpHdrCcCreate() +{ + HttpHdrCc *cc = memAllocate(MEM_HTTP_HDR_CC); + cc->max_age = -1; + return cc; +} + +/* creates an cc object from a 0-terminating string */ +HttpHdrCc * +httpHdrCcParseCreate(const char *str) +{ + HttpHdrCc *cc = httpHdrCcCreate(); + httpHdrCcParseInit(cc, str); + return cc; +} + +/* parses a 0-terminating string and inits cc */ +void +httpHdrCcParseInit(HttpHdrCc * cc, const char *str) +{ + const char *item; + const char *p; /* '=' parameter */ + const char *pos = NULL; + int type; + int ilen; + assert(cc && str); + + CcPasredCount++; + /* iterate through comma separated list */ + while (strListGetItem(str, ',', &item, &ilen, &pos)) { + /* strip '=' statements @?@ */ + if ((p = strchr(item, '=')) && (p - item < ilen)) + ilen = p++ - item; + /* find type */ + type = httpHeaderIdByName(item, ilen, + CcAttrs, CC_ENUM_END, -1); + if (type < 0) { + debug(55, 0) ("hdr cc: unknown cache-directive: near '%s' in '%s'\n", item, str); + continue; + } + if (EBIT_TEST(cc->mask, type)) { + debug(55, 0) ("hdr cc: ignoring duplicate cache-directive: near '%s' in '%s'\n", item, str); + CcAttrs[type].stat.repCount++; + continue; + } + /* update mask */ + EBIT_SET(cc->mask, type); + /* post-processing special cases */ + switch (type) { + case CC_MAX_AGE: + if (p) + cc->max_age = (time_t) atoi(p); + if (cc->max_age < 0) { + debug(55, 0) ("cc: invalid max-age specs near '%s'\n", item); + cc->max_age = -1; + EBIT_CLR(cc->mask, type); + } + break; + default: + /* note that we ignore most of '=' specs @?@ */ + break; + } + } + return; +} + +void +httpHdrCcDestroy(HttpHdrCc * cc) +{ + assert(cc); + memFree(MEM_HTTP_HDR_CC, cc); +} + +HttpHdrCc * +httpHdrCcDup(HttpHdrCc * cc) +{ + HttpHdrCc *dup; + assert(cc); + dup = httpHdrCcCreate(); + dup->mask = cc->mask; + dup->max_age = cc->max_age; + return dup; +} + +void +httpHdrCcPackValueInto(HttpHdrCc * cc, Packer * p) +{ + http_hdr_cc_type flag; + int pcount = 0; + assert(cc && p); + if (cc->max_age >= 0) { + packerPrintf(p, "max-age=%d", cc->max_age); + pcount++; + } + for (flag = 0; flag < CC_ENUM_END; flag++) { + if (EBIT_TEST(cc->mask, flag)) { + packerPrintf(p, pcount ? ", %s" : "%s", CcAttrs[flag].name); + pcount++; + } + } +} + +void +httpHdrCcJoinWith(HttpHdrCc * cc, HttpHdrCc * new_cc) +{ + assert(cc && new_cc); + if (cc->max_age < 0) + cc->max_age = new_cc->max_age; + cc->mask |= new_cc->mask; +} + +void +httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist) +{ + http_hdr_cc_type c; + assert(cc); + for (c = 0; c < CC_ENUM_END; c++) + if (EBIT_TEST(cc->mask, c)) + statHistCount(hist, c); +} + +void +httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count) +{ + const int id = (int) val; + const int valid_id = id >= 0 && id < CC_ENUM_END; + const char *name = valid_id ? CcAttrs[id].name : "INVALID"; + if (count || valid_id) + storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n", + id, name, count, xdiv(count, CcPasredCount)); +} diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index b9468f997e..90b3545cc2 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -1,5 +1,5 @@ /* - * $Id: HttpHeader.cc,v 1.13 1998/03/04 05:39:28 rousskov Exp $ + * $Id: HttpHeader.cc,v 1.14 1998/03/05 00:01:07 rousskov Exp $ * * DEBUG: section 55 HTTP Header * AUTHOR: Alex Rousskov @@ -62,16 +62,6 @@ struct _HttpHeaderExtField { char *value; /* field-value from HTTP/1.1 */ }; -/* possible types for fields */ -typedef enum { - ftInvalid = HDR_ENUM_END, /* to catch nasty errors with hdr_id<->fld_type clashes */ - ftInt, - ftPChar, - ftDate_1123, - ftPSCC, - ftPExtField -} field_type; - /* * HttpHeader entry * ( the concrete type of entry.field is Headers[id].type ) @@ -82,18 +72,6 @@ struct _HttpHeaderEntry { }; -/* counters and size accumulators for stat objects */ -typedef int StatCount; -typedef size_t StatSize; - -/* per field statistics */ -typedef struct { - StatCount aliveCount; /* created but not destroyed (count) */ - StatCount parsCount; /* #parsing attempts */ - StatCount errCount; /* #pasring errors */ - StatCount repCount; /* #repetitons */ -} HttpHeaderFieldStat; - /* per header statistics */ typedef struct { const char *label; @@ -103,15 +81,6 @@ typedef struct { } HttpHeaderStat; -/* constant attributes of fields */ -typedef struct { - const char *name; - http_hdr_type id; - field_type type; - int name_len; - HttpHeaderFieldStat stat; -} field_attrs_t; - /* use HttpHeaderPos as opaque type, do not interpret */ typedef ssize_t HttpHeaderPos; /* use this and only this to initialize HttpHeaderPos */ @@ -157,19 +126,6 @@ static field_attrs_t Headers[] = {"Other:", HDR_OTHER, ftPExtField} /* ':' will not allow matches */ }; -/* this table is used for parsing server cache control header */ -static field_attrs_t SccAttrs[] = -{ - {"public", SCC_PUBLIC}, - {"private", SCC_PRIVATE}, - {"no-cache", SCC_NO_CACHE}, - {"no-store", SCC_NO_STORE}, - {"no-transform", SCC_NO_TRANSFORM}, - {"must-revalidate", SCC_MUST_REVALIDATE}, - {"proxy-revalidate", SCC_PROXY_REVALIDATE}, - {"max-age", SCC_MAX_AGE} -}; - /* * headers with field values defined as #(values) in HTTP/1.1 * @@ -227,15 +183,14 @@ static HttpHeaderStat HttpHeaderStats[] = static int HttpHeaderStatCount = sizeof(HttpHeaderStats) / sizeof(*HttpHeaderStats); /* global counters */ -static StatCount HeaderParsedCount = 0; -static StatCount CcPasredCount = 0; -static StatCount HeaderEntryParsedCount = 0; +static int HeaderParsedCount = 0; +static int HeaderEntryParsedCount = 0; /* long strings accounting */ -static StatCount longStrAliveCount = 0; -static StatCount longStrHighWaterCount = 0; -static StatSize longStrAliveSize = 0; -static StatSize longStrHighWaterSize = 0; +static int longStrAliveCount = 0; +static int longStrHighWaterCount = 0; +static size_t longStrAliveSize = 0; +static size_t longStrHighWaterSize = 0; /* @@ -244,10 +199,6 @@ static StatSize longStrHighWaterSize = 0; #define assert_eid(id) assert((id) >= 0 && (id) < HDR_ENUM_END) -static void httpHeaderInitAttrTable(field_attrs_t * table, int count); -static int httpHeaderCalcMask(const int *enums, int count); -static void httpHeaderStatInit(HttpHeaderStat * hs, const char *label); - static HttpHeaderEntry *httpHeaderGetEntry(const HttpHeader * hdr, HttpHeaderPos * pos); static void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos); static void httpHeaderAddParsedEntry(HttpHeader * hdr, HttpHeaderEntry * e); @@ -255,7 +206,6 @@ static void httpHeaderAddNewEntry(HttpHeader * hdr, const HttpHeaderEntry * e); static field_store httpHeaderGet(const HttpHeader * hdr, http_hdr_type id); static void httpHeaderSet(HttpHeader * hdr, http_hdr_type id, const field_store value); static void httpHeaderSyncMasks(HttpHeader * hdr, const HttpHeaderEntry * e, int add); -static int httpHeaderIdByName(const char *name, int name_len, const field_attrs_t * attrs, int end, int mask); static void httpHeaderGrow(HttpHeader * hdr); static void httpHeaderEntryInit(HttpHeaderEntry * e, http_hdr_type id, field_store field); @@ -274,21 +224,23 @@ static void httpHeaderFieldInit(field_store * field); static field_store httpHeaderFieldDup(field_type type, field_store value); static field_store httpHeaderFieldBadValue(field_type type); +#if 0 static HttpScc *httpSccCreate(); static HttpScc *httpSccParseCreate(const char *str); static void httpSccParseInit(HttpScc * scc, const char *str); static void httpSccDestroy(HttpScc * scc); static HttpScc *httpSccDup(HttpScc * scc); static void httpSccUpdateStats(const HttpScc * scc, StatHist * hist); - static void httpSccPackValueInto(HttpScc * scc, Packer * p); static void httpSccJoinWith(HttpScc * scc, HttpScc * new_scc); +#endif static HttpHeaderExtField *httpHeaderExtFieldCreate(const char *name, const char *value); static HttpHeaderExtField *httpHeaderExtFieldParseCreate(const char *field_start, const char *field_end); static void httpHeaderExtFieldDestroy(HttpHeaderExtField * f); static HttpHeaderExtField *httpHeaderExtFieldDup(HttpHeaderExtField * f); +static void httpHeaderStatInit(HttpHeaderStat * hs, const char *label); static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e); static void shortStringStatDump(StoreEntry * e); @@ -298,13 +250,12 @@ static char *appShortStr(char *str, const char *app_str); static char *allocShortBuf(size_t size); static void freeShortString(char *str); +#if 0 static int strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos); static const char *getStringPrefix(const char *str); +#endif -/* delete this when everybody remembers that ':' is not a part of a name */ -#define conversion_period_name_check(name) assert(!strchr((name), ':')) - /* handy to determine the #elements in a static array */ #define countof(arr) (sizeof(arr)/sizeof(*arr)) @@ -328,7 +279,6 @@ httpHeaderInitModule() assert(sizeof(field_store) == sizeof(char *)); /* have to force removal of const here */ httpHeaderInitAttrTable((field_attrs_t *) Headers, countof(Headers)); - httpHeaderInitAttrTable((field_attrs_t *) SccAttrs, countof(SccAttrs)); /* create masks */ ListHeadersMask = httpHeaderCalcMask((const int *) ListHeaders, countof(ListHeaders)); ReplyHeadersMask = httpHeaderCalcMask((const int *) ReplyHeaders, countof(ReplyHeaders)); @@ -338,6 +288,7 @@ httpHeaderInitModule() /* init header stats */ for (i = 0; i < HttpHeaderStatCount; i++) httpHeaderStatInit(HttpHeaderStats + i, HttpHeaderStats[i].label); + httpHdrCcInitModule(); cachemgrRegister("http_headers", "HTTP Header Statistics", httpHeaderStoreReport, 0); } @@ -351,38 +302,6 @@ httpHeaderCleanModule() } } -static void -httpHeaderInitAttrTable(field_attrs_t * table, int count) -{ - int i; - assert(table); - assert(count > 1); /* to protect from buggy "countof" implementations */ - - /* reorder so that .id becomes an index */ - for (i = 0; i < count;) { - const int id = table[i].id; - assert(id >= 0 && id < count); /* sanity check */ - assert(id >= i); /* entries prior to i have been indexed already */ - if (id != i) { /* out of order */ - const field_attrs_t fa = table[id]; - assert(fa.id != id); /* avoid endless loops */ - table[id] = table[i]; /* swap */ - table[i] = fa; - } else - i++; /* make progress */ - } - - /* calculate name lengths and init stats */ - for (i = 0; i < count; ++i) { - assert(table[i].name); - table[i].name_len = strlen(table[i].name); - debug(55, 5) ("hdr table entry[%d]: %s (%d)\n", i, table[i].name, table[i].name_len); - assert(table[i].name_len); - /* init stats */ - memset(&table[i].stat, 0, sizeof(table[i].stat)); - } -} - static void httpHeaderStatInit(HttpHeaderStat * hs, const char *label) { @@ -391,27 +310,9 @@ httpHeaderStatInit(HttpHeaderStat * hs, const char *label) hs->label = label; statHistEnumInit(&hs->hdrUCountDistr, 32); /* not a real enum */ statHistEnumInit(&hs->fieldTypeDistr, HDR_ENUM_END); - statHistEnumInit(&hs->ccTypeDistr, SCC_ENUM_END); -} - -/* calculates a bit mask of a given array (move this to lib/uitils) @?@ */ -static int -httpHeaderCalcMask(const int *enums, int count) -{ - int i; - int mask = 0; - assert(enums); - assert(count < sizeof(int) * 8); /* check for overflow */ - - for (i = 0; i < count; ++i) { - assert(enums[i] < sizeof(int) * 8); /* check for overflow again */ - assert(!EBIT_TEST(mask, enums[i])); /* check for duplicates */ - EBIT_SET(mask, enums[i]); - } - return mask; + statHistEnumInit(&hs->ccTypeDistr, CC_ENUM_END); } - /* * HttpHeader Implementation */ @@ -448,7 +349,7 @@ httpHeaderClean(HttpHeader * hdr) /* fix this (for scc too) for req headers @?@ */ statHistCount(&HttpHeaderStats[0].fieldTypeDistr, e->id); if (e->id == HDR_CACHE_CONTROL) - httpSccUpdateStats(e->field.v_pscc, &HttpHeaderStats[0].ccTypeDistr); + httpHdrCcUpdateStats(e->field.v_pcc, &HttpHeaderStats[0].ccTypeDistr); httpHeaderDelAt(hdr, pos); } xfree(hdr->entries); @@ -883,10 +784,10 @@ httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id) return httpHeaderGet(hdr, id).v_time; } -HttpScc * -httpHeaderGetScc(const HttpHeader * hdr) +HttpHdrCc * +httpHeaderGetCc(const HttpHeader * hdr) { - return httpHeaderGet(hdr, HDR_CACHE_CONTROL).v_pscc; + return httpHeaderGet(hdr, HDR_CACHE_CONTROL).v_pcc; } /* updates header masks */ @@ -906,22 +807,6 @@ httpHeaderSyncMasks(HttpHeader * hdr, const HttpHeaderEntry * e, int add) add ? EBIT_SET(hdr->emask, e->id) : EBIT_CLR(hdr->emask, e->id); } -static int -httpHeaderIdByName(const char *name, int name_len, const field_attrs_t * attrs, int end, int mask) -{ - int i; - for (i = 0; i < end; ++i) { - if (mask < 0 || EBIT_TEST(mask, i)) { - if (name_len >= 0 && name_len != attrs[i].name_len) - continue; - if (!strncasecmp(name, attrs[i].name, - name_len < 0 ? attrs[i].name_len + 1 : name_len)) - return i; - } - } - return -1; -} - /* doubles the size of the fields index, starts with INIT_FIELDS_PER_HEADER */ static void httpHeaderGrow(HttpHeader * hdr) @@ -971,8 +856,8 @@ httpHeaderEntryClean(HttpHeaderEntry * e) freeShortString(e->field.v_pchar); break; case ftPSCC: - if (e->field.v_pscc) - httpSccDestroy(e->field.v_pscc); + if (e->field.v_pcc) + httpHdrCcDestroy(e->field.v_pcc); break; case ftPExtField: if (e->field.v_pefield) @@ -1101,8 +986,8 @@ httpHeaderEntryParseByTypeInit(HttpHeaderEntry * e, int id, const HttpHeaderExtF break; case ftPSCC: - field.v_pscc = httpSccParseCreate(f->value); - if (!field.v_pscc) { + field.v_pcc = httpHdrCcParseCreate(f->value); + if (!field.v_pcc) { debug(55, 0) ("failed to parse scc hdr: id: %d, field: '%s: %s'\n", id, f->name, f->value); Headers[id].stat.errCount++; @@ -1174,7 +1059,7 @@ httpHeaderEntryPackByType(const HttpHeaderEntry * e, Packer * p) packerPrintf(p, "%s", mkrfc1123(e->field.v_time)); break; case ftPSCC: - httpSccPackValueInto(e->field.v_pscc, p); + httpHdrCcPackValueInto(e->field.v_pcc, p); break; case ftPExtField: packerPrintf(p, "%s", e->field.v_pefield->value); @@ -1200,7 +1085,7 @@ httpHeaderEntryJoinWith(HttpHeaderEntry * e, const HttpHeaderEntry * newe) e->field.v_pchar = appShortStr(e->field.v_pchar, newe->field.v_pchar); break; case ftPSCC: - httpSccJoinWith(e->field.v_pscc, newe->field.v_pscc); + httpHdrCcJoinWith(e->field.v_pcc, newe->field.v_pcc); break; default: debug(55, 0) ("join for invalid/unknown type: id: %d, type: %d\n", e->id, type); @@ -1227,7 +1112,7 @@ httpHeaderEntryIsValid(const HttpHeaderEntry * e) case ftDate_1123: return e->field.v_time >= 0; case ftPSCC: - return e->field.v_pscc != NULL; + return e->field.v_pcc != NULL; case ftPExtField: return e->field.v_pefield != NULL; default: @@ -1268,7 +1153,7 @@ httpHeaderFieldDup(field_type type, field_store value) case ftPChar: return ptrField(dupShortStr(value.v_pchar)); case ftPSCC: - return ptrField(httpSccDup(value.v_pscc)); + return ptrField(httpHdrCcDup(value.v_pcc)); case ftPExtField: return ptrField(httpHeaderExtFieldDup(value.v_pefield)); default: @@ -1300,6 +1185,8 @@ httpHeaderFieldBadValue(field_type type) return ptrField(NULL); /* not reached */ } +#if 0 /* moved to HttpHdrCC.c */ + /* * HttpScc (server cache control) */ @@ -1426,6 +1313,8 @@ httpSccUpdateStats(const HttpScc * scc, StatHist * hist) statHistCount(hist, c); } +#endif + /* * HttpHeaderExtField */ @@ -1501,6 +1390,7 @@ httpHeaderFieldStatDumper(StoreEntry * sentry, int idx, double val, double size, id, name, count, xdiv(count, HeaderParsedCount)); } +#if 0 static void httpHeaderCCStatDumper(StoreEntry * sentry, int idx, double val, double size, int count) { @@ -1511,7 +1401,7 @@ httpHeaderCCStatDumper(StoreEntry * sentry, int idx, double val, double size, in storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n", id, name, count, xdiv(count, CcPasredCount)); } - +#endif static void httpHeaderFldsPerHdrDumper(StoreEntry * sentry, int idx, double val, double size, int count) @@ -1535,7 +1425,7 @@ httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e) storeAppendPrintf(e, "

Cache-control directives distribution

\n"); storeAppendPrintf(e, "%2s\t %-20s\t %5s\t %6s\n", "id", "name", "count", "#/cc_field"); - statHistDump(&hs->ccTypeDistr, e, httpHeaderCCStatDumper); + statHistDump(&hs->ccTypeDistr, e, httpHdrCcStatDumper); storeAppendPrintf(e, "

Number of fields per header distribution (init size: %d)

\n", INIT_FIELDS_PER_HEADER); storeAppendPrintf(e, "%2s\t %-5s\t %5s\t %6s\n", @@ -1655,6 +1545,7 @@ freeShortString(char *str) } } +#if 0 /* * other routines (move these into lib if you need them somewhere else?) */ @@ -1705,3 +1596,4 @@ getStringPrefix(const char *str) xstrncpy(buf, str, SHORT_PREFIX_SIZE); return buf; } +#endif diff --git a/src/HttpHeaderTools.cc b/src/HttpHeaderTools.cc new file mode 100644 index 0000000000..7cf32c0562 --- /dev/null +++ b/src/HttpHeaderTools.cc @@ -0,0 +1,144 @@ +/* + * $Id: HttpHeaderTools.cc,v 1.1 1998/03/05 00:01:08 rousskov Exp $ + * + * DEBUG: section 66 HTTP Header Tools + * 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. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "squid.h" + +void +httpHeaderInitAttrTable(field_attrs_t * table, int count) +{ + int i; + assert(table); + assert(count > 1); /* to protect from buggy "countof" implementations */ + + /* reorder so that .id becomes an index */ + for (i = 0; i < count;) { + const int id = table[i].id; + assert(id >= 0 && id < count); /* sanity check */ + assert(id >= i); /* entries prior to i have been indexed already */ + if (id != i) { /* out of order */ + const field_attrs_t fa = table[id]; + assert(fa.id != id); /* avoid endless loops */ + table[id] = table[i]; /* swap */ + table[i] = fa; + } else + i++; /* make progress */ + } + + /* calculate name lengths and init stats */ + for (i = 0; i < count; ++i) { + assert(table[i].name); + table[i].name_len = strlen(table[i].name); + debug(55, 5) ("hdr table entry[%d]: %s (%d)\n", i, table[i].name, table[i].name_len); + assert(table[i].name_len); + /* init stats */ + memset(&table[i].stat, 0, sizeof(table[i].stat)); + } +} + +/* calculates a bit mask of a given array */ +int +httpHeaderCalcMask(const int *enums, int count) +{ + int i; + int mask = 0; + assert(enums); + assert(count < sizeof(int) * 8); /* check for overflow */ + + for (i = 0; i < count; ++i) { + assert(enums[i] < sizeof(int) * 8); /* check for overflow again */ + assert(!EBIT_TEST(mask, enums[i])); /* check for duplicates */ + EBIT_SET(mask, enums[i]); + } + return mask; +} + + +int +httpHeaderIdByName(const char *name, int name_len, const field_attrs_t * attrs, int end, int mask) +{ + int i; + for (i = 0; i < end; ++i) { + if (mask < 0 || EBIT_TEST(mask, i)) { + if (name_len >= 0 && name_len != attrs[i].name_len) + continue; + if (!strncasecmp(name, attrs[i].name, + name_len < 0 ? attrs[i].name_len + 1 : name_len)) + return i; + } + } + return -1; +} + +/* + * iterates through a 0-terminated string of items separated by 'del's. + * white space around 'del' is considered to be a part of 'del' + * like strtok, but preserves the source, and can iterate several strings at once + * + * returns true if next item is found. + * init pos with NULL to start iteration. + */ +int +strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos) +{ + size_t len; + assert(str && item && pos); + if (*pos) + if (!**pos) /* end of string */ + return 0; + else + (*pos)++; + else + *pos = str; + + /* skip leading ws (ltrim) */ + *pos += xcountws(*pos); + *item = *pos; /* remember item's start */ + /* find next delimiter */ + *pos = strchr(*item, del); + if (!*pos) /* last item */ + *pos = *item + strlen(*item); + len = *pos - *item; /* *pos points to del or '\0' */ + /* rtrim */ + while (len > 0 && isspace((*item)[len - 1])) + len--; + if (ilen) + *ilen = len; + return len > 0; +} + +/* handy to printf prefixes of potentially very long buffers */ +const char * +getStringPrefix(const char *str) +{ +#define SHORT_PREFIX_SIZE 256 + LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE); + xstrncpy(buf, str, SHORT_PREFIX_SIZE); + return buf; +} diff --git a/src/HttpReply.cc b/src/HttpReply.cc index 6efd533a1b..5a0d9b87e7 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -1,6 +1,6 @@ /* - * $Id: HttpReply.cc,v 1.9 1998/03/04 05:39:27 rousskov Exp $ + * $Id: HttpReply.cc,v 1.10 1998/03/05 00:01:08 rousskov Exp $ * * DEBUG: section 58 HTTP Reply (Response) * AUTHOR: Alex Rousskov @@ -295,28 +295,28 @@ httpReplyContentType(const HttpReply * rep) time_t httpReplyExpires(const HttpReply * rep) { - HttpScc *scc; + HttpHdrCc *cc; time_t exp = -1; assert(rep); /* The max-age directive takes priority over Expires, check it first */ - scc = httpHeaderGetScc(&rep->hdr); - if (scc) - exp = scc->max_age; + cc = httpHeaderGetCc(&rep->hdr); + if (cc) + exp = cc->max_age; if (exp < 0) exp = httpHeaderGetTime(&rep->hdr, HDR_EXPIRES); return exp; } int -httpReplyHasScc(const HttpReply * rep, http_scc_type type) +httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type) { - HttpScc *scc; + HttpHdrCc *cc; assert(rep); - assert(type >= 0 && type < SCC_ENUM_END); + assert(type >= 0 && type < CC_ENUM_END); - scc = httpHeaderGetScc(&rep->hdr); - return scc && /* scc header is present */ - EBIT_TEST(scc->mask, type); + cc = httpHeaderGetCc(&rep->hdr); + return cc && /* scc header is present */ + EBIT_TEST(cc->mask, type); } diff --git a/src/Makefile.in b/src/Makefile.in index 52fcbf9e8f..8ef7e82231 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.126 1998/03/03 00:31:00 rousskov Exp $ +# $Id: Makefile.in,v 1.127 1998/03/05 00:01:09 rousskov Exp $ # # Uncomment and customize the following to suit your needs: # @@ -90,7 +90,9 @@ OBJS = \ http.o \ http-anon.o \ HttpStatusLine.o \ + HttpHdrCc.o \ HttpHeader.o \ + HttpHeaderTools.o \ HttpBody.o \ HttpReply.o \ icmp.o \ diff --git a/src/defines.h b/src/defines.h index 9f7c3dfc14..9595fe3f69 100644 --- a/src/defines.h +++ b/src/defines.h @@ -209,3 +209,7 @@ /* were to look for errors if config path fails */ #define DEFAULT_SQUID_ERROR_DIR "/usr/local/squid/etc/errors" + +/* gb_type operations */ +#define gb_flush_limit (0x3FFFFFFF) +#define gb_inc(gb, delta) { if ((gb)->bytes > gb_flush_limit || delta > gb_flush_limit) gb_flush(gb); (gb)->bytes += delta; (gb)->count++; } diff --git a/src/enums.h b/src/enums.h index fce7dd65e9..e94974b4e3 100644 --- a/src/enums.h +++ b/src/enums.h @@ -194,16 +194,26 @@ typedef enum { /* server cache-control */ typedef enum { - SCC_PUBLIC, - SCC_PRIVATE, - SCC_NO_CACHE, - SCC_NO_STORE, - SCC_NO_TRANSFORM, - SCC_MUST_REVALIDATE, - SCC_PROXY_REVALIDATE, - SCC_MAX_AGE, - SCC_ENUM_END -} http_scc_type; + CC_PUBLIC, + CC_PRIVATE, + CC_NO_CACHE, + CC_NO_STORE, + CC_NO_TRANSFORM, + CC_MUST_REVALIDATE, + CC_PROXY_REVALIDATE, + CC_MAX_AGE, + CC_ENUM_END +} http_hdr_cc_type; + +/* possible types for http header fields */ +typedef enum { + ftInvalid = HDR_ENUM_END, /* to catch nasty errors with hdr_id<->fld_type clashes */ + ftInt, + ftPChar, + ftDate_1123, + ftPSCC, + ftPExtField +} field_type; typedef enum { HIER_NONE, @@ -464,7 +474,7 @@ typedef enum { #else MEM_HTTPREPLY, #endif - MEM_HTTP_SCC, + MEM_HTTP_HDR_CC, MEM_HTTPSTATEDATA, MEM_ICPUDPDATA, MEM_CLIENTHTTPREQUEST, diff --git a/src/http.cc b/src/http.cc index 3be3fefe50..cb2f07655a 100644 --- a/src/http.cc +++ b/src/http.cc @@ -1,6 +1,6 @@ /* - * $Id: http.cc,v 1.244 1998/03/04 23:52:40 wessels Exp $ + * $Id: http.cc,v 1.245 1998/03/05 00:01:11 rousskov Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -435,14 +435,14 @@ static int httpCachableReply(HttpStateData * httpState) { HttpHeader *hdr = &httpState->entry->mem_obj->reply->hdr; - const HttpScc *scc = httpHeaderGetScc(hdr); - const int scc_mask = (scc) ? scc->mask : 0; - if (EBIT_TEST(scc_mask, SCC_PRIVATE)) + const HttpHdrCc *cc = httpHeaderGetCc(hdr); + const int cc_mask = (cc) ? cc->mask : 0; + if (EBIT_TEST(cc_mask, CC_PRIVATE)) return 0; - if (EBIT_TEST(scc_mask, SCC_NO_CACHE)) + if (EBIT_TEST(cc_mask, CC_NO_CACHE)) return 0; if (EBIT_TEST(httpState->request->flags, REQ_AUTH)) - if (!EBIT_TEST(scc_mask, SCC_PROXY_REVALIDATE)) + if (!EBIT_TEST(cc_mask, CC_PROXY_REVALIDATE)) return 0; /* * Dealing with cookies is quite a bit more complicated @@ -572,7 +572,7 @@ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size) assert(0); break; } - if (httpReplyHasScc(reply, SCC_PROXY_REVALIDATE)) + if (httpReplyHasCc(reply, CC_PROXY_REVALIDATE)) EBIT_SET(entry->flag, ENTRY_REVALIDATE); if (EBIT_TEST(httpState->flags, HTTP_KEEPALIVE)) if (httpState->peer) @@ -1159,7 +1159,7 @@ httpReplyHeaderStats(StoreEntry * entry) storeAppendPrintf(entry, "%21.21s: %d\n", HttpHdrMiscStr[j], ReplyHeaderStats.misc[j]); - for (i = SCC_PUBLIC; i < SCC_ENUM_END; i++) + for (i = CC_PUBLIC; i < CC_ENUM_END; i++) storeAppendPrintf(entry, "Cache-Control %s: %d\n", HttpServerCCStr[i], ReplyHeaderStats.cc[i]); diff --git a/src/mem.cc b/src/mem.cc index d13d394e26..4c7fee3866 100644 --- a/src/mem.cc +++ b/src/mem.cc @@ -1,6 +1,6 @@ /* - * $Id: mem.cc,v 1.9 1998/03/03 22:17:54 rousskov Exp $ + * $Id: mem.cc,v 1.10 1998/03/05 00:01:11 rousskov Exp $ * * DEBUG: section 13 High Level Memory Pool Management * AUTHOR: Harvest Derived @@ -35,7 +35,7 @@ static MemPool *MemPools[MEM_MAX]; -/* all pools share common memory chunks so it is probably better to ignore max_pages */ +/* we have a limit on _total_ amount of idle memory so we ignore max_pages for now */ static void memDataInit(mem_type type, const char *name, size_t size, int max_pages_notused) { @@ -126,7 +126,7 @@ memInit(void) sizeof(HierarchyLogEntry), 0); memDataInit(MEM_HTTPSTATEDATA, "HttpStateData", sizeof(HttpStateData), 0); memDataInit(MEM_HTTPREPLY, "http_reply", sizeof(http_reply), 0); - memDataInit(MEM_HTTP_SCC, "HttpScc", sizeof(HttpScc), 0); + memDataInit(MEM_HTTP_HDR_CC, "HttpHdrCc", sizeof(HttpHdrCc), 0); memDataInit(MEM_ICPUDPDATA, "icpUdpData", sizeof(icpUdpData), 0); memDataInit(MEM_ICP_COMMON_T, "icp_common_t", sizeof(icp_common_t), 0); memDataInit(MEM_ICP_PING_DATA, "icp_ping_data", sizeof(icp_ping_data), 0); diff --git a/src/protos.h b/src/protos.h index d218e06544..19fb42a262 100644 --- a/src/protos.h +++ b/src/protos.h @@ -257,6 +257,25 @@ extern void httpBodySet(HttpBody * body, const char *content, int size, extern void httpBodyPackInto(const HttpBody * body, Packer * p); +/* Http Cache Control Header Field */ +extern void httpHdrCcInitModule(); +extern HttpHdrCc *httpHdrCcCreate(); +extern HttpHdrCc *httpHdrCcParseCreate(const char *str); +extern void httpHdrCcParseInit(HttpHdrCc * scc, const char *str); +extern void httpHdrCcDestroy(HttpHdrCc * scc); +extern HttpHdrCc *httpHdrCcDup(HttpHdrCc * scc); +extern void httpHdrCcPackValueInto(HttpHdrCc * scc, Packer * p); +extern void httpHdrCcJoinWith(HttpHdrCc * scc, HttpHdrCc * new_scc); +extern void httpHdrCcUpdateStats(const HttpHdrCc * scc, StatHist * hist); +extern void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count); + +/* Http Header Tools */ +extern int httpHeaderIdByName(const char *name, int name_len, const field_attrs_t * attrs, int end, int mask); +extern void httpHeaderInitAttrTable(field_attrs_t * table, int count); +extern int httpHeaderCalcMask(const int *enums, int count); +extern int strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos); +extern const char *getStringPrefix(const char *str); + /* Http Header */ extern void httpHeaderInitModule(); extern void httpHeaderCleanModule(); @@ -280,8 +299,8 @@ extern void httpHeaderSetAuth(HttpHeader * hdr, const char *authScheme, const ch extern void httpHeaderAddExt(HttpHeader * hdr, const char *name, const char *value); extern int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id); extern time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id); +extern HttpHdrCc *httpHeaderGetCc(const HttpHeader * hdr); extern const char *httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id); -extern HttpScc *httpHeaderGetScc(const HttpHeader * hdr); int httpHeaderDelFields(HttpHeader * hdr, const char *name); /* store report about current header usage and other stats */ extern void httpHeaderStoreReport(StoreEntry * e); @@ -317,7 +336,7 @@ extern void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep); extern int httpReplyContentLen(const HttpReply * rep); extern const char *httpReplyContentType(const HttpReply * rep); extern time_t httpReplyExpires(const HttpReply * rep); -extern int httpReplyHasScc(const HttpReply * rep, http_scc_type type); +extern int httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type); extern void icmpOpen(void); @@ -787,6 +806,9 @@ extern void asnFreeMemory(void); extern void dlinkAdd(void *data, dlink_node *, dlink_list *); extern void dlinkDelete(dlink_node * m, dlink_list * list); extern void kb_incr(kb_t *, size_t); +extern double gb_to_double(const gb_t *); +extern const char *gb_to_str(const gb_t *); +extern void gb_flush(gb_t *); /* internal, do not use this */ /* * prototypes for system functions missing from system includes diff --git a/src/structs.h b/src/structs.h index 16141dd4d6..23cfc73755 100644 --- a/src/structs.h +++ b/src/structs.h @@ -465,22 +465,41 @@ struct _HttpBody { }; -/* server cache control */ -struct _HttpScc { +/* http cache control header field*/ +struct _HttpHdrCc { int mask; time_t max_age; }; + /* a storage for an entry of one of possible types (for lower level routines) */ union _field_store { int v_int; time_t v_time; char *v_pchar; const char *v_pcchar; - HttpScc *v_pscc; + HttpHdrCc *v_pcc; HttpHeaderExtField *v_pefield; }; +/* per field statistics */ +struct _HttpHeaderFieldStat { + int aliveCount; /* created but not destroyed (count) */ + int parsCount; /* #parsing attempts */ + int errCount; /* #pasring errors */ + int repCount; /* #repetitons */ +}; + + +/* constant attributes of http header fields */ +struct _field_attrs_t { + const char *name; + http_hdr_type id; + field_type type; + int name_len; + HttpHeaderFieldStat stat; +}; + struct _HttpHeader { /* public, read only */ int emask; /* bits set for present entries */ diff --git a/src/typedefs.h b/src/typedefs.h index 3fdf0158c8..e4db68fb88 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -9,6 +9,12 @@ typedef struct { size_t kb; } kb_t; +typedef struct { + size_t count; + size_t bytes; + size_t gb; +} gb_t; + /* * grep '^struct' structs.h \ * | perl -ne '($a,$b)=split;$c=$b;$c=~s/^_//; print "typedef struct $b $c;\n";' @@ -42,19 +48,17 @@ typedef struct _fileMap fileMap; typedef struct _fqdncache_entry fqdncache_entry; typedef struct _hash_link hash_link; typedef struct _hash_table hash_table; -#if 0 /* use new interfaces */ -typedef struct _http_reply http_reply; -#else typedef struct _HttpReply http_reply; typedef struct _HttpStatusLine HttpStatusLine; +typedef struct _field_attrs_t field_attrs_t; typedef struct _HttpHeader HttpHeader; -typedef struct _HttpScc HttpScc; +typedef struct _HttpHdrCc HttpHdrCc; typedef struct _HttpHeaderExtField HttpHeaderExtField; typedef struct _HttpHeaderEntry HttpHeaderEntry; -typedef union _field_store field_store; +typedef struct _HttpHeaderFieldStat HttpHeaderFieldStat; +typedef union _field_store field_store; typedef struct _HttpBody HttpBody; typedef struct _HttpReply HttpReply; -#endif typedef struct _HttpStateData HttpStateData; typedef struct _icpUdpData icpUdpData; typedef struct _clientHttpRequest clientHttpRequest;