]> git.ipfire.org Git - thirdparty/squid.git/blame - src/format/Format.cc
Do not leak url_rewrite_extras and store_id_extras on reconfigure/shutdown.
[thirdparty/squid.git] / src / format / Format.cc
CommitLineData
bbc27441 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
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.
7 */
8
f7f3304a 9#include "squid.h"
38e16f92 10#include "AccessLogEntry.h"
582c2af2 11#include "client_side.h"
38e16f92
AJ
12#include "comm/Connection.h"
13#include "err_detail_type.h"
14#include "errorpage.h"
f4698e0b 15#include "fde.h"
38e16f92
AJ
16#include "format/Format.h"
17#include "format/Quoting.h"
31971e6a 18#include "format/Token.h"
95e6d864 19#include "fqdncache.h"
d3dddfb5 20#include "http/Stream.h"
38e16f92
AJ
21#include "HttpRequest.h"
22#include "MemBuf.h"
23#include "rfc1738.h"
92e3827b 24#include "security/CertError.h"
4b307ad4 25#include "security/NegotiationHistory.h"
38e16f92
AJ
26#include "SquidTime.h"
27#include "Store.h"
95d78f10 28#include "tools.h"
b1bd952a 29#include "URL.h"
cb4f4424 30#if USE_OPENSSL
2f3e52b5 31#include "ssl/ErrorDetail.h"
cedca6e7 32#include "ssl/ServerBump.h"
2f3e52b5
CT
33#endif
34
bd85ea1f
AJ
35/// Convert a string to NULL pointer if it is ""
36#define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
38e16f92 37
f57ae909
NH
38const SBuf Format::Dash("-");
39
38e16f92 40Format::Format::Format(const char *n) :
f53969cc
SM
41 format(NULL),
42 next(NULL)
38e16f92
AJ
43{
44 name = xstrdup(n);
45}
46
47Format::Format::~Format()
48{
49 // erase the list without consuming stack space
50 while (next) {
51 // unlink the next entry for deletion
52 Format *temp = next;
53 next = temp->next;
54 temp->next = NULL;
55 delete temp;
56 }
57
58 // remove locals
59 xfree(name);
60 delete format;
61}
62
63bool
f4698e0b 64Format::Format::parse(const char *def)
38e16f92 65{
f4698e0b 66 const char *cur, *eos;
38e16f92
AJ
67 Token *new_lt, *last_lt;
68 enum Quoting quote = LOG_QUOTE_NONE;
69
70 debugs(46, 2, HERE << "got definition '" << def << "'");
71
72 if (format) {
73 debugs(46, DBG_IMPORTANT, "WARNING: existing format for '" << name << " " << def << "'");
74 return false;
75 }
76
77 /* very inefficent parser, but who cares, this needs to be simple */
78 /* First off, let's tokenize, we'll optimize in a second pass.
79 * A token can either be a %-prefixed sequence (usually a dynamic
80 * token but it can be an escaped sequence), or a string. */
81 cur = def;
82 eos = def + strlen(def);
83 format = new_lt = last_lt = new Token;
84 cur += new_lt->parse(cur, &quote);
85
86 while (cur < eos) {
87 new_lt = new Token;
88 last_lt->next = new_lt;
89 last_lt = new_lt;
90 cur += new_lt->parse(cur, &quote);
91 }
92
93 return true;
94}
95
96void
4e56d7f6 97Format::Format::dump(StoreEntry * entry, const char *directiveName, bool eol) const
38e16f92
AJ
98{
99 debugs(46, 4, HERE);
100
101 // loop rather than recursing to conserve stack space.
4e56d7f6 102 for (const Format *fmt = this; fmt; fmt = fmt->next) {
5f621cd0 103 debugs(46, 3, HERE << "Dumping format definition for " << fmt->name);
4e56d7f6
AJ
104 if (directiveName)
105 storeAppendPrintf(entry, "%s %s ", directiveName, fmt->name);
38e16f92 106
5f621cd0 107 for (Token *t = fmt->format; t; t = t->next) {
38e16f92
AJ
108 if (t->type == LFT_STRING)
109 storeAppendPrintf(entry, "%s", t->data.string);
110 else {
111 char argbuf[256];
112 char *arg = NULL;
113 ByteCode_t type = t->type;
114
115 switch (type) {
f53969cc 116 /* special cases */
38e16f92
AJ
117
118 case LFT_STRING:
119 break;
120#if USE_ADAPTATION
121 case LFT_ADAPTATION_LAST_HEADER_ELEM:
122#endif
123#if ICAP_CLIENT
124 case LFT_ICAP_REQ_HEADER_ELEM:
125 case LFT_ICAP_REP_HEADER_ELEM:
126#endif
127 case LFT_REQUEST_HEADER_ELEM:
128 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
129 case LFT_REPLY_HEADER_ELEM:
130
131 if (t->data.header.separator != ',')
132 snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
133 else
134 snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
135
136 arg = argbuf;
137
138 switch (type) {
139 case LFT_REQUEST_HEADER_ELEM:
140 type = LFT_REQUEST_HEADER_ELEM; // XXX: remove _ELEM?
141 break;
142 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
143 type = LFT_ADAPTED_REQUEST_HEADER_ELEM; // XXX: remove _ELEM?
144 break;
145 case LFT_REPLY_HEADER_ELEM:
146 type = LFT_REPLY_HEADER_ELEM; // XXX: remove _ELEM?
147 break;
148#if USE_ADAPTATION
149 case LFT_ADAPTATION_LAST_HEADER_ELEM:
150 type = LFT_ADAPTATION_LAST_HEADER;
151 break;
152#endif
153#if ICAP_CLIENT
154 case LFT_ICAP_REQ_HEADER_ELEM:
155 type = LFT_ICAP_REQ_HEADER;
156 break;
157 case LFT_ICAP_REP_HEADER_ELEM:
158 type = LFT_ICAP_REP_HEADER;
159 break;
160#endif
161 default:
162 break;
163 }
164
165 break;
166
167 case LFT_REQUEST_ALL_HEADERS:
168 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
169 case LFT_REPLY_ALL_HEADERS:
170
171#if USE_ADAPTATION
172 case LFT_ADAPTATION_LAST_ALL_HEADERS:
173#endif
174#if ICAP_CLIENT
175 case LFT_ICAP_REQ_ALL_HEADERS:
176 case LFT_ICAP_REP_ALL_HEADERS:
177#endif
178
179 switch (type) {
180 case LFT_REQUEST_ALL_HEADERS:
181 type = LFT_REQUEST_HEADER;
182 break;
183 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
184 type = LFT_ADAPTED_REQUEST_HEADER;
185 break;
186 case LFT_REPLY_ALL_HEADERS:
187 type = LFT_REPLY_HEADER;
188 break;
189#if USE_ADAPTATION
190 case LFT_ADAPTATION_LAST_ALL_HEADERS:
191 type = LFT_ADAPTATION_LAST_HEADER;
192 break;
193#endif
194#if ICAP_CLIENT
195 case LFT_ICAP_REQ_ALL_HEADERS:
196 type = LFT_ICAP_REQ_HEADER;
197 break;
198 case LFT_ICAP_REP_ALL_HEADERS:
199 type = LFT_ICAP_REP_HEADER;
200 break;
201#endif
202 default:
203 break;
204 }
205
206 break;
207
208 default:
209 if (t->data.string)
210 arg = t->data.string;
211
212 break;
213 }
214
215 entry->append("%", 1);
216
217 switch (t->quote) {
218
219 case LOG_QUOTE_QUOTES:
220 entry->append("\"", 1);
221 break;
222
223 case LOG_QUOTE_MIMEBLOB:
224 entry->append("[", 1);
225 break;
226
227 case LOG_QUOTE_URL:
228 entry->append("#", 1);
229 break;
230
231 case LOG_QUOTE_RAW:
232 entry->append("'", 1);
233 break;
234
95d78f10
AJ
235 case LOG_QUOTE_SHELL:
236 entry->append("/", 1);
237 break;
238
38e16f92
AJ
239 case LOG_QUOTE_NONE:
240 break;
241 }
242
243 if (t->left)
244 entry->append("-", 1);
245
246 if (t->zero)
247 entry->append("0", 1);
248
8846a2b4
CT
249 if (t->widthMin >= 0)
250 storeAppendPrintf(entry, "%d", t->widthMin);
38e16f92 251
8846a2b4
CT
252 if (t->widthMax >= 0)
253 storeAppendPrintf(entry, ".%d", t->widthMax);
38e16f92
AJ
254
255 if (arg)
256 storeAppendPrintf(entry, "{%s}", arg);
257
aa99e35e 258 storeAppendPrintf(entry, "%s", t->label);
38e16f92
AJ
259
260 if (t->space)
261 entry->append(" ", 1);
262 }
263 }
264
4e56d7f6
AJ
265 if (eol)
266 entry->append("\n", 1);
38e16f92
AJ
267 }
268
269}
270
271static void
272log_quoted_string(const char *str, char *out)
273{
274 char *p = out;
275
276 while (*str) {
277 int l = strcspn(str, "\"\\\r\n\t");
278 memcpy(p, str, l);
279 str += l;
280 p += l;
281
282 switch (*str) {
283
284 case '\0':
285 break;
286
287 case '\r':
a38ec4b1
FC
288 *p = '\\';
289 ++p;
290 *p = 'r';
291 ++p;
cb4185f1 292 ++str;
38e16f92
AJ
293 break;
294
295 case '\n':
a38ec4b1
FC
296 *p = '\\';
297 ++p;
298 *p = 'n';
299 ++p;
cb4185f1 300 ++str;
38e16f92
AJ
301 break;
302
303 case '\t':
a38ec4b1
FC
304 *p = '\\';
305 ++p;
306 *p = 't';
307 ++p;
cb4185f1 308 ++str;
38e16f92
AJ
309 break;
310
311 default:
a38ec4b1
FC
312 *p = '\\';
313 ++p;
314 *p = *str;
315 ++p;
cb4185f1 316 ++str;
38e16f92
AJ
317 break;
318 }
319 }
320
cb4185f1 321 *p = '\0';
38e16f92
AJ
322}
323
7598eb63
CT
324#if USE_OPENSSL
325static char *
13cd7dee 326sslErrorName(Security::ErrorCode err, char *buf, size_t size)
7598eb63
CT
327{
328 snprintf(buf, size, "SSL_ERR=%d", err);
329 return buf;
330}
331#endif
332
9e8d0e18 333/// XXX: Misnamed. TODO: Split <h (and this function) to distinguish received
501b5d24
AR
334/// headers from sent headers rather than failing to distinguish requests from responses.
335/// \retval HttpReply sent to the HTTP client (access.log and default context).
336/// \retval HttpReply received (encapsulated) from the ICAP server (icap.log context).
337/// \retval HttpRequest received (encapsulated) from the ICAP server (icap.log context).
bd59d61c
EB
338static const HttpMsg *
339actualReplyHeader(const AccessLogEntry::Pointer &al)
340{
341 const HttpMsg *msg = al->reply;
25dadb98 342#if USE_ADAPTATION
501b5d24 343 // al->icap.reqMethod is methodNone in access.log context
bd59d61c
EB
344 if (!msg && al->icap.reqMethod == Adaptation::methodReqmod)
345 msg = al->adapted_request;
25dadb98 346#endif
bd59d61c
EB
347 return msg;
348}
349
501b5d24
AR
350/// XXX: Misnamed. See actualReplyHeader().
351/// \return HttpRequest or HttpReply for %http::>h.
bd59d61c
EB
352static const HttpMsg *
353actualRequestHeader(const AccessLogEntry::Pointer &al)
354{
25dadb98 355#if USE_ADAPTATION
501b5d24 356 // al->icap.reqMethod is methodNone in access.log context
bd59d61c
EB
357 if (al->icap.reqMethod == Adaptation::methodRespmod) {
358 // XXX: for now AccessLogEntry lacks virgin response headers
359 return nullptr;
360 }
25dadb98 361#endif
bd59d61c
EB
362 return al->request;
363}
364
38e16f92 365void
f4698e0b 366Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logSequenceNumber) const
38e16f92
AJ
367{
368 char tmp[1024];
369 String sb;
370
f53969cc 371 for (Token *fmt = format; fmt != NULL; fmt = fmt->next) { /* for each token */
38e16f92
AJ
372 const char *out = NULL;
373 int quote = 0;
374 long int outint = 0;
375 int doint = 0;
376 int dofree = 0;
377 int64_t outoff = 0;
378 int dooff = 0;
01bd87d8
CT
379 struct timeval outtv = {0, 0};
380 int doMsec = 0;
381 int doSec = 0;
38e16f92
AJ
382
383 switch (fmt->type) {
384
385 case LFT_NONE:
386 out = "";
387 break;
388
389 case LFT_STRING:
390 out = fmt->data.string;
391 break;
392
393 case LFT_CLIENT_IP_ADDRESS:
d4204018
AJ
394 al->getLogClientIp(tmp, sizeof(tmp));
395 out = tmp;
38e16f92
AJ
396 break;
397
398 case LFT_CLIENT_FQDN:
4dd643d5 399 if (al->cache.caddr.isAnyAddr()) // e.g., ICAP OPTIONS lack client
38e16f92
AJ
400 out = "-";
401 else
402 out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
403 if (!out) {
4dd643d5 404 out = al->cache.caddr.toStr(tmp,1024);
38e16f92
AJ
405 }
406
407 break;
408
409 case LFT_CLIENT_PORT:
410 if (al->request) {
4dd643d5 411 outint = al->request->client_addr.port();
38e16f92
AJ
412 doint = 1;
413 }
414 break;
415
38e16f92 416 case LFT_CLIENT_EUI:
8652f8e7 417#if USE_SQUID_EUI
38e16f92
AJ
418 // TODO make the ACL checklist have a direct link to any TCP details.
419 if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) {
4dd643d5 420 if (al->request->clientConnectionManager->clientConnection->remote.isIPv4())
38e16f92
AJ
421 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
422 else
423 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
424 out = tmp;
425 }
38e16f92 426#endif
8652f8e7 427 break;
38e16f92 428
4e56d7f6 429 case LFT_EXT_ACL_CLIENT_EUI48:
38d7fa02 430#if USE_SQUID_EUI
4e56d7f6
AJ
431 if (al->request && al->request->clientConnectionManager.valid() &&
432 al->request->clientConnectionManager->clientConnection != NULL &&
433 al->request->clientConnectionManager->clientConnection->remote.isIPv4()) {
434 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
435 out = tmp;
436 }
38d7fa02 437#endif
4e56d7f6
AJ
438 break;
439
440 case LFT_EXT_ACL_CLIENT_EUI64:
38d7fa02 441#if USE_SQUID_EUI
4e56d7f6
AJ
442 if (al->request && al->request->clientConnectionManager.valid() &&
443 al->request->clientConnectionManager->clientConnection != NULL &&
444 !al->request->clientConnectionManager->clientConnection->remote.isIPv4()) {
445 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
446 out = tmp;
447 }
4e56d7f6 448#endif
38d7fa02 449 break;
4e56d7f6 450
8652f8e7
AJ
451 case LFT_SERVER_IP_ADDRESS:
452 if (al->hier.tcpServer != NULL) {
4dd643d5 453 out = al->hier.tcpServer->remote.toStr(tmp,sizeof(tmp));
8652f8e7
AJ
454 }
455 break;
38e16f92 456
8652f8e7 457 case LFT_SERVER_FQDN_OR_PEER_NAME:
38e16f92 458 out = al->hier.host;
38e16f92
AJ
459 break;
460
8652f8e7
AJ
461 case LFT_SERVER_PORT:
462 if (al->hier.tcpServer != NULL) {
4dd643d5 463 outint = al->hier.tcpServer->remote.port();
8652f8e7
AJ
464 doint = 1;
465 }
466 break;
38e16f92 467
28417506
CT
468 case LFT_LOCAL_LISTENING_IP: {
469 // avoid logging a dash if we have reliable info
47176c0b 470 const bool interceptedAtKnownPort = al->request ?
0d901ef4 471 (al->request->flags.interceptTproxy ||
fa720bfb 472 al->request->flags.intercepted) && al->cache.port != NULL :
47176c0b 473 false;
28417506 474 if (interceptedAtKnownPort) {
4dd643d5 475 const bool portAddressConfigured = !al->cache.port->s.isAnyAddr();
28417506 476 if (portAddressConfigured)
4dd643d5 477 out = al->cache.port->s.toStr(tmp, sizeof(tmp));
28417506 478 } else if (al->tcpClient != NULL)
4dd643d5 479 out = al->tcpClient->local.toStr(tmp, sizeof(tmp));
28417506
CT
480 }
481 break;
482
8652f8e7 483 case LFT_CLIENT_LOCAL_IP:
a14f38d0 484 if (al->tcpClient != NULL) {
4dd643d5 485 out = al->tcpClient->local.toStr(tmp,sizeof(tmp));
38e16f92 486 }
38e16f92
AJ
487 break;
488
f123f5e9
CT
489 case LFT_CLIENT_LOCAL_TOS:
490 if (al->tcpClient != NULL) {
491 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->tcpClient->tos);
492 out = tmp;
493 }
494 break;
495
496 case LFT_CLIENT_LOCAL_NFMARK:
497 if (al->tcpClient != NULL) {
498 snprintf(tmp, sizeof(tmp), "0x%x", al->tcpClient->nfmark);
499 out = tmp;
500 }
501 break;
502
28417506 503 case LFT_LOCAL_LISTENING_PORT:
fa720bfb 504 if (al->cache.port != NULL) {
4dd643d5 505 outint = al->cache.port->s.port();
28417506 506 doint = 1;
fbbea662
AJ
507 } else if (al->request) {
508 outint = al->request->my_addr.port();
509 doint = 1;
28417506
CT
510 }
511 break;
512
8652f8e7 513 case LFT_CLIENT_LOCAL_PORT:
a14f38d0 514 if (al->tcpClient != NULL) {
4dd643d5 515 outint = al->tcpClient->local.port();
38e16f92
AJ
516 doint = 1;
517 }
38e16f92
AJ
518 break;
519
8652f8e7
AJ
520 case LFT_SERVER_LOCAL_IP_OLD_27:
521 case LFT_SERVER_LOCAL_IP:
a14f38d0 522 if (al->hier.tcpServer != NULL) {
4dd643d5 523 out = al->hier.tcpServer->local.toStr(tmp,sizeof(tmp));
38e16f92
AJ
524 }
525 break;
526
8652f8e7 527 case LFT_SERVER_LOCAL_PORT:
a14f38d0 528 if (al->hier.tcpServer != NULL) {
4dd643d5 529 outint = al->hier.tcpServer->local.port();
38e16f92
AJ
530 doint = 1;
531 }
532
533 break;
534
f123f5e9
CT
535 case LFT_SERVER_LOCAL_TOS:
536 if (al->hier.tcpServer != NULL) {
537 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->hier.tcpServer->tos);
538 out = tmp;
539 }
540 break;
541
542 case LFT_SERVER_LOCAL_NFMARK:
543 if (al->hier.tcpServer != NULL) {
544 snprintf(tmp, sizeof(tmp), "0x%x", al->hier.tcpServer->nfmark);
545 out = tmp;
546 }
547 break;
548
38e16f92
AJ
549 case LFT_TIME_SECONDS_SINCE_EPOCH:
550 // some platforms store time in 32-bit, some 64-bit...
551 outoff = static_cast<int64_t>(current_time.tv_sec);
552 dooff = 1;
553 break;
554
555 case LFT_TIME_SUBSECOND:
556 outint = current_time.tv_usec / fmt->divisor;
557 doint = 1;
558 break;
559
38e16f92
AJ
560 case LFT_TIME_LOCALTIME:
561
562 case LFT_TIME_GMT: {
563 const char *spec;
564
565 struct tm *t;
b22c1ad3 566 spec = fmt->data.string;
38e16f92
AJ
567
568 if (fmt->type == LFT_TIME_LOCALTIME) {
569 if (!spec)
570 spec = "%d/%b/%Y:%H:%M:%S %z";
571 t = localtime(&squid_curtime);
572 } else {
573 if (!spec)
574 spec = "%d/%b/%Y:%H:%M:%S";
575
576 t = gmtime(&squid_curtime);
577 }
578
579 strftime(tmp, sizeof(tmp), spec, t);
580
581 out = tmp;
582 }
583
584 break;
585
01bd87d8
CT
586 case LFT_TIME_START:
587 outtv = al->cache.start_time;
588 doSec = 1;
f53969cc 589 break;
af0ded40 590
38e16f92 591 case LFT_TIME_TO_HANDLE_REQUEST:
01bd87d8
CT
592 outtv = al->cache.trTime;
593 doMsec = 1;
38e16f92
AJ
594 break;
595
596 case LFT_PEER_RESPONSE_TIME:
01bd87d8 597 if (al->hier.peer_response_time.tv_sec == -1) {
38e16f92
AJ
598 out = "-";
599 } else {
01bd87d8
CT
600 outtv = al->hier.peer_response_time;
601 doMsec = 1;
38e16f92
AJ
602 }
603 break;
604
16b70e2a 605 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME: {
01bd87d8
CT
606 timeval total_response_time;
607 al->hier.totalResponseTime(total_response_time);
608 if (total_response_time.tv_sec == -1) {
38e16f92
AJ
609 out = "-";
610 } else {
01bd87d8
CT
611 outtv = total_response_time;
612 doMsec = 1;
38e16f92 613 }
16b70e2a
CT
614 }
615 break;
38e16f92
AJ
616
617 case LFT_DNS_WAIT_TIME:
618 if (al->request && al->request->dnsWait >= 0) {
01bd87d8
CT
619 // TODO: microsecond precision for dns wait time.
620 // Convert miliseconds to timeval struct:
621 outtv.tv_sec = al->request->dnsWait / 1000;
622 outtv.tv_usec = (al->request->dnsWait % 1000) * 1000;
623 doMsec = 1;
38e16f92
AJ
624 }
625 break;
626
627 case LFT_REQUEST_HEADER:
bd59d61c
EB
628 if (const HttpMsg *msg = actualRequestHeader(al))
629 sb = msg->header.getByName(fmt->data.header.header);
38e16f92
AJ
630
631 out = sb.termedBuf();
632
633 quote = 1;
634
635 break;
636
637 case LFT_ADAPTED_REQUEST_HEADER:
638
38d92afa 639 if (al->adapted_request)
38e16f92
AJ
640 sb = al->adapted_request->header.getByName(fmt->data.header.header);
641
642 out = sb.termedBuf();
643
644 quote = 1;
645
646 break;
647
bd59d61c
EB
648 case LFT_REPLY_HEADER: {
649 if (const HttpMsg *msg = actualReplyHeader(al))
650 sb = msg->header.getByName(fmt->data.header.header);
38e16f92
AJ
651
652 out = sb.termedBuf();
653
654 quote = 1;
bd59d61c
EB
655 }
656 break;
38e16f92
AJ
657
658#if USE_ADAPTATION
31971e6a 659 case LFT_ADAPTATION_SUM_XACT_TIMES:
38e16f92
AJ
660 if (al->request) {
661 Adaptation::History::Pointer ah = al->request->adaptHistory();
662 if (ah != NULL)
663 ah->sumLogString(fmt->data.string, sb);
664 out = sb.termedBuf();
665 }
666 break;
667
31971e6a 668 case LFT_ADAPTATION_ALL_XACT_TIMES:
38e16f92
AJ
669 if (al->request) {
670 Adaptation::History::Pointer ah = al->request->adaptHistory();
671 if (ah != NULL)
672 ah->allLogString(fmt->data.string, sb);
673 out = sb.termedBuf();
674 }
675 break;
676
677 case LFT_ADAPTATION_LAST_HEADER:
678 if (al->request) {
679 const Adaptation::History::Pointer ah = al->request->adaptHistory();
680 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
681 sb = ah->allMeta.getByName(fmt->data.header.header);
682 }
683
684 // XXX: here and elsewhere: move such code inside the if guard
685 out = sb.termedBuf();
686
687 quote = 1;
688
689 break;
690
691 case LFT_ADAPTATION_LAST_HEADER_ELEM:
692 if (al->request) {
693 const Adaptation::History::Pointer ah = al->request->adaptHistory();
694 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
695 sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
696 }
697
698 out = sb.termedBuf();
699
700 quote = 1;
701
702 break;
703
704 case LFT_ADAPTATION_LAST_ALL_HEADERS:
705 out = al->adapt.last_meta;
706
707 quote = 1;
708
709 break;
710#endif
711
712#if ICAP_CLIENT
713 case LFT_ICAP_ADDR:
714 if (!out)
4dd643d5 715 out = al->icap.hostAddr.toStr(tmp,1024);
38e16f92
AJ
716 break;
717
718 case LFT_ICAP_SERV_NAME:
719 out = al->icap.serviceName.termedBuf();
720 break;
721
722 case LFT_ICAP_REQUEST_URI:
723 out = al->icap.reqUri.termedBuf();
724 break;
725
726 case LFT_ICAP_REQUEST_METHOD:
727 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
728 break;
729
730 case LFT_ICAP_BYTES_SENT:
731 outoff = al->icap.bytesSent;
732 dooff = 1;
733 break;
734
735 case LFT_ICAP_BYTES_READ:
736 outoff = al->icap.bytesRead;
737 dooff = 1;
738 break;
739
740 case LFT_ICAP_BODY_BYTES_READ:
741 if (al->icap.bodyBytesRead >= 0) {
742 outoff = al->icap.bodyBytesRead;
743 dooff = 1;
744 }
745 // else if icap.bodyBytesRead < 0, we do not have any http data,
746 // so just print a "-" (204 responses etc)
747 break;
748
749 case LFT_ICAP_REQ_HEADER:
750 if (NULL != al->icap.request) {
751 sb = al->icap.request->header.getByName(fmt->data.header.header);
752 out = sb.termedBuf();
753 quote = 1;
754 }
755 break;
756
757 case LFT_ICAP_REQ_HEADER_ELEM:
7f0ceafc 758 if (al->icap.request)
38e16f92
AJ
759 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
760
761 out = sb.termedBuf();
762
763 quote = 1;
764
765 break;
766
767 case LFT_ICAP_REQ_ALL_HEADERS:
768 if (al->icap.request) {
769 HttpHeaderPos pos = HttpHeaderInitPos;
770 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
771 sb.append(e->name);
772 sb.append(": ");
773 sb.append(e->value);
774 sb.append("\r\n");
775 }
776 out = sb.termedBuf();
777 quote = 1;
778 }
779 break;
780
781 case LFT_ICAP_REP_HEADER:
782 if (NULL != al->icap.reply) {
783 sb = al->icap.reply->header.getByName(fmt->data.header.header);
784 out = sb.termedBuf();
785 quote = 1;
786 }
787 break;
788
789 case LFT_ICAP_REP_HEADER_ELEM:
790 if (NULL != al->icap.reply)
791 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
792
793 out = sb.termedBuf();
794
795 quote = 1;
796
797 break;
798
799 case LFT_ICAP_REP_ALL_HEADERS:
800 if (al->icap.reply) {
801 HttpHeaderPos pos = HttpHeaderInitPos;
802 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
803 sb.append(e->name);
804 sb.append(": ");
805 sb.append(e->value);
806 sb.append("\r\n");
807 }
808 out = sb.termedBuf();
809 quote = 1;
810 }
811 break;
812
813 case LFT_ICAP_TR_RESPONSE_TIME:
01bd87d8
CT
814 outtv = al->icap.trTime;
815 doMsec = 1;
38e16f92
AJ
816 break;
817
818 case LFT_ICAP_IO_TIME:
01bd87d8
CT
819 outtv = al->icap.ioTime;
820 doMsec = 1;
38e16f92
AJ
821 break;
822
823 case LFT_ICAP_STATUS_CODE:
824 outint = al->icap.resStatus;
825 doint = 1;
826 break;
827
828 case LFT_ICAP_OUTCOME:
829 out = al->icap.outcome;
830 break;
831
832 case LFT_ICAP_TOTAL_TIME:
01bd87d8
CT
833 outtv = al->icap.processingTime;
834 doMsec = 1;
38e16f92
AJ
835 break;
836#endif
837 case LFT_REQUEST_HEADER_ELEM:
bd59d61c
EB
838 if (const HttpMsg *msg = actualRequestHeader(al))
839 sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
38e16f92
AJ
840
841 out = sb.termedBuf();
842
843 quote = 1;
844
845 break;
846
847 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
848 if (al->adapted_request)
849 sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
850
851 out = sb.termedBuf();
852
853 quote = 1;
854
855 break;
856
bd59d61c
EB
857 case LFT_REPLY_HEADER_ELEM: {
858 if (const HttpMsg *msg = actualReplyHeader(al))
859 sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
38e16f92
AJ
860
861 out = sb.termedBuf();
862
863 quote = 1;
bd59d61c
EB
864 }
865 break;
38e16f92
AJ
866
867 case LFT_REQUEST_ALL_HEADERS:
25dadb98 868#if USE_ADAPTATION
bd59d61c
EB
869 if (al->icap.reqMethod == Adaptation::methodRespmod) {
870 // XXX: since AccessLogEntry::Headers lacks virgin response
871 // headers, do nothing for now
872 out = nullptr;
25dadb98
AR
873 } else
874#endif
875 {
bd59d61c
EB
876 out = al->headers.request;
877 }
38e16f92
AJ
878
879 quote = 1;
880
881 break;
882
883 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
884 out = al->headers.adapted_request;
885
886 quote = 1;
887
888 break;
889
890 case LFT_REPLY_ALL_HEADERS:
891 out = al->headers.reply;
25dadb98 892#if USE_ADAPTATION
bd59d61c
EB
893 if (!out && al->icap.reqMethod == Adaptation::methodReqmod)
894 out = al->headers.adapted_request;
25dadb98 895#endif
38e16f92
AJ
896
897 quote = 1;
898
899 break;
900
901 case LFT_USER_NAME:
c0e8c76f
AJ
902#if USE_AUTH
903 if (al->request && al->request->auth_user_request != NULL)
904 out = strOrNull(al->request->auth_user_request->username());
905#endif
93cc83e7
AJ
906 if (!out && al->request && al->request->extacl_user.size()) {
907 if (const char *t = al->request->extacl_user.termedBuf())
908 out = t;
909 }
910
38e16f92 911 if (!out)
bd85ea1f 912 out = strOrNull(al->cache.extuser);
93cc83e7 913
cb4f4424 914#if USE_OPENSSL
38e16f92 915 if (!out)
bd85ea1f 916 out = strOrNull(al->cache.ssluser);
38e16f92 917#endif
38e16f92 918 if (!out)
bd85ea1f 919 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
920 break;
921
922 case LFT_USER_LOGIN:
c0e8c76f
AJ
923#if USE_AUTH
924 if (al->request && al->request->auth_user_request != NULL)
925 out = strOrNull(al->request->auth_user_request->username());
926#endif
38e16f92
AJ
927 break;
928
929 case LFT_USER_IDENT:
bd85ea1f 930 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
931 break;
932
933 case LFT_USER_EXTERNAL:
93cc83e7
AJ
934 if (al->request && al->request->extacl_user.size()) {
935 if (const char *t = al->request->extacl_user.termedBuf())
936 out = t;
937 }
4e56d7f6
AJ
938
939 if (!out)
940 out = strOrNull(al->cache.extuser);
38e16f92
AJ
941 break;
942
f53969cc
SM
943 /* case LFT_USER_REALM: */
944 /* case LFT_USER_SCHEME: */
38e16f92 945
f53969cc
SM
946 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
947 // but compiler complains if ommited
38e16f92
AJ
948 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
949 case LFT_HTTP_SENT_STATUS_CODE:
950 outint = al->http.code;
951
952 doint = 1;
953
954 break;
955
956 case LFT_HTTP_RECEIVED_STATUS_CODE:
955394ce 957 if (al->hier.peer_reply_status == Http::scNone) {
38e16f92
AJ
958 out = "-";
959 } else {
960 outint = al->hier.peer_reply_status;
961 doint = 1;
962 }
963 break;
f53969cc
SM
964 /* case LFT_HTTP_STATUS:
965 * out = statusline->text;
966 * quote = 1;
967 * break;
968 */
38e16f92
AJ
969 case LFT_HTTP_BODY_BYTES_READ:
970 if (al->hier.bodyBytesRead >= 0) {
971 outoff = al->hier.bodyBytesRead;
972 dooff = 1;
973 }
974 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
975 // a peer server so just print a "-" (eg requests served from cache,
976 // or internal error messages).
977 break;
978
979 case LFT_SQUID_STATUS:
a981b360 980 out = al->cache.code.c_str();
38e16f92
AJ
981 break;
982
983 case LFT_SQUID_ERROR:
984 if (al->request && al->request->errType != ERR_NONE)
985 out = errorPageName(al->request->errType);
986 break;
987
988 case LFT_SQUID_ERROR_DETAIL:
cb4f4424 989#if USE_OPENSSL
2f3e52b5 990 if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
7598eb63
CT
991 if (! (out = Ssl::GetErrorName(al->request->errDetail)))
992 out = sslErrorName(al->request->errDetail, tmp, sizeof(tmp));
e83cdc25 993 } else
2f3e52b5 994#endif
e83cdc25 995 if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
4e56d7f6 996 if (al->request->errDetail > ERR_DETAIL_START && al->request->errDetail < ERR_DETAIL_MAX)
e83cdc25
A
997 out = errorDetailName(al->request->errDetail);
998 else {
999 if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
1000 snprintf(tmp, sizeof(tmp), "%s=0x%X",
1001 errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
1002 else
1003 snprintf(tmp, sizeof(tmp), "%s=%d",
1004 errorDetailName(al->request->errDetail), al->request->errDetail);
1005 out = tmp;
1006 }
38e16f92 1007 }
38e16f92
AJ
1008 break;
1009
1010 case LFT_SQUID_HIERARCHY:
1011 if (al->hier.ping.timedout)
1012 mb.append("TIMEOUT_", 8);
1013
1014 out = hier_code_str[al->hier.code];
1015
1016 break;
1017
1018 case LFT_MIME_TYPE:
1019 out = al->http.content_type;
1020
1021 break;
1022
1023 case LFT_CLIENT_REQ_METHOD:
1024 if (al->request) {
7f06a3d8
AJ
1025 const SBuf &s = al->request->method.image();
1026 sb.append(s.rawContent(), s.length());
1027 out = sb.termedBuf();
38e16f92
AJ
1028 quote = 1;
1029 }
1030 break;
1031
1032 case LFT_CLIENT_REQ_URI:
1033 // original client URI
1034 if (al->request) {
851feda6
AJ
1035 const SBuf &s = al->request->effectiveRequestUri();
1036 sb.append(s.rawContent(), s.length());
1037 out = sb.termedBuf();
38e16f92
AJ
1038 quote = 1;
1039 }
1040 break;
1041
5aca9cf2
AJ
1042 case LFT_CLIENT_REQ_URLSCHEME:
1043 if (al->request) {
d31d59d8
AJ
1044 const SBuf s(al->request->url.getScheme().image());
1045 sb.append(s.rawContent(), s.length());
1046 out = sb.termedBuf();
5aca9cf2
AJ
1047 quote = 1;
1048 }
1049 break;
1050
fa450988
AJ
1051 case LFT_CLIENT_REQ_URLDOMAIN:
1052 if (al->request) {
5c51bffb 1053 out = al->request->url.host();
fa450988
AJ
1054 quote = 1;
1055 }
1056 break;
1057
5aca9cf2
AJ
1058 case LFT_CLIENT_REQ_URLPORT:
1059 if (al->request) {
5c51bffb 1060 outint = al->request->url.port();
5aca9cf2
AJ
1061 doint = 1;
1062 }
1063 break;
1064
38e16f92
AJ
1065 case LFT_REQUEST_URLPATH_OLD_31:
1066 case LFT_CLIENT_REQ_URLPATH:
1067 if (al->request) {
51b5dcf5
AJ
1068 SBuf s = al->request->url.path();
1069 out = s.c_str();
38e16f92
AJ
1070 quote = 1;
1071 }
1072 break;
1073
1074 case LFT_CLIENT_REQ_VERSION:
1075 if (al->request) {
1076 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
1077 out = tmp;
1078 }
1079 break;
1080
1081 case LFT_REQUEST_METHOD:
3736fdd6
SM
1082 {
1083 const SBuf s(al->getLogMethod());
1084 sb.append(s.rawContent(), s.length());
1085 out = sb.termedBuf();
1086 quote = 1;
1087 }
1088 break;
38e16f92
AJ
1089
1090 case LFT_REQUEST_URI:
f57ae909
NH
1091 if (!al->url.isEmpty()) {
1092 const SBuf &s = al->url;
1093 sb.append(s.rawContent(), s.length());
1094 out = sb.termedBuf();
1095 }
38e16f92
AJ
1096 break;
1097
1098 case LFT_REQUEST_VERSION_OLD_2X:
1099 case LFT_REQUEST_VERSION:
1100 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
1101 out = tmp;
1102 break;
1103
1104 case LFT_SERVER_REQ_METHOD:
1105 if (al->adapted_request) {
7f06a3d8
AJ
1106 const SBuf &s = al->adapted_request->method.image();
1107 sb.append(s.rawContent(), s.length());
1108 out = sb.termedBuf();
38e16f92
AJ
1109 quote = 1;
1110 }
1111 break;
1112
1113 case LFT_SERVER_REQ_URI:
1114 // adapted request URI sent to server/peer
1115 if (al->adapted_request) {
851feda6
AJ
1116 const SBuf &s = al->adapted_request->effectiveRequestUri();
1117 sb.append(s.rawContent(), s.length());
1118 out = sb.termedBuf();
38e16f92
AJ
1119 quote = 1;
1120 }
1121 break;
1122
5aca9cf2
AJ
1123 case LFT_SERVER_REQ_URLSCHEME:
1124 if (al->adapted_request) {
d31d59d8
AJ
1125 const SBuf s(al->adapted_request->url.getScheme().image());
1126 sb.append(s.rawContent(), s.length());
1127 out = sb.termedBuf();
5aca9cf2
AJ
1128 quote = 1;
1129 }
1130 break;
1131
1132 case LFT_SERVER_REQ_URLDOMAIN:
1133 if (al->adapted_request) {
5c51bffb 1134 out = al->adapted_request->url.host();
5aca9cf2
AJ
1135 quote = 1;
1136 }
1137 break;
1138
1139 case LFT_SERVER_REQ_URLPORT:
1140 if (al->adapted_request) {
5c51bffb 1141 outint = al->adapted_request->url.port();
5aca9cf2
AJ
1142 doint = 1;
1143 }
1144 break;
1145
38e16f92
AJ
1146 case LFT_SERVER_REQ_URLPATH:
1147 if (al->adapted_request) {
51b5dcf5
AJ
1148 SBuf s = al->adapted_request->url.path();
1149 out = s.c_str();
38e16f92
AJ
1150 quote = 1;
1151 }
1152 break;
1153
1154 case LFT_SERVER_REQ_VERSION:
1155 if (al->adapted_request) {
1156 snprintf(tmp, sizeof(tmp), "%d.%d",
1157 (int) al->adapted_request->http_ver.major,
1158 (int) al->adapted_request->http_ver.minor);
1159 out = tmp;
1160 }
1161 break;
1162
d6df21d2 1163 case LFT_CLIENT_REQUEST_SIZE_TOTAL:
cc0ca3b9 1164 outoff = al->http.clientRequestSz.messageTotal();
38e16f92
AJ
1165 dooff = 1;
1166 break;
1167
d6df21d2 1168 case LFT_CLIENT_REQUEST_SIZE_HEADERS:
cc0ca3b9 1169 outoff = al->http.clientRequestSz.header;
38e16f92
AJ
1170 dooff =1;
1171 break;
d6df21d2 1172
f53969cc
SM
1173 /*case LFT_REQUEST_SIZE_BODY: */
1174 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
38e16f92 1175
d6df21d2 1176 case LFT_ADAPTED_REPLY_SIZE_TOTAL:
cc0ca3b9 1177 outoff = al->http.clientReplySz.messageTotal();
38e16f92
AJ
1178 dooff = 1;
1179 break;
1180
1181 case LFT_REPLY_HIGHOFFSET:
1182 outoff = al->cache.highOffset;
1183
1184 dooff = 1;
1185
1186 break;
1187
1188 case LFT_REPLY_OBJECTSIZE:
1189 outoff = al->cache.objectSize;
1190
1191 dooff = 1;
1192
1193 break;
1194
d6df21d2 1195 case LFT_ADAPTED_REPLY_SIZE_HEADERS:
cc0ca3b9 1196 outint = al->http.clientReplySz.header;
38e16f92
AJ
1197 doint = 1;
1198 break;
d6df21d2 1199
f53969cc
SM
1200 /*case LFT_REPLY_SIZE_BODY: */
1201 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
38e16f92 1202
d6df21d2 1203 case LFT_CLIENT_IO_SIZE_TOTAL:
cc0ca3b9 1204 outint = al->http.clientRequestSz.messageTotal() + al->http.clientReplySz.messageTotal();
d6df21d2
AJ
1205 doint = 1;
1206 break;
f53969cc 1207 /*case LFT_SERVER_IO_SIZE_TOTAL: */
d6df21d2 1208
38e16f92
AJ
1209 case LFT_TAG:
1210 if (al->request)
1211 out = al->request->tag.termedBuf();
1212
1213 quote = 1;
1214
1215 break;
1216
38e16f92
AJ
1217 case LFT_EXT_LOG:
1218 if (al->request)
1219 out = al->request->extacl_log.termedBuf();
1220
1221 quote = 1;
1222
1223 break;
1224
1225 case LFT_SEQUENCE_NUMBER:
1226 outoff = logSequenceNumber;
1227 dooff = 1;
1228 break;
1229
cb4f4424 1230#if USE_OPENSSL
08097970
AR
1231 case LFT_SSL_BUMP_MODE: {
1232 const Ssl::BumpMode mode = static_cast<Ssl::BumpMode>(al->ssl.bumpMode);
1233 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1234 out = Ssl::bumpMode(mode);
08097970 1235 }
3736fdd6 1236 break;
4e56d7f6
AJ
1237
1238 case LFT_EXT_ACL_USER_CERT_RAW:
1239 if (al->request) {
1240 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1241 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1242 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
4e56d7f6
AJ
1243 out = sslGetUserCertificatePEM(ssl);
1244 }
1245 }
1246 break;
1247
1248 case LFT_EXT_ACL_USER_CERTCHAIN_RAW:
1249 if (al->request) {
1250 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1251 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1252 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
4e56d7f6
AJ
1253 out = sslGetUserCertificatePEM(ssl);
1254 }
1255 }
1256 break;
1257
1258 case LFT_EXT_ACL_USER_CERT:
1259 if (al->request) {
1260 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1261 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1262 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
4e56d7f6
AJ
1263 out = sslGetUserAttribute(ssl, format->data.header.header);
1264 }
1265 }
1266 break;
1267
1268 case LFT_EXT_ACL_USER_CA_CERT:
1269 if (al->request) {
1270 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1271 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1272 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
3736fdd6 1273 out = sslGetCAAttribute(ssl, format->data.header.header);
4e56d7f6
AJ
1274 }
1275 }
1276 break;
71cae389 1277
f4698e0b
CT
1278 case LFT_SSL_USER_CERT_SUBJECT:
1279 if (X509 *cert = al->cache.sslClientCert.get()) {
1280 if (X509_NAME *subject = X509_get_subject_name(cert)) {
1281 X509_NAME_oneline(subject, tmp, sizeof(tmp));
1282 out = tmp;
1283 }
1284 }
1285 break;
1286
1287 case LFT_SSL_USER_CERT_ISSUER:
1288 if (X509 *cert = al->cache.sslClientCert.get()) {
1289 if (X509_NAME *issuer = X509_get_issuer_name(cert)) {
1290 X509_NAME_oneline(issuer, tmp, sizeof(tmp));
1291 out = tmp;
1292 }
1293 }
1294 break;
4e56d7f6 1295
cedca6e7
CT
1296 case LFT_SSL_CLIENT_SNI:
1297 if (al->request && al->request->clientConnectionManager.valid()) {
1298 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1299 if (!srvBump->clientSni.isEmpty())
1300 out = srvBump->clientSni.c_str();
1301 }
1302 }
1303 break;
789dda8d 1304
7598eb63
CT
1305 case LFT_SSL_SERVER_CERT_ERRORS:
1306 if (al->request && al->request->clientConnectionManager.valid()) {
1307 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1308 const char *separator = fmt->data.string ? fmt->data.string : ":";
92e3827b 1309 for (const Security::CertErrors *sslError = srvBump->sslErrors(); sslError != nullptr; sslError = sslError->next) {
7598eb63
CT
1310 if (sb.size())
1311 sb.append(separator);
1312 if (const char *errorName = Ssl::GetErrorName(sslError->element.code))
1313 sb.append(errorName);
1314 else
1315 sb.append(sslErrorName(sslError->element.code, tmp, sizeof(tmp)));
b4e6a8d4
CT
1316 if (sslError->element.depth >= 0) {
1317 snprintf(tmp, sizeof(tmp), "@depth=%d", sslError->element.depth);
1318 sb.append(tmp);
1319 }
7598eb63
CT
1320 }
1321 if (sb.size())
1322 out = sb.termedBuf();
1323 }
1324 }
cedca6e7 1325 break;
789dda8d
CT
1326
1327 case LFT_SSL_SERVER_CERT_ISSUER:
1328 case LFT_SSL_SERVER_CERT_SUBJECT:
d4ddb3e6
CT
1329 if (al->request && al->request->clientConnectionManager.valid()) {
1330 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1331 if (X509 *serverCert = srvBump->serverCert.get()) {
1332 if (fmt->type == LFT_SSL_SERVER_CERT_SUBJECT)
1333 out = Ssl::GetX509UserAttribute(serverCert, "DN");
1334 else
1335 out = Ssl::GetX509CAAttribute(serverCert, "DN");
1336 }
1337 }
1338 }
789dda8d 1339 break;
2bcab852
CT
1340
1341 case LFT_TLS_CLIENT_NEGOTIATED_VERSION:
1342 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1343 out = al->tcpClient->hasTlsNegotiations()->negotiatedVersion();
1344 break;
1345
1346 case LFT_TLS_SERVER_NEGOTIATED_VERSION:
1347 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1348 out = al->hier.tcpServer->hasTlsNegotiations()->negotiatedVersion();
1349 break;
1350
1351 case LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION:
1352 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1353 out = al->tcpClient->hasTlsNegotiations()->helloVersion();
1354 break;
1355
1356 case LFT_TLS_SERVER_RECEIVED_HELLO_VERSION:
1357 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1358 out = al->hier.tcpServer->hasTlsNegotiations()->helloVersion();
1359 break;
1360
1361 case LFT_TLS_CLIENT_SUPPORTED_VERSION:
1362 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1363 out = al->tcpClient->hasTlsNegotiations()->supportedVersion();
1364 break;
1365
1366 case LFT_TLS_SERVER_SUPPORTED_VERSION:
1367 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1368 out = al->hier.tcpServer->hasTlsNegotiations()->supportedVersion();
1369 break;
1370
1371 case LFT_TLS_CLIENT_NEGOTIATED_CIPHER:
1372 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1373 out = al->tcpClient->hasTlsNegotiations()->cipherName();
1374 break;
1375
1376 case LFT_TLS_SERVER_NEGOTIATED_CIPHER:
1377 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1378 out = al->hier.tcpServer->hasTlsNegotiations()->cipherName();
1379 break;
08097970 1380#endif
f123f5e9 1381
d074f918
TT
1382 case LFT_REQUEST_URLGROUP_OLD_2X:
1383 assert(LFT_REQUEST_URLGROUP_OLD_2X == 0); // should never happen.
1384
d7f4a0b7 1385 case LFT_NOTE:
c7bcf010
CT
1386 tmp[0] = fmt->data.header.separator;
1387 tmp[1] = '\0';
1388 if (fmt->data.header.header && *fmt->data.header.header) {
1389 const char *separator = tmp;
cf9f0261 1390#if USE_ADAPTATION
7f0ceafc 1391 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
cf9f0261 1392 if (ah != NULL && ah->metaHeaders != NULL) {
c7bcf010 1393 if (const char *meta = ah->metaHeaders->find(fmt->data.header.header, separator))
cf9f0261
CT
1394 sb.append(meta);
1395 }
1396#endif
f4f55a21 1397 if (al->notes != NULL) {
c7bcf010 1398 if (const char *note = al->notes->find(fmt->data.header.header, separator)) {
cf9f0261 1399 if (sb.size())
c7bcf010 1400 sb.append(separator);
cf9f0261
CT
1401 sb.append(note);
1402 }
1403 }
d7f4a0b7
CT
1404 out = sb.termedBuf();
1405 quote = 1;
1406 } else {
c7bcf010
CT
1407 // if no argument given use default "\r\n" as notes separator
1408 const char *separator = fmt->data.string ? tmp : "\r\n";
cf9f0261 1409#if USE_ADAPTATION
7f0ceafc 1410 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
cf9f0261 1411 if (ah != NULL && ah->metaHeaders != NULL && !ah->metaHeaders->empty())
c7bcf010 1412 sb.append(ah->metaHeaders->toString(separator));
cf9f0261 1413#endif
f4f55a21 1414 if (al->notes != NULL && !al->notes->empty())
c7bcf010 1415 sb.append(al->notes->toString(separator));
f4f55a21 1416
d7f4a0b7
CT
1417 out = sb.termedBuf();
1418 quote = 1;
1419 }
1420 break;
08097970 1421
d4806c91
CT
1422 case LFT_CREDENTIALS:
1423#if USE_AUTH
1424 if (al->request && al->request->auth_user_request != NULL)
1425 out = strOrNull(al->request->auth_user_request->credentialsStr());
1426#endif
1427
1428 break;
1429
38e16f92
AJ
1430 case LFT_PERCENT:
1431 out = "%";
5aca9cf2 1432 break;
38e16f92 1433
5aca9cf2 1434 case LFT_EXT_ACL_NAME:
4ff6370b 1435 out = al->lastAclName;
4e56d7f6
AJ
1436 break;
1437
5aca9cf2 1438 case LFT_EXT_ACL_DATA:
b0e14ce2
NH
1439 if (!al->lastAclData.isEmpty())
1440 out = al->lastAclData.c_str();
38e16f92
AJ
1441 break;
1442 }
1443
1444 if (dooff) {
8846a2b4 1445 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff);
38e16f92
AJ
1446 out = tmp;
1447
1448 } else if (doint) {
8846a2b4 1449 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
38e16f92 1450 out = tmp;
01bd87d8
CT
1451 } else if (doMsec) {
1452 if (fmt->widthMax < 0) {
1453 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->widthMin , tvToMsec(outtv));
1454 } else {
1455 int precision = fmt->widthMax;
1456 snprintf(tmp, sizeof(tmp), "%0*" PRId64 ".%0*" PRId64 "", fmt->zero && (fmt->widthMin - precision - 1 >= 0) ? fmt->widthMin - precision - 1 : 0, static_cast<int64_t>(outtv.tv_sec * 1000 + outtv.tv_usec / 1000), precision, static_cast<int64_t>((outtv.tv_usec % 1000 )* (1000 / fmt->divisor)));
1457 }
1458 out = tmp;
1459 } else if (doSec) {
1460 int precision = fmt->widthMax >=0 ? fmt->widthMax :3;
1461 snprintf(tmp, sizeof(tmp), "%0*" PRId64 ".%0*d", fmt->zero && (fmt->widthMin - precision - 1 >= 0) ? fmt->widthMin - precision - 1 : 0, static_cast<int64_t>(outtv.tv_sec), precision, (int)(outtv.tv_usec / fmt->divisor));
1462 out = tmp;
38e16f92
AJ
1463 }
1464
1465 if (out && *out) {
1466 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1467 char *newout = NULL;
1468 int newfree = 0;
1469
1470 switch (fmt->quote) {
1471
1472 case LOG_QUOTE_NONE:
1473 newout = rfc1738_escape_unescaped(out);
1474 break;
1475
1476 case LOG_QUOTE_QUOTES: {
1477 size_t out_len = static_cast<size_t>(strlen(out)) * 2 + 1;
1478 if (out_len >= sizeof(tmp)) {
1479 newout = (char *)xmalloc(out_len);
1480 newfree = 1;
1481 } else
1482 newout = tmp;
1483 log_quoted_string(out, newout);
1484 }
1485 break;
1486
1487 case LOG_QUOTE_MIMEBLOB:
1488 newout = QuoteMimeBlob(out);
1489 newfree = 1;
1490 break;
1491
1492 case LOG_QUOTE_URL:
1493 newout = rfc1738_escape(out);
1494 break;
1495
95d78f10
AJ
1496 case LOG_QUOTE_SHELL: {
1497 MemBuf mbq;
1498 mbq.init();
1499 strwordquote(&mbq, out);
1500 newout = mbq.content();
1501 mbq.stolen = 1;
1502 newfree = 1;
3736fdd6
SM
1503 }
1504 break;
95d78f10 1505
38e16f92
AJ
1506 case LOG_QUOTE_RAW:
1507 break;
1508 }
1509
1510 if (newout) {
1511 if (dofree)
1512 safe_free(out);
1513
1514 out = newout;
1515
1516 dofree = newfree;
1517 }
1518 }
1519
c32c6db7 1520 // enforce width limits if configured
01bd87d8 1521 const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff && !doMsec && !doSec;
8846a2b4
CT
1522 if (haveMaxWidth || fmt->widthMin) {
1523 const int minWidth = fmt->widthMin >= 0 ?
b8ad91f5 1524 fmt->widthMin :0;
c32c6db7 1525 const int maxWidth = haveMaxWidth ?
8846a2b4 1526 fmt->widthMax : strlen(out);
c32c6db7 1527
38e16f92 1528 if (fmt->left)
4391cd15 1529 mb.appendf("%-*.*s", minWidth, maxWidth, out);
38e16f92 1530 else
4391cd15 1531 mb.appendf("%*.*s", minWidth, maxWidth, out);
38e16f92
AJ
1532 } else
1533 mb.append(out, strlen(out));
1534 } else {
1535 mb.append("-", 1);
1536 }
1537
1538 if (fmt->space)
1539 mb.append(" ", 1);
1540
1541 sb.clean();
1542
1543 if (dofree)
1544 safe_free(out);
1545 }
1546}
f53969cc 1547