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