]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpHeaderTools.cc
Prevent forwarding loops from netdbClosestParent()
[thirdparty/squid.git] / src / HttpHeaderTools.cc
CommitLineData
7faf2bdb 1/*
99edd1c3 2 * $Id: HttpHeaderTools.cc,v 1.11 1998/05/11 18:44:27 rousskov Exp $
7faf2bdb 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
13 * the National Science Foundation.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
29 */
30
31#include "squid.h"
32
de336bbe 33static int httpHeaderStrCmp(const char *h1, const char *h2, int len);
34
35
36HttpHeaderFieldInfo *
b644367b 37httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count)
7faf2bdb 38{
39 int i;
de336bbe 40 HttpHeaderFieldInfo *table = NULL;
41 assert(attrs && count);
42
43 /* allocate space */
44 table = xcalloc(count, sizeof(HttpHeaderFieldInfo));
7faf2bdb 45
7faf2bdb 46 for (i = 0; i < count; ++i) {
de336bbe 47 const int id = attrs[i].id;
48 HttpHeaderFieldInfo *info = table + id;
49 /* sanity checks */
50 assert(id >= 0 && id < count);
51 assert(attrs[i].name);
b644367b 52 assert(info->id == 0 && info->type == 0); /* was not set before */
de336bbe 53 /* copy and init fields */
54 info->id = id;
55 info->type = attrs[i].type;
56 stringInit(&info->name, attrs[i].name);
57 assert(strLen(info->name));
7faf2bdb 58 /* init stats */
de336bbe 59 memset(&info->stat, 0, sizeof(info->stat));
7faf2bdb 60 }
de336bbe 61 return table;
62}
63
64void
b644367b 65httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * table, int count)
de336bbe 66{
67 int i;
68 for (i = 0; i < count; ++i)
69 stringClean(&table[i].name);
70 xfree(table);
7faf2bdb 71}
72
d8b249ef 73void
b644367b 74httpHeaderMaskInit(HttpHeaderMask * mask)
d8b249ef 75{
76 memset(mask, 0, sizeof(*mask));
77}
78
99edd1c3 79/* calculates a bit mask of a given array; does not reset mask! */
d8b249ef 80void
b644367b 81httpHeaderCalcMask(HttpHeaderMask * mask, const int *enums, int count)
7faf2bdb 82{
83 int i;
d8b249ef 84 assert(mask && enums);
99edd1c3 85 assert(count < sizeof(*mask) * 8); /* check for overflow */
7faf2bdb 86
87 for (i = 0; i < count; ++i) {
d8b249ef 88 assert(!CBIT_TEST(*mask, enums[i])); /* check for duplicates */
89 CBIT_SET(*mask, enums[i]);
7faf2bdb 90 }
7faf2bdb 91}
92
93
94int
b644367b 95httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo * info, int end)
7faf2bdb 96{
97 int i;
98 for (i = 0; i < end; ++i) {
d8b249ef 99 if (name_len >= 0 && name_len != strLen(info[i].name))
100 continue;
101 if (!strncasecmp(name, strBuf(info[i].name),
b644367b 102 name_len < 0 ? strLen(info[i].name) + 1 : name_len))
103 return i;
7faf2bdb 104 }
105 return -1;
106}
107
99edd1c3 108/*
109 * return true if a given directive is found in at least one of the "connection" header-fields
110 * note: if HDR_PROXY_CONNECTION is present we ignore HDR_CONNECTION
111 */
112int
113httpHeaderHasConnDir(const HttpHeader *hdr, const char *directive)
114{
115 if (httpHeaderHas(hdr, HDR_PROXY_CONNECTION)) {
116 const char *str = httpHeaderGetStr(hdr, HDR_PROXY_CONNECTION);
117 return str && !strcasecmp(str, directive);
118 }
119 if (httpHeaderHas(hdr, HDR_CONNECTION)) {
120 String str = httpHeaderGetList(hdr, HDR_CONNECTION);
121 const int res = strListIsMember(&str, directive, ',');
122 stringClean(&str);
123 return res;
124 }
125 return 0;
126}
127
128/* returns true iff "m" is a member of the list */
129int
130strListIsMember(const String *list, const char *m, char del)
131{
132 const char *pos = NULL;
133 const char *item;
134 assert(list && m);
135 while (strListGetItem(list, del, &item, NULL, &pos)) {
136 if (!strcasecmp(item, m))
137 return 1;
138 }
139 return 0;
140}
141
142/* appends an item to the list */
143void
144strListAdd(String *str, const char *item, char del)
145{
146 assert(str && item);
147 if (strLen(*str))
148 stringAppend(str, &del, 1);
149 stringAppend(str, item, strlen(item));
150}
151
7faf2bdb 152/*
153 * iterates through a 0-terminated string of items separated by 'del's.
154 * white space around 'del' is considered to be a part of 'del'
155 * like strtok, but preserves the source, and can iterate several strings at once
156 *
157 * returns true if next item is found.
158 * init pos with NULL to start iteration.
159 */
160int
99edd1c3 161strListGetItem(const String *str, char del, const char **item, int *ilen, const char **pos)
7faf2bdb 162{
163 size_t len;
164 assert(str && item && pos);
a3f9588e 165 if (*pos) {
7faf2bdb 166 if (!**pos) /* end of string */
167 return 0;
168 else
169 (*pos)++;
a3f9588e 170 } else {
99edd1c3 171 *pos = strBuf(*str);
172 if (!*pos)
173 return 0;
a3f9588e 174 }
7faf2bdb 175
176 /* skip leading ws (ltrim) */
177 *pos += xcountws(*pos);
178 *item = *pos; /* remember item's start */
179 /* find next delimiter */
180 *pos = strchr(*item, del);
181 if (!*pos) /* last item */
182 *pos = *item + strlen(*item);
183 len = *pos - *item; /* *pos points to del or '\0' */
184 /* rtrim */
185 while (len > 0 && isspace((*item)[len - 1]))
186 len--;
187 if (ilen)
188 *ilen = len;
189 return len > 0;
190}
191
192/* handy to printf prefixes of potentially very long buffers */
193const char *
d8b249ef 194getStringPrefix(const char *str, const char *end)
7faf2bdb 195{
d8b249ef 196#define SHORT_PREFIX_SIZE 512
7faf2bdb 197 LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE);
b644367b 198 const int sz = 1 + (end ? end - str : strlen(str));
d8b249ef 199 xstrncpy(buf, str, (sz > SHORT_PREFIX_SIZE) ? SHORT_PREFIX_SIZE : sz);
7faf2bdb 200 return buf;
201}
b5107edb 202
203/*
204 * parses an int field, complains if soemthing went wrong, returns true on
205 * success
206 */
207int
208httpHeaderParseInt(const char *start, int *value)
209{
210 assert(value);
211 *value = atoi(start);
212 if (!*value && !isdigit(*start)) {
213 debug(66, 2) ("failed to parse an int header field near '%s'\n", start);
b644367b 214 return 0;
b5107edb 215 }
216 return 1;
217}
218
219int
b644367b 220httpHeaderParseSize(const char *start, size_t * value)
b5107edb 221{
222 int v;
223 const int res = httpHeaderParseInt(start, &v);
224 assert(value);
225 *value = res ? v : 0;
226 return res;
227}
de336bbe 228
229
230/*
231 * parses a given string then packs compiled headers and compares the result
232 * with the original, reports discrepancies
233 */
4b4cd312 234void
b644367b 235httpHeaderTestParser(const char *hstr)
de336bbe 236{
237 static int bug_count = 0;
238 int hstr_len;
239 int parse_success;
240 HttpHeader hdr;
241 int pos;
242 Packer p;
243 MemBuf mb;
244 assert(hstr);
de336bbe 245 /* skip start line if any */
246 if (!strncasecmp(hstr, "HTTP/", 5)) {
247 const char *p = strchr(hstr, '\n');
248 if (p)
b644367b 249 hstr = p + 1;
de336bbe 250 }
251 /* skip invalid first line if any */
252 if (isspace(*hstr)) {
253 const char *p = strchr(hstr, '\n');
254 if (p)
b644367b 255 hstr = p + 1;
de336bbe 256 }
257 hstr_len = strlen(hstr);
258 /* skip terminator if any */
259 if (strstr(hstr, "\n\r\n"))
260 hstr_len -= 2;
b644367b 261 else if (strstr(hstr, "\n\n"))
de336bbe 262 hstr_len -= 1;
263 httpHeaderInit(&hdr);
264 /* debugLevels[55] = 8; */
b644367b 265 parse_success = httpHeaderParse(&hdr, hstr, hstr + hstr_len);
de336bbe 266 /* debugLevels[55] = 2; */
267 if (!parse_success) {
d8b249ef 268 debug(66, 2) ("TEST (%d): failed to parsed a header: {\n%s}\n", bug_count, hstr);
de336bbe 269 return;
270 }
271 /* we think that we parsed it, veryfy */
272 memBufDefInit(&mb);
273 packerToMemInit(&p, &mb);
274 httpHeaderPackInto(&hdr, &p);
275 if ((pos = abs(httpHeaderStrCmp(hstr, mb.buf, hstr_len)))) {
276 bug_count++;
d8b249ef 277 debug(66, 2) ("TEST (%d): hdr parsing bug (pos: %d near '%s'): expected: {\n%s} got: {\n%s}\n",
b644367b 278 bug_count, pos, hstr + pos, hstr, mb.buf);
de336bbe 279 }
280 httpHeaderClean(&hdr);
281 packerClean(&p);
282 memBufClean(&mb);
283}
284
285
b644367b 286/* like strncasecmp but ignores ws characters */
de336bbe 287static int
288httpHeaderStrCmp(const char *h1, const char *h2, int len)
289{
290 int len1 = 0;
291 int len2 = 0;
292 assert(h1 && h2);
293 /* fast check first */
294 if (!strncasecmp(h1, h2, len))
295 return 0;
296 while (1) {
297 const char c1 = toupper(h1[len1 += xcountws(h1 + len1)]);
298 const char c2 = toupper(h2[len2 += xcountws(h2 + len2)]);
b644367b 299 if (c1 < c2)
300 return -len1;
301 if (c1 > c2)
302 return +len1;
de336bbe 303 if (!c1 && !c2)
304 return 0;
b644367b 305 if (c1)
306 len1++;
307 if (c2)
308 len2++;
de336bbe 309 }
310 return 0;
311}