HttpHeaderTools.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:10k
- /*
- * $Id: HttpHeaderTools.c,v 1.24.2.1 1999/02/12 19:38:19 wessels 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. 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"
- static int httpHeaderStrCmp(const char *h1, const char *h2, int len);
- static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs);
- HttpHeaderFieldInfo *
- httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count)
- {
- int i;
- HttpHeaderFieldInfo *table = NULL;
- assert(attrs && count);
- /* allocate space */
- table = xcalloc(count, sizeof(HttpHeaderFieldInfo));
- for (i = 0; i < count; ++i) {
- const int id = attrs[i].id;
- HttpHeaderFieldInfo *info = table + id;
- /* sanity checks */
- assert(id >= 0 && id < count);
- assert(attrs[i].name);
- assert(info->id == 0 && info->type == 0); /* was not set before */
- /* copy and init fields */
- info->id = id;
- info->type = attrs[i].type;
- stringInit(&info->name, attrs[i].name);
- assert(strLen(info->name));
- /* init stats */
- memset(&info->stat, 0, sizeof(info->stat));
- }
- return table;
- }
- void
- httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * table, int count)
- {
- int i;
- for (i = 0; i < count; ++i)
- stringClean(&table[i].name);
- xfree(table);
- }
- void
- httpHeaderMaskInit(HttpHeaderMask * mask, int value)
- {
- memset(mask, value, sizeof(*mask));
- }
- /* calculates a bit mask of a given array; does not reset mask! */
- void
- httpHeaderCalcMask(HttpHeaderMask * mask, const int *enums, int count)
- {
- int i;
- assert(mask && enums);
- assert(count < sizeof(*mask) * 8); /* check for overflow */
- for (i = 0; i < count; ++i) {
- assert(!CBIT_TEST(*mask, enums[i])); /* check for duplicates */
- CBIT_SET(*mask, enums[i]);
- }
- }
- /* same as httpHeaderPutStr, but formats the string using snprintf first */
- #if STDC_HEADERS
- void
- httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt,...)
- {
- va_list args;
- va_start(args, fmt);
- #else
- void
- httpHeaderPutStrf(va_alist)
- va_dcl
- {
- va_list args;
- HttpHeader *hdr = NULL;
- http_hdr_type id = HDR_ENUM_END;
- const char *fmt = NULL;
- va_start(args);
- hdr = va_arg(args, HttpHeader *);
- id = va_arg(args, http_hdr_type);
- fmt = va_arg(args, char *);
- #endif
- httpHeaderPutStrvf(hdr, id, fmt, args);
- va_end(args);
- }
- /* used by httpHeaderPutStrf */
- static void
- httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs)
- {
- MemBuf mb;
- memBufDefInit(&mb);
- memBufVPrintf(&mb, fmt, vargs);
- httpHeaderPutStr(hdr, id, mb.buf);
- memBufClean(&mb);
- }
- /* wrapper arrounf PutContRange */
- void
- httpHeaderAddContRange(HttpHeader * hdr, HttpHdrRangeSpec spec, size_t ent_len)
- {
- HttpHdrContRange *cr = httpHdrContRangeCreate();
- assert(hdr && ent_len >= 0);
- httpHdrContRangeSet(cr, spec, ent_len);
- httpHeaderPutContRange(hdr, cr);
- httpHdrContRangeDestroy(cr);
- }
- /*
- * return true if a given directive is found in at least one of the "connection" header-fields
- * note: if HDR_PROXY_CONNECTION is present we ignore HDR_CONNECTION
- */
- int
- httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive)
- {
- if (httpHeaderHas(hdr, HDR_PROXY_CONNECTION)) {
- const char *str = httpHeaderGetStr(hdr, HDR_PROXY_CONNECTION);
- return str && !strcasecmp(str, directive);
- }
- if (httpHeaderHas(hdr, HDR_CONNECTION)) {
- String str = httpHeaderGetList(hdr, HDR_CONNECTION);
- const int res = strListIsMember(&str, directive, ',');
- stringClean(&str);
- return res;
- }
- return 0;
- }
- /* returns true iff "m" is a member of the list */
- int
- strListIsMember(const String * list, const char *m, char del)
- {
- const char *pos = NULL;
- const char *item;
- assert(list && m);
- while (strListGetItem(list, del, &item, NULL, &pos)) {
- if (!strcasecmp(item, m))
- return 1;
- }
- return 0;
- }
- /* returns true iff "s" is a substring of a member of the list */
- int
- strListIsSubstr(const String * list, const char *s, char del)
- {
- const char *pos = NULL;
- const char *item;
- assert(list && s);
- while (strListGetItem(list, del, &item, NULL, &pos)) {
- if (strstr(item, s))
- return 1;
- }
- return 0;
- }
- /* appends an item to the list */
- void
- strListAdd(String * str, const char *item, char del)
- {
- assert(str && item);
- if (strLen(*str)) {
- char buf[3];
- buf[0] = del;
- buf[1] = ' ';
- buf[2] = ' ';
- stringAppend(str, buf, 2);
- }
- stringAppend(str, item, strlen(item));
- }
- /*
- * 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 String * 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 = strBuf(*str);
- if (!*pos)
- return 0;
- }
- /* 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 ' ' */
- /* rtrim */
- while (len > 0 && xisspace((*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, const char *end)
- {
- #define SHORT_PREFIX_SIZE 512
- LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE);
- const int sz = 1 + (end ? end - str : strlen(str));
- xstrncpy(buf, str, (sz > SHORT_PREFIX_SIZE) ? SHORT_PREFIX_SIZE : sz);
- return buf;
- }
- /*
- * parses an int field, complains if soemthing went wrong, returns true on
- * success
- */
- int
- httpHeaderParseInt(const char *start, int *value)
- {
- assert(value);
- *value = atoi(start);
- if (!*value && !xisdigit(*start)) {
- debug(66, 2) ("failed to parse an int header field near '%s'n", start);
- return 0;
- }
- return 1;
- }
- int
- httpHeaderParseSize(const char *start, size_t * value)
- {
- int v;
- const int res = httpHeaderParseInt(start, &v);
- assert(value);
- *value = res ? v : 0;
- return res;
- }
- /*
- * parses a given string then packs compiled headers and compares the result
- * with the original, reports discrepancies
- */
- void
- httpHeaderTestParser(const char *hstr)
- {
- static int bug_count = 0;
- int hstr_len;
- int parse_success;
- HttpHeader hdr;
- int pos;
- Packer p;
- MemBuf mb;
- assert(hstr);
- /* skip start line if any */
- if (!strncasecmp(hstr, "HTTP/", 5)) {
- const char *p = strchr(hstr, 'n');
- if (p)
- hstr = p + 1;
- }
- /* skip invalid first line if any */
- if (xisspace(*hstr)) {
- const char *p = strchr(hstr, 'n');
- if (p)
- hstr = p + 1;
- }
- hstr_len = strlen(hstr);
- /* skip terminator if any */
- if (strstr(hstr, "nrn"))
- hstr_len -= 2;
- else if (strstr(hstr, "nn"))
- hstr_len -= 1;
- httpHeaderInit(&hdr, hoReply);
- /* debugLevels[55] = 8; */
- parse_success = httpHeaderParse(&hdr, hstr, hstr + hstr_len);
- /* debugLevels[55] = 2; */
- if (!parse_success) {
- debug(66, 2) ("TEST (%d): failed to parsed a header: {n%s}n", bug_count, hstr);
- return;
- }
- /* we think that we parsed it, veryfy */
- memBufDefInit(&mb);
- packerToMemInit(&p, &mb);
- httpHeaderPackInto(&hdr, &p);
- if ((pos = abs(httpHeaderStrCmp(hstr, mb.buf, hstr_len)))) {
- bug_count++;
- debug(66, 2) ("TEST (%d): hdr parsing bug (pos: %d near '%s'): expected: {n%s} got: {n%s}n",
- bug_count, pos, hstr + pos, hstr, mb.buf);
- }
- httpHeaderClean(&hdr);
- packerClean(&p);
- memBufClean(&mb);
- }
- /* like strncasecmp but ignores ws characters */
- static int
- httpHeaderStrCmp(const char *h1, const char *h2, int len)
- {
- int len1 = 0;
- int len2 = 0;
- assert(h1 && h2);
- /* fast check first */
- if (!strncasecmp(h1, h2, len))
- return 0;
- while (1) {
- const char c1 = xtoupper(h1[len1 += xcountws(h1 + len1)]);
- const char c2 = xtoupper(h2[len2 += xcountws(h2 + len2)]);
- if (c1 < c2)
- return -len1;
- if (c1 > c2)
- return +len1;
- if (!c1 && !c2)
- return 0;
- if (c1)
- len1++;
- if (c2)
- len2++;
- }
- return 0;
- }