HttpHeaderTools.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: HttpHeaderTools.c,v 1.24.2.1 1999/02/12 19:38:19 wessels Exp $
  3.  *
  4.  * DEBUG: section 66    HTTP Header Tools
  5.  * AUTHOR: Alex Rousskov
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. static int httpHeaderStrCmp(const char *h1, const char *h2, int len);
  36. static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs);
  37. HttpHeaderFieldInfo *
  38. httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count)
  39. {
  40.     int i;
  41.     HttpHeaderFieldInfo *table = NULL;
  42.     assert(attrs && count);
  43.     /* allocate space */
  44.     table = xcalloc(count, sizeof(HttpHeaderFieldInfo));
  45.     for (i = 0; i < count; ++i) {
  46. const int id = attrs[i].id;
  47. HttpHeaderFieldInfo *info = table + id;
  48. /* sanity checks */
  49. assert(id >= 0 && id < count);
  50. assert(attrs[i].name);
  51. assert(info->id == 0 && info->type == 0); /* was not set before */
  52. /* copy and init fields */
  53. info->id = id;
  54. info->type = attrs[i].type;
  55. stringInit(&info->name, attrs[i].name);
  56. assert(strLen(info->name));
  57. /* init stats */
  58. memset(&info->stat, 0, sizeof(info->stat));
  59.     }
  60.     return table;
  61. }
  62. void
  63. httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * table, int count)
  64. {
  65.     int i;
  66.     for (i = 0; i < count; ++i)
  67. stringClean(&table[i].name);
  68.     xfree(table);
  69. }
  70. void
  71. httpHeaderMaskInit(HttpHeaderMask * mask, int value)
  72. {
  73.     memset(mask, value, sizeof(*mask));
  74. }
  75. /* calculates a bit mask of a given array; does not reset mask! */
  76. void
  77. httpHeaderCalcMask(HttpHeaderMask * mask, const int *enums, int count)
  78. {
  79.     int i;
  80.     assert(mask && enums);
  81.     assert(count < sizeof(*mask) * 8); /* check for overflow */
  82.     for (i = 0; i < count; ++i) {
  83. assert(!CBIT_TEST(*mask, enums[i])); /* check for duplicates */
  84. CBIT_SET(*mask, enums[i]);
  85.     }
  86. }
  87. /* same as httpHeaderPutStr, but formats the string using snprintf first */
  88. #if STDC_HEADERS
  89. void
  90. httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt,...)
  91. {
  92.     va_list args;
  93.     va_start(args, fmt);
  94. #else
  95. void
  96. httpHeaderPutStrf(va_alist)
  97.      va_dcl
  98. {
  99.     va_list args;
  100.     HttpHeader *hdr = NULL;
  101.     http_hdr_type id = HDR_ENUM_END;
  102.     const char *fmt = NULL;
  103.     va_start(args);
  104.     hdr = va_arg(args, HttpHeader *);
  105.     id = va_arg(args, http_hdr_type);
  106.     fmt = va_arg(args, char *);
  107. #endif
  108.     httpHeaderPutStrvf(hdr, id, fmt, args);
  109.     va_end(args);
  110. }
  111. /* used by httpHeaderPutStrf */
  112. static void
  113. httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs)
  114. {
  115.     MemBuf mb;
  116.     memBufDefInit(&mb);
  117.     memBufVPrintf(&mb, fmt, vargs);
  118.     httpHeaderPutStr(hdr, id, mb.buf);
  119.     memBufClean(&mb);
  120. }
  121. /* wrapper arrounf PutContRange */
  122. void
  123. httpHeaderAddContRange(HttpHeader * hdr, HttpHdrRangeSpec spec, size_t ent_len)
  124. {
  125.     HttpHdrContRange *cr = httpHdrContRangeCreate();
  126.     assert(hdr && ent_len >= 0);
  127.     httpHdrContRangeSet(cr, spec, ent_len);
  128.     httpHeaderPutContRange(hdr, cr);
  129.     httpHdrContRangeDestroy(cr);
  130. }
  131. /*
  132.  * return true if a given directive is found in at least one of the "connection" header-fields
  133.  * note: if HDR_PROXY_CONNECTION is present we ignore HDR_CONNECTION
  134.  */
  135. int
  136. httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive)
  137. {
  138.     if (httpHeaderHas(hdr, HDR_PROXY_CONNECTION)) {
  139. const char *str = httpHeaderGetStr(hdr, HDR_PROXY_CONNECTION);
  140. return str && !strcasecmp(str, directive);
  141.     }
  142.     if (httpHeaderHas(hdr, HDR_CONNECTION)) {
  143. String str = httpHeaderGetList(hdr, HDR_CONNECTION);
  144. const int res = strListIsMember(&str, directive, ',');
  145. stringClean(&str);
  146. return res;
  147.     }
  148.     return 0;
  149. }
  150. /* returns true iff "m" is a member of the list */
  151. int
  152. strListIsMember(const String * list, const char *m, char del)
  153. {
  154.     const char *pos = NULL;
  155.     const char *item;
  156.     assert(list && m);
  157.     while (strListGetItem(list, del, &item, NULL, &pos)) {
  158. if (!strcasecmp(item, m))
  159.     return 1;
  160.     }
  161.     return 0;
  162. }
  163. /* returns true iff "s" is a substring of a member of the list */
  164. int
  165. strListIsSubstr(const String * list, const char *s, char del)
  166. {
  167.     const char *pos = NULL;
  168.     const char *item;
  169.     assert(list && s);
  170.     while (strListGetItem(list, del, &item, NULL, &pos)) {
  171. if (strstr(item, s))
  172.     return 1;
  173.     }
  174.     return 0;
  175. }
  176. /* appends an item to the list */
  177. void
  178. strListAdd(String * str, const char *item, char del)
  179. {
  180.     assert(str && item);
  181.     if (strLen(*str)) {
  182. char buf[3];
  183. buf[0] = del;
  184. buf[1] = ' ';
  185. buf[2] = '';
  186. stringAppend(str, buf, 2);
  187.     }
  188.     stringAppend(str, item, strlen(item));
  189. }
  190. /*
  191.  * iterates through a 0-terminated string of items separated by 'del's.
  192.  * white space around 'del' is considered to be a part of 'del'
  193.  * like strtok, but preserves the source, and can iterate several strings at once
  194.  *
  195.  * returns true if next item is found.
  196.  * init pos with NULL to start iteration.
  197.  */
  198. int
  199. strListGetItem(const String * str, char del, const char **item, int *ilen, const char **pos)
  200. {
  201.     size_t len;
  202.     assert(str && item && pos);
  203.     if (*pos) {
  204. if (!**pos) /* end of string */
  205.     return 0;
  206. else
  207.     (*pos)++;
  208.     } else {
  209. *pos = strBuf(*str);
  210. if (!*pos)
  211.     return 0;
  212.     }
  213.     /* skip leading ws (ltrim) */
  214.     *pos += xcountws(*pos);
  215.     *item = *pos; /* remember item's start */
  216.     /* find next delimiter */
  217.     *pos = strchr(*item, del);
  218.     if (!*pos) /* last item */
  219. *pos = *item + strlen(*item);
  220.     len = *pos - *item; /* *pos points to del or '' */
  221.     /* rtrim */
  222.     while (len > 0 && xisspace((*item)[len - 1]))
  223. len--;
  224.     if (ilen)
  225. *ilen = len;
  226.     return len > 0;
  227. }
  228. /* handy to printf prefixes of potentially very long buffers */
  229. const char *
  230. getStringPrefix(const char *str, const char *end)
  231. {
  232. #define SHORT_PREFIX_SIZE 512
  233.     LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE);
  234.     const int sz = 1 + (end ? end - str : strlen(str));
  235.     xstrncpy(buf, str, (sz > SHORT_PREFIX_SIZE) ? SHORT_PREFIX_SIZE : sz);
  236.     return buf;
  237. }
  238. /*
  239.  * parses an int field, complains if soemthing went wrong, returns true on
  240.  * success
  241.  */
  242. int
  243. httpHeaderParseInt(const char *start, int *value)
  244. {
  245.     assert(value);
  246.     *value = atoi(start);
  247.     if (!*value && !xisdigit(*start)) {
  248. debug(66, 2) ("failed to parse an int header field near '%s'n", start);
  249. return 0;
  250.     }
  251.     return 1;
  252. }
  253. int
  254. httpHeaderParseSize(const char *start, size_t * value)
  255. {
  256.     int v;
  257.     const int res = httpHeaderParseInt(start, &v);
  258.     assert(value);
  259.     *value = res ? v : 0;
  260.     return res;
  261. }
  262. /*
  263.  * parses a given string then packs compiled headers and compares the result
  264.  * with the original, reports discrepancies
  265.  */
  266. void
  267. httpHeaderTestParser(const char *hstr)
  268. {
  269.     static int bug_count = 0;
  270.     int hstr_len;
  271.     int parse_success;
  272.     HttpHeader hdr;
  273.     int pos;
  274.     Packer p;
  275.     MemBuf mb;
  276.     assert(hstr);
  277.     /* skip start line if any */
  278.     if (!strncasecmp(hstr, "HTTP/", 5)) {
  279. const char *p = strchr(hstr, 'n');
  280. if (p)
  281.     hstr = p + 1;
  282.     }
  283.     /* skip invalid first line if any */
  284.     if (xisspace(*hstr)) {
  285. const char *p = strchr(hstr, 'n');
  286. if (p)
  287.     hstr = p + 1;
  288.     }
  289.     hstr_len = strlen(hstr);
  290.     /* skip terminator if any */
  291.     if (strstr(hstr, "nrn"))
  292. hstr_len -= 2;
  293.     else if (strstr(hstr, "nn"))
  294. hstr_len -= 1;
  295.     httpHeaderInit(&hdr, hoReply);
  296.     /* debugLevels[55] = 8; */
  297.     parse_success = httpHeaderParse(&hdr, hstr, hstr + hstr_len);
  298.     /* debugLevels[55] = 2; */
  299.     if (!parse_success) {
  300. debug(66, 2) ("TEST (%d): failed to parsed a header: {n%s}n", bug_count, hstr);
  301. return;
  302.     }
  303.     /* we think that we parsed it, veryfy */
  304.     memBufDefInit(&mb);
  305.     packerToMemInit(&p, &mb);
  306.     httpHeaderPackInto(&hdr, &p);
  307.     if ((pos = abs(httpHeaderStrCmp(hstr, mb.buf, hstr_len)))) {
  308. bug_count++;
  309. debug(66, 2) ("TEST (%d): hdr parsing bug (pos: %d near '%s'): expected: {n%s} got: {n%s}n",
  310.     bug_count, pos, hstr + pos, hstr, mb.buf);
  311.     }
  312.     httpHeaderClean(&hdr);
  313.     packerClean(&p);
  314.     memBufClean(&mb);
  315. }
  316. /* like strncasecmp but ignores ws characters */
  317. static int
  318. httpHeaderStrCmp(const char *h1, const char *h2, int len)
  319. {
  320.     int len1 = 0;
  321.     int len2 = 0;
  322.     assert(h1 && h2);
  323.     /* fast check first */
  324.     if (!strncasecmp(h1, h2, len))
  325. return 0;
  326.     while (1) {
  327. const char c1 = xtoupper(h1[len1 += xcountws(h1 + len1)]);
  328. const char c2 = xtoupper(h2[len2 += xcountws(h2 + len2)]);
  329. if (c1 < c2)
  330.     return -len1;
  331. if (c1 > c2)
  332.     return +len1;
  333. if (!c1 && !c2)
  334.     return 0;
  335. if (c1)
  336.     len1++;
  337. if (c2)
  338.     len2++;
  339.     }
  340.     return 0;
  341. }