]>
Commit | Line | Data |
---|---|---|
7faf2bdb | 1 | /* |
7faf2bdb | 2 | * DEBUG: section 66 HTTP Header Tools |
3 | * AUTHOR: Alex Rousskov | |
4 | * | |
2b6662ba | 5 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 6 | * ---------------------------------------------------------- |
7faf2bdb | 7 | * |
2b6662ba | 8 | * Squid is the result of efforts by numerous individuals from |
9 | * the Internet community; see the CONTRIBUTORS file for full | |
10 | * details. Many organizations have provided support for Squid's | |
11 | * development; see the SPONSORS file for full details. Squid is | |
12 | * Copyrighted (C) 2001 by the Regents of the University of | |
13 | * California; see the COPYRIGHT file for full details. Squid | |
14 | * incorporates software developed and/or copyrighted by other | |
15 | * sources; see the CREDITS file for full details. | |
7faf2bdb | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | |
18 | * it under the terms of the GNU General Public License as published by | |
19 | * the Free Software Foundation; either version 2 of the License, or | |
20 | * (at your option) any later version. | |
26ac0430 | 21 | * |
7faf2bdb | 22 | * This program is distributed in the hope that it will be useful, |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26ac0430 | 26 | * |
7faf2bdb | 27 | * You should have received a copy of the GNU General Public License |
28 | * along with this program; if not, write to the Free Software | |
cbdec147 | 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 30 | * |
7faf2bdb | 31 | */ |
32 | ||
582c2af2 | 33 | #include "squid.h" |
c0941a6a | 34 | #include "acl/FilledChecklist.h" |
3b07476b | 35 | #include "acl/Gadgets.h" |
f4698e0b | 36 | #include "client_side_request.h" |
582c2af2 | 37 | #include "client_side.h" |
f4698e0b | 38 | #include "comm/Connection.h" |
27bc2077 | 39 | #include "compat/strtoll.h" |
f4698e0b | 40 | #include "fde.h" |
27bc2077 AJ |
41 | #include "HttpHdrContRange.h" |
42 | #include "HttpHeader.h" | |
3b07476b CT |
43 | #include "HttpHeaderTools.h" |
44 | #include "HttpRequest.h" | |
0eb49b6d | 45 | #include "MemBuf.h" |
4d5904f7 | 46 | #include "SquidConfig.h" |
582c2af2 | 47 | #include "Store.h" |
28204b3b | 48 | #include "StrList.h" |
582c2af2 | 49 | |
f4698e0b CT |
50 | #if USE_SSL |
51 | #include "ssl/support.h" | |
52 | #endif | |
582c2af2 | 53 | |
f4698e0b | 54 | #include <algorithm> |
f4698e0b | 55 | #include <string> |
21d845b1 FC |
56 | #if HAVE_ERRNO_H |
57 | #include <errno.h> | |
58 | #endif | |
7faf2bdb | 59 | |
2246b732 | 60 | static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs); |
de336bbe | 61 | |
de336bbe | 62 | HttpHeaderFieldInfo * |
b644367b | 63 | httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count) |
7faf2bdb | 64 | { |
65 | int i; | |
de336bbe | 66 | HttpHeaderFieldInfo *table = NULL; |
67 | assert(attrs && count); | |
68 | ||
69 | /* allocate space */ | |
0353e724 | 70 | table = new HttpHeaderFieldInfo[count]; |
7faf2bdb | 71 | |
7faf2bdb | 72 | for (i = 0; i < count; ++i) { |
62e76326 | 73 | const http_hdr_type id = attrs[i].id; |
74 | HttpHeaderFieldInfo *info = table + id; | |
75 | /* sanity checks */ | |
76 | assert(id >= 0 && id < count); | |
77 | assert(attrs[i].name); | |
0353e724 | 78 | assert(info->id == HDR_ACCEPT && info->type == ftInvalid); /* was not set before */ |
62e76326 | 79 | /* copy and init fields */ |
80 | info->id = id; | |
81 | info->type = attrs[i].type; | |
82 | info->name = attrs[i].name; | |
83 | assert(info->name.size()); | |
7faf2bdb | 84 | } |
62e76326 | 85 | |
de336bbe | 86 | return table; |
87 | } | |
88 | ||
89 | void | |
b644367b | 90 | httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * table, int count) |
de336bbe | 91 | { |
92 | int i; | |
62e76326 | 93 | |
de336bbe | 94 | for (i = 0; i < count; ++i) |
30abd221 | 95 | table[i].name.clean(); |
62e76326 | 96 | |
7f4c8dec | 97 | delete [] table; |
7faf2bdb | 98 | } |
99 | ||
d8b249ef | 100 | void |
97474590 | 101 | httpHeaderMaskInit(HttpHeaderMask * mask, int value) |
d8b249ef | 102 | { |
97474590 | 103 | memset(mask, value, sizeof(*mask)); |
d8b249ef | 104 | } |
105 | ||
b50e327b | 106 | /** calculates a bit mask of a given array; does not reset mask! */ |
d8b249ef | 107 | void |
8abf232c | 108 | httpHeaderCalcMask(HttpHeaderMask * mask, http_hdr_type http_hdr_type_enums[], size_t count) |
7faf2bdb | 109 | { |
e6ccf245 | 110 | size_t i; |
8abf232c | 111 | const int * enums = (const int *) http_hdr_type_enums; |
d8b249ef | 112 | assert(mask && enums); |
99edd1c3 | 113 | assert(count < sizeof(*mask) * 8); /* check for overflow */ |
7faf2bdb | 114 | |
115 | for (i = 0; i < count; ++i) { | |
62e76326 | 116 | assert(!CBIT_TEST(*mask, enums[i])); /* check for duplicates */ |
117 | CBIT_SET(*mask, enums[i]); | |
7faf2bdb | 118 | } |
7faf2bdb | 119 | } |
120 | ||
2246b732 | 121 | /* same as httpHeaderPutStr, but formats the string using snprintf first */ |
2246b732 | 122 | void |
eeb423fb | 123 | httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt,...) |
2246b732 | 124 | { |
9bc73deb | 125 | va_list args; |
126 | va_start(args, fmt); | |
62e76326 | 127 | |
2246b732 | 128 | httpHeaderPutStrvf(hdr, id, fmt, args); |
129 | va_end(args); | |
130 | } | |
131 | ||
132 | /* used by httpHeaderPutStrf */ | |
133 | static void | |
134 | httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs) | |
135 | { | |
2246b732 | 136 | MemBuf mb; |
2fe7eff9 | 137 | mb.init(); |
138 | mb.vPrintf(fmt, vargs); | |
a9925b40 | 139 | hdr->putStr(id, mb.buf); |
2fe7eff9 | 140 | mb.clean(); |
2246b732 | 141 | } |
142 | ||
9035d1d5 | 143 | /** wrapper arrounf PutContRange */ |
d192d11f | 144 | void |
47f6e231 | 145 | httpHeaderAddContRange(HttpHeader * hdr, HttpHdrRangeSpec spec, int64_t ent_len) |
d192d11f | 146 | { |
147 | HttpHdrContRange *cr = httpHdrContRangeCreate(); | |
148 | assert(hdr && ent_len >= 0); | |
149 | httpHdrContRangeSet(cr, spec, ent_len); | |
a9925b40 | 150 | hdr->putContRange(cr); |
d192d11f | 151 | httpHdrContRangeDestroy(cr); |
152 | } | |
153 | ||
9035d1d5 | 154 | /** |
9bc73deb | 155 | * return true if a given directive is found in at least one of |
156 | * the "connection" header-fields note: if HDR_PROXY_CONNECTION is | |
157 | * present we ignore HDR_CONNECTION. | |
99edd1c3 | 158 | */ |
159 | int | |
5999b776 | 160 | httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive) |
99edd1c3 | 161 | { |
30abd221 | 162 | String list; |
9bc73deb | 163 | int res; |
164 | /* what type of header do we have? */ | |
62e76326 | 165 | |
95e78500 | 166 | #if USE_HTTP_VIOLATIONS |
a9925b40 | 167 | if (hdr->has(HDR_PROXY_CONNECTION)) |
95e78500 AJ |
168 | list = hdr->getList(HDR_PROXY_CONNECTION); |
169 | else | |
170 | #endif | |
2e881a6f A |
171 | if (hdr->has(HDR_CONNECTION)) |
172 | list = hdr->getList(HDR_CONNECTION); | |
173 | else | |
174 | return 0; | |
9bc73deb | 175 | |
9bc73deb | 176 | res = strListIsMember(&list, directive, ','); |
62e76326 | 177 | |
30abd221 | 178 | list.clean(); |
179 | ||
9bc73deb | 180 | return res; |
99edd1c3 | 181 | } |
182 | ||
99edd1c3 | 183 | |
7faf2bdb | 184 | |
b50e327b | 185 | /** handy to printf prefixes of potentially very long buffers */ |
7faf2bdb | 186 | const char * |
d8b249ef | 187 | getStringPrefix(const char *str, const char *end) |
7faf2bdb | 188 | { |
d8b249ef | 189 | #define SHORT_PREFIX_SIZE 512 |
7faf2bdb | 190 | LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE); |
b644367b | 191 | const int sz = 1 + (end ? end - str : strlen(str)); |
d8b249ef | 192 | xstrncpy(buf, str, (sz > SHORT_PREFIX_SIZE) ? SHORT_PREFIX_SIZE : sz); |
7faf2bdb | 193 | return buf; |
194 | } | |
b5107edb | 195 | |
b50e327b | 196 | /** |
b5107edb | 197 | * parses an int field, complains if soemthing went wrong, returns true on |
198 | * success | |
199 | */ | |
200 | int | |
201 | httpHeaderParseInt(const char *start, int *value) | |
202 | { | |
203 | assert(value); | |
204 | *value = atoi(start); | |
62e76326 | 205 | |
b6a2f15e | 206 | if (!*value && !xisdigit(*start)) { |
bf8fe701 | 207 | debugs(66, 2, "failed to parse an int header field near '" << start << "'"); |
62e76326 | 208 | return 0; |
b5107edb | 209 | } |
62e76326 | 210 | |
b5107edb | 211 | return 1; |
212 | } | |
213 | ||
47f6e231 | 214 | int |
215 | httpHeaderParseOffset(const char *start, int64_t * value) | |
216 | { | |
66e255bc | 217 | errno = 0; |
47f6e231 | 218 | int64_t res = strtoll(start, NULL, 10); |
219 | if (!res && EINVAL == errno) /* maybe not portable? */ | |
26ac0430 | 220 | return 0; |
47f6e231 | 221 | *value = res; |
222 | return 1; | |
223 | } | |
224 | ||
b50e327b AJ |
225 | /** |
226 | * Parses a quoted-string field (RFC 2616 section 2.2), complains if | |
43ae1d95 | 227 | * something went wrong, returns non-zero on success. |
34460e19 | 228 | * Un-escapes quoted-pair characters found within the string. |
229af339 | 229 | * start should point at the first double-quote. |
43ae1d95 | 230 | */ |
231 | int | |
34460e19 | 232 | httpHeaderParseQuotedString(const char *start, const int len, String *val) |
43ae1d95 | 233 | { |
234 | const char *end, *pos; | |
30abd221 | 235 | val->clean(); |
9abd1514 | 236 | if (*start != '"') { |
5f5ddef6 | 237 | debugs(66, 2, HERE << "failed to parse a quoted-string header field near '" << start << "'"); |
6d97f5f1 | 238 | return 0; |
9abd1514 | 239 | } |
43ae1d95 | 240 | pos = start + 1; |
241 | ||
34460e19 | 242 | while (*pos != '"' && len > (pos-start)) { |
5f5ddef6 CT |
243 | |
244 | if (*pos =='\r') { | |
95dc7ff4 | 245 | ++pos; |
5f5ddef6 CT |
246 | if ((pos-start) > len || *pos != '\n') { |
247 | debugs(66, 2, HERE << "failed to parse a quoted-string header field with '\\r' octet " << (start-pos) | |
248 | << " bytes into '" << start << "'"); | |
249 | val->clean(); | |
250 | return 0; | |
251 | } | |
252 | } | |
253 | ||
254 | if (*pos == '\n') { | |
95dc7ff4 | 255 | ++pos; |
5f5ddef6 CT |
256 | if ( (pos-start) > len || (*pos != ' ' && *pos != '\t')) { |
257 | debugs(66, 2, HERE << "failed to parse multiline quoted-string header field '" << start << "'"); | |
258 | val->clean(); | |
259 | return 0; | |
260 | } | |
261 | // TODO: replace the entire LWS with a space | |
262 | val->append(" "); | |
95dc7ff4 | 263 | ++pos; |
5f5ddef6 CT |
264 | debugs(66, 2, HERE << "len < pos-start => " << len << " < " << (pos-start)); |
265 | continue; | |
266 | } | |
267 | ||
a0133f10 | 268 | bool quoted = (*pos == '\\'); |
5f5ddef6 | 269 | if (quoted) { |
95dc7ff4 | 270 | ++pos; |
5f5ddef6 CT |
271 | if (!*pos || (pos-start) > len) { |
272 | debugs(66, 2, HERE << "failed to parse a quoted-string header field near '" << start << "'"); | |
273 | val->clean(); | |
274 | return 0; | |
275 | } | |
6d97f5f1 | 276 | } |
34460e19 | 277 | end = pos; |
c4b86597 | 278 | while (end < (start+len) && *end != '\\' && *end != '\"' && (unsigned char)*end > 0x1F && *end != 0x7F) |
95dc7ff4 | 279 | ++end; |
c4b86597 | 280 | if (((unsigned char)*end <= 0x1F && *end != '\r' && *end != '\n') || *end == 0x7F) { |
5f5ddef6 | 281 | debugs(66, 2, HERE << "failed to parse a quoted-string header field with CTL octet " << (start-pos) |
34460e19 AJ |
282 | << " bytes into '" << start << "'"); |
283 | val->clean(); | |
284 | return 0; | |
285 | } | |
6d97f5f1 A |
286 | val->append(pos, end-pos); |
287 | pos = end; | |
43ae1d95 | 288 | } |
5f5ddef6 CT |
289 | |
290 | if (*pos != '\"') { | |
291 | debugs(66, 2, HERE << "failed to parse a quoted-string header field which did not end with \" "); | |
292 | val->clean(); | |
293 | return 0; | |
294 | } | |
9abd1514 HN |
295 | /* Make sure it's defined even if empty "" */ |
296 | if (!val->defined()) | |
6d97f5f1 | 297 | val->limitInit("", 0); |
9abd1514 | 298 | return 1; |
43ae1d95 | 299 | } |
300 | ||
b50e327b AJ |
301 | /** |
302 | * Checks the anonymizer (header_access) configuration. | |
4f4611bf | 303 | * |
b50e327b AJ |
304 | * \retval 0 Header is explicitly blocked for removal |
305 | * \retval 1 Header is explicitly allowed | |
306 | * \retval 1 Header has been replaced, the current version can be used. | |
307 | * \retval 1 Header has no access controls to test | |
6bccf575 | 308 | */ |
2d72d4fd | 309 | static int |
8c01ada0 | 310 | httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep) |
6bccf575 | 311 | { |
e9b1e111 | 312 | int retval; |
313 | ||
6bccf575 | 314 | /* check with anonymizer tables */ |
3b07476b | 315 | HeaderManglers *hms = NULL; |
6bccf575 | 316 | assert(e); |
8c01ada0 | 317 | |
318 | if (ROR_REQUEST == req_or_rep) { | |
3b07476b | 319 | hms = Config.request_header_access; |
8c01ada0 | 320 | } else if (ROR_REPLY == req_or_rep) { |
3b07476b | 321 | hms = Config.reply_header_access; |
8c01ada0 | 322 | } else { |
323 | /* error. But let's call it "request". */ | |
3b07476b | 324 | hms = Config.request_header_access; |
8c01ada0 | 325 | } |
326 | ||
3b07476b CT |
327 | /* manglers are not configured for this message kind */ |
328 | if (!hms) | |
329 | return 1; | |
330 | ||
331 | const header_mangler *hm = hms->find(*e); | |
332 | ||
b50e327b | 333 | /* mangler or checklist went away. default allow */ |
af6a12ee | 334 | if (!hm || !hm->access_list) { |
b50e327b AJ |
335 | return 1; |
336 | } | |
337 | ||
c0941a6a | 338 | ACLFilledChecklist checklist(hm->access_list, request, NULL); |
62e76326 | 339 | |
2efeb0b7 | 340 | if (checklist.fastCheck() == ACCESS_ALLOWED) { |
b50e327b | 341 | /* aclCheckFast returns true for allow. */ |
62e76326 | 342 | retval = 1; |
a453662f | 343 | } else if (NULL == hm->replacement) { |
62e76326 | 344 | /* It was denied, and we don't have any replacement */ |
345 | retval = 0; | |
a453662f | 346 | } else { |
62e76326 | 347 | /* It was denied, but we have a replacement. Replace the |
348 | * header on the fly, and return that the new header | |
349 | * is allowed. | |
350 | */ | |
351 | e->value = hm->replacement; | |
352 | retval = 1; | |
a453662f | 353 | } |
e9b1e111 | 354 | |
e9b1e111 | 355 | return retval; |
6bccf575 | 356 | } |
357 | ||
b50e327b | 358 | /** Mangles headers for a list of headers. */ |
6bccf575 | 359 | void |
8c01ada0 | 360 | httpHdrMangleList(HttpHeader * l, HttpRequest * request, int req_or_rep) |
6bccf575 | 361 | { |
362 | HttpHeaderEntry *e; | |
363 | HttpHeaderPos p = HttpHeaderInitPos; | |
62e76326 | 364 | |
ba9fb01d | 365 | int headers_deleted = 0; |
a9925b40 | 366 | while ((e = l->getEntry(&p))) |
8c01ada0 | 367 | if (0 == httpHdrMangle(e, request, req_or_rep)) |
ba9fb01d | 368 | l->delAt(p, headers_deleted); |
369 | ||
370 | if (headers_deleted) | |
371 | l->refreshMask(); | |
6bccf575 | 372 | } |
5967c0bf | 373 | |
3b07476b CT |
374 | static |
375 | void header_mangler_clean(header_mangler &m) | |
376 | { | |
377 | aclDestroyAccessList(&m.access_list); | |
378 | safe_free(m.replacement); | |
379 | } | |
380 | ||
381 | static | |
382 | void header_mangler_dump_access(StoreEntry * entry, const char *option, | |
d3abcb0d | 383 | const header_mangler &m, const char *name) |
3b07476b CT |
384 | { |
385 | if (m.access_list != NULL) { | |
386 | storeAppendPrintf(entry, "%s ", option); | |
387 | dump_acl_access(entry, name, m.access_list); | |
388 | } | |
389 | } | |
390 | ||
391 | static | |
392 | void header_mangler_dump_replacement(StoreEntry * entry, const char *option, | |
d3abcb0d | 393 | const header_mangler &m, const char *name) |
3b07476b CT |
394 | { |
395 | if (m.replacement) | |
396 | storeAppendPrintf(entry, "%s %s %s\n", option, name, m.replacement); | |
397 | } | |
398 | ||
399 | HeaderManglers::HeaderManglers() | |
400 | { | |
401 | memset(known, 0, sizeof(known)); | |
402 | memset(&all, 0, sizeof(all)); | |
403 | } | |
404 | ||
405 | HeaderManglers::~HeaderManglers() | |
406 | { | |
95dc7ff4 | 407 | for (int i = 0; i < HDR_ENUM_END; ++i) |
3b07476b CT |
408 | header_mangler_clean(known[i]); |
409 | ||
410 | typedef ManglersByName::iterator MBNI; | |
411 | for (MBNI i = custom.begin(); i != custom.end(); ++i) | |
412 | header_mangler_clean(i->second); | |
413 | ||
414 | header_mangler_clean(all); | |
415 | } | |
416 | ||
417 | void | |
418 | HeaderManglers::dumpAccess(StoreEntry * entry, const char *name) const | |
5967c0bf | 419 | { |
95dc7ff4 | 420 | for (int i = 0; i < HDR_ENUM_END; ++i) { |
3b07476b CT |
421 | header_mangler_dump_access(entry, name, known[i], |
422 | httpHeaderNameById(i)); | |
5967c0bf | 423 | } |
424 | ||
3b07476b CT |
425 | typedef ManglersByName::const_iterator MBNCI; |
426 | for (MBNCI i = custom.begin(); i != custom.end(); ++i) | |
427 | header_mangler_dump_access(entry, name, i->second, i->first.c_str()); | |
428 | ||
429 | header_mangler_dump_access(entry, name, all, "All"); | |
5967c0bf | 430 | } |
3b07476b CT |
431 | |
432 | void | |
433 | HeaderManglers::dumpReplacement(StoreEntry * entry, const char *name) const | |
434 | { | |
95dc7ff4 | 435 | for (int i = 0; i < HDR_ENUM_END; ++i) { |
3b07476b CT |
436 | header_mangler_dump_replacement(entry, name, known[i], |
437 | httpHeaderNameById(i)); | |
438 | } | |
439 | ||
440 | typedef ManglersByName::const_iterator MBNCI; | |
441 | for (MBNCI i = custom.begin(); i != custom.end(); ++i) { | |
442 | header_mangler_dump_replacement(entry, name, i->second, | |
443 | i->first.c_str()); | |
444 | } | |
445 | ||
446 | header_mangler_dump_replacement(entry, name, all, "All"); | |
447 | } | |
448 | ||
449 | header_mangler * | |
450 | HeaderManglers::track(const char *name) | |
451 | { | |
452 | int id = httpHeaderIdByNameDef(name, strlen(name)); | |
453 | ||
454 | if (id == HDR_BAD_HDR) { // special keyword or a custom header | |
455 | if (strcmp(name, "All") == 0) | |
456 | id = HDR_ENUM_END; | |
457 | else if (strcmp(name, "Other") == 0) | |
458 | id = HDR_OTHER; | |
459 | } | |
460 | ||
461 | header_mangler *m = NULL; | |
462 | if (id == HDR_ENUM_END) { | |
463 | m = &all; | |
d3abcb0d | 464 | } else if (id == HDR_BAD_HDR) { |
3b07476b CT |
465 | m = &custom[name]; |
466 | } else { | |
467 | m = &known[id]; // including HDR_OTHER | |
468 | } | |
469 | ||
470 | assert(m); | |
471 | return m; | |
472 | } | |
473 | ||
474 | void | |
475 | HeaderManglers::setReplacement(const char *name, const char *value) | |
476 | { | |
477 | // for backword compatibility, we allow replacements to be configured | |
478 | // for headers w/o access rules, but such replacements are ignored | |
479 | header_mangler *m = track(name); | |
480 | ||
481 | safe_free(m->replacement); // overwrite old value if any | |
482 | m->replacement = xstrdup(value); | |
483 | } | |
484 | ||
485 | const header_mangler * | |
486 | HeaderManglers::find(const HttpHeaderEntry &e) const | |
487 | { | |
488 | // a known header with a configured ACL list | |
489 | if (e.id != HDR_OTHER && 0 <= e.id && e.id < HDR_ENUM_END && | |
d3abcb0d | 490 | known[e.id].access_list) |
3b07476b CT |
491 | return &known[e.id]; |
492 | ||
493 | // a custom header | |
494 | if (e.id == HDR_OTHER) { | |
495 | // does it have an ACL list configured? | |
496 | // Optimize: use a name type that we do not need to convert to here | |
497 | const ManglersByName::const_iterator i = custom.find(e.name.termedBuf()); | |
498 | if (i != custom.end()) | |
499 | return &i->second; | |
500 | } | |
501 | ||
502 | // Next-to-last resort: "Other" rules match any custom header | |
503 | if (e.id == HDR_OTHER && known[HDR_OTHER].access_list) | |
504 | return &known[HDR_OTHER]; | |
505 | ||
506 | // Last resort: "All" rules match any header | |
507 | if (all.access_list) | |
508 | return &all; | |
509 | ||
510 | return NULL; | |
511 | } | |
512 | ||
f4698e0b | 513 | void |
4bf68cfa | 514 | httpHdrAdd(HttpHeader *heads, HttpRequest *request, const AccessLogEntryPointer &al, HeaderWithAclList &headersAdd) |
f4698e0b CT |
515 | { |
516 | ACLFilledChecklist checklist(NULL, request, NULL); | |
517 | ||
518 | for (HeaderWithAclList::const_iterator hwa = headersAdd.begin(); hwa != headersAdd.end(); ++hwa) { | |
519 | if (!hwa->aclList || checklist.fastCheck(hwa->aclList) == ACCESS_ALLOWED) { | |
520 | const char *fieldValue = NULL; | |
521 | MemBuf mb; | |
522 | if (hwa->quoted) { | |
4bf68cfa | 523 | if (al != NULL) { |
f4698e0b | 524 | mb.init(); |
4bf68cfa | 525 | hwa->valueFormat->assemble(mb, al, 0); |
f4698e0b CT |
526 | fieldValue = mb.content(); |
527 | } | |
528 | } else { | |
529 | fieldValue = hwa->fieldValue.c_str(); | |
530 | } | |
531 | ||
532 | if (!fieldValue || fieldValue[0] == '\0') | |
533 | fieldValue = "-"; | |
534 | ||
999aa5d2 A |
535 | HttpHeaderEntry *e = new HttpHeaderEntry(hwa->fieldId, hwa->fieldName.c_str(), |
536 | fieldValue); | |
f4698e0b CT |
537 | heads->addEntry(e); |
538 | } | |
539 | } | |
540 | } |