]> git.ipfire.org Git - thirdparty/squid.git/blame - src/format/Format.cc
squidclient: link GnuTLS library debug to -v level display
[thirdparty/squid.git] / src / format / Format.cc
CommitLineData
bbc27441 1/*
4ac4a490 2 * Copyright (C) 1996-2017 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;
c529dfc7 342#if ICAP_CLIENT
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{
c529dfc7 355#if ICAP_CLIENT
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 412 doint = 1;
57462605
AR
413 } else if (al->tcpClient) {
414 outint = al->tcpClient->remote.port();
415 doint = 1;
38e16f92
AJ
416 }
417 break;
418
38e16f92 419 case LFT_CLIENT_EUI:
8652f8e7 420#if USE_SQUID_EUI
38e16f92
AJ
421 // TODO make the ACL checklist have a direct link to any TCP details.
422 if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) {
4dd643d5 423 if (al->request->clientConnectionManager->clientConnection->remote.isIPv4())
38e16f92
AJ
424 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
425 else
426 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
427 out = tmp;
428 }
38e16f92 429#endif
8652f8e7 430 break;
38e16f92 431
4e56d7f6 432 case LFT_EXT_ACL_CLIENT_EUI48:
38d7fa02 433#if USE_SQUID_EUI
4e56d7f6
AJ
434 if (al->request && al->request->clientConnectionManager.valid() &&
435 al->request->clientConnectionManager->clientConnection != NULL &&
436 al->request->clientConnectionManager->clientConnection->remote.isIPv4()) {
437 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
438 out = tmp;
439 }
38d7fa02 440#endif
4e56d7f6
AJ
441 break;
442
443 case LFT_EXT_ACL_CLIENT_EUI64:
38d7fa02 444#if USE_SQUID_EUI
4e56d7f6
AJ
445 if (al->request && al->request->clientConnectionManager.valid() &&
446 al->request->clientConnectionManager->clientConnection != NULL &&
447 !al->request->clientConnectionManager->clientConnection->remote.isIPv4()) {
448 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
449 out = tmp;
450 }
4e56d7f6 451#endif
38d7fa02 452 break;
4e56d7f6 453
8652f8e7
AJ
454 case LFT_SERVER_IP_ADDRESS:
455 if (al->hier.tcpServer != NULL) {
4dd643d5 456 out = al->hier.tcpServer->remote.toStr(tmp,sizeof(tmp));
8652f8e7
AJ
457 }
458 break;
38e16f92 459
8652f8e7 460 case LFT_SERVER_FQDN_OR_PEER_NAME:
38e16f92 461 out = al->hier.host;
38e16f92
AJ
462 break;
463
8652f8e7
AJ
464 case LFT_SERVER_PORT:
465 if (al->hier.tcpServer != NULL) {
4dd643d5 466 outint = al->hier.tcpServer->remote.port();
8652f8e7
AJ
467 doint = 1;
468 }
469 break;
38e16f92 470
28417506
CT
471 case LFT_LOCAL_LISTENING_IP: {
472 // avoid logging a dash if we have reliable info
47176c0b 473 const bool interceptedAtKnownPort = al->request ?
0d901ef4 474 (al->request->flags.interceptTproxy ||
fa720bfb 475 al->request->flags.intercepted) && al->cache.port != NULL :
47176c0b 476 false;
28417506 477 if (interceptedAtKnownPort) {
4dd643d5 478 const bool portAddressConfigured = !al->cache.port->s.isAnyAddr();
28417506 479 if (portAddressConfigured)
4dd643d5 480 out = al->cache.port->s.toStr(tmp, sizeof(tmp));
28417506 481 } else if (al->tcpClient != NULL)
4dd643d5 482 out = al->tcpClient->local.toStr(tmp, sizeof(tmp));
28417506
CT
483 }
484 break;
485
8652f8e7 486 case LFT_CLIENT_LOCAL_IP:
a14f38d0 487 if (al->tcpClient != NULL) {
4dd643d5 488 out = al->tcpClient->local.toStr(tmp,sizeof(tmp));
38e16f92 489 }
38e16f92
AJ
490 break;
491
f123f5e9
CT
492 case LFT_CLIENT_LOCAL_TOS:
493 if (al->tcpClient != NULL) {
494 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->tcpClient->tos);
495 out = tmp;
496 }
497 break;
498
499 case LFT_CLIENT_LOCAL_NFMARK:
500 if (al->tcpClient != NULL) {
501 snprintf(tmp, sizeof(tmp), "0x%x", al->tcpClient->nfmark);
502 out = tmp;
503 }
504 break;
505
28417506 506 case LFT_LOCAL_LISTENING_PORT:
fa720bfb 507 if (al->cache.port != NULL) {
4dd643d5 508 outint = al->cache.port->s.port();
28417506 509 doint = 1;
fbbea662
AJ
510 } else if (al->request) {
511 outint = al->request->my_addr.port();
512 doint = 1;
28417506
CT
513 }
514 break;
515
8652f8e7 516 case LFT_CLIENT_LOCAL_PORT:
a14f38d0 517 if (al->tcpClient != NULL) {
4dd643d5 518 outint = al->tcpClient->local.port();
38e16f92
AJ
519 doint = 1;
520 }
38e16f92
AJ
521 break;
522
8652f8e7
AJ
523 case LFT_SERVER_LOCAL_IP_OLD_27:
524 case LFT_SERVER_LOCAL_IP:
a14f38d0 525 if (al->hier.tcpServer != NULL) {
4dd643d5 526 out = al->hier.tcpServer->local.toStr(tmp,sizeof(tmp));
38e16f92
AJ
527 }
528 break;
529
8652f8e7 530 case LFT_SERVER_LOCAL_PORT:
a14f38d0 531 if (al->hier.tcpServer != NULL) {
4dd643d5 532 outint = al->hier.tcpServer->local.port();
38e16f92
AJ
533 doint = 1;
534 }
535
536 break;
537
f123f5e9
CT
538 case LFT_SERVER_LOCAL_TOS:
539 if (al->hier.tcpServer != NULL) {
540 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->hier.tcpServer->tos);
541 out = tmp;
542 }
543 break;
544
545 case LFT_SERVER_LOCAL_NFMARK:
546 if (al->hier.tcpServer != NULL) {
547 snprintf(tmp, sizeof(tmp), "0x%x", al->hier.tcpServer->nfmark);
548 out = tmp;
549 }
550 break;
551
38e16f92
AJ
552 case LFT_TIME_SECONDS_SINCE_EPOCH:
553 // some platforms store time in 32-bit, some 64-bit...
554 outoff = static_cast<int64_t>(current_time.tv_sec);
555 dooff = 1;
556 break;
557
558 case LFT_TIME_SUBSECOND:
559 outint = current_time.tv_usec / fmt->divisor;
560 doint = 1;
561 break;
562
38e16f92
AJ
563 case LFT_TIME_LOCALTIME:
564
565 case LFT_TIME_GMT: {
566 const char *spec;
567
568 struct tm *t;
b22c1ad3 569 spec = fmt->data.string;
38e16f92
AJ
570
571 if (fmt->type == LFT_TIME_LOCALTIME) {
572 if (!spec)
573 spec = "%d/%b/%Y:%H:%M:%S %z";
574 t = localtime(&squid_curtime);
575 } else {
576 if (!spec)
577 spec = "%d/%b/%Y:%H:%M:%S";
578
579 t = gmtime(&squid_curtime);
580 }
581
582 strftime(tmp, sizeof(tmp), spec, t);
583
584 out = tmp;
585 }
586
587 break;
588
01bd87d8
CT
589 case LFT_TIME_START:
590 outtv = al->cache.start_time;
591 doSec = 1;
f53969cc 592 break;
af0ded40 593
38e16f92 594 case LFT_TIME_TO_HANDLE_REQUEST:
01bd87d8
CT
595 outtv = al->cache.trTime;
596 doMsec = 1;
38e16f92
AJ
597 break;
598
599 case LFT_PEER_RESPONSE_TIME:
01bd87d8 600 if (al->hier.peer_response_time.tv_sec == -1) {
38e16f92
AJ
601 out = "-";
602 } else {
01bd87d8
CT
603 outtv = al->hier.peer_response_time;
604 doMsec = 1;
38e16f92
AJ
605 }
606 break;
607
16b70e2a 608 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME: {
01bd87d8
CT
609 timeval total_response_time;
610 al->hier.totalResponseTime(total_response_time);
611 if (total_response_time.tv_sec == -1) {
38e16f92
AJ
612 out = "-";
613 } else {
01bd87d8
CT
614 outtv = total_response_time;
615 doMsec = 1;
38e16f92 616 }
16b70e2a
CT
617 }
618 break;
38e16f92
AJ
619
620 case LFT_DNS_WAIT_TIME:
621 if (al->request && al->request->dnsWait >= 0) {
01bd87d8
CT
622 // TODO: microsecond precision for dns wait time.
623 // Convert miliseconds to timeval struct:
624 outtv.tv_sec = al->request->dnsWait / 1000;
625 outtv.tv_usec = (al->request->dnsWait % 1000) * 1000;
626 doMsec = 1;
38e16f92
AJ
627 }
628 break;
629
630 case LFT_REQUEST_HEADER:
bd59d61c
EB
631 if (const HttpMsg *msg = actualRequestHeader(al))
632 sb = msg->header.getByName(fmt->data.header.header);
38e16f92
AJ
633
634 out = sb.termedBuf();
635
636 quote = 1;
637
638 break;
639
640 case LFT_ADAPTED_REQUEST_HEADER:
641
38d92afa 642 if (al->adapted_request)
38e16f92
AJ
643 sb = al->adapted_request->header.getByName(fmt->data.header.header);
644
645 out = sb.termedBuf();
646
647 quote = 1;
648
649 break;
650
bd59d61c
EB
651 case LFT_REPLY_HEADER: {
652 if (const HttpMsg *msg = actualReplyHeader(al))
653 sb = msg->header.getByName(fmt->data.header.header);
38e16f92
AJ
654
655 out = sb.termedBuf();
656
657 quote = 1;
bd59d61c
EB
658 }
659 break;
38e16f92
AJ
660
661#if USE_ADAPTATION
31971e6a 662 case LFT_ADAPTATION_SUM_XACT_TIMES:
38e16f92
AJ
663 if (al->request) {
664 Adaptation::History::Pointer ah = al->request->adaptHistory();
665 if (ah != NULL)
666 ah->sumLogString(fmt->data.string, sb);
667 out = sb.termedBuf();
668 }
669 break;
670
31971e6a 671 case LFT_ADAPTATION_ALL_XACT_TIMES:
38e16f92
AJ
672 if (al->request) {
673 Adaptation::History::Pointer ah = al->request->adaptHistory();
674 if (ah != NULL)
675 ah->allLogString(fmt->data.string, sb);
676 out = sb.termedBuf();
677 }
678 break;
679
680 case LFT_ADAPTATION_LAST_HEADER:
681 if (al->request) {
682 const Adaptation::History::Pointer ah = al->request->adaptHistory();
683 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
684 sb = ah->allMeta.getByName(fmt->data.header.header);
685 }
686
687 // XXX: here and elsewhere: move such code inside the if guard
688 out = sb.termedBuf();
689
690 quote = 1;
691
692 break;
693
694 case LFT_ADAPTATION_LAST_HEADER_ELEM:
695 if (al->request) {
696 const Adaptation::History::Pointer ah = al->request->adaptHistory();
697 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
698 sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
699 }
700
701 out = sb.termedBuf();
702
703 quote = 1;
704
705 break;
706
707 case LFT_ADAPTATION_LAST_ALL_HEADERS:
708 out = al->adapt.last_meta;
709
710 quote = 1;
711
712 break;
713#endif
714
715#if ICAP_CLIENT
716 case LFT_ICAP_ADDR:
717 if (!out)
4dd643d5 718 out = al->icap.hostAddr.toStr(tmp,1024);
38e16f92
AJ
719 break;
720
721 case LFT_ICAP_SERV_NAME:
722 out = al->icap.serviceName.termedBuf();
723 break;
724
725 case LFT_ICAP_REQUEST_URI:
726 out = al->icap.reqUri.termedBuf();
727 break;
728
729 case LFT_ICAP_REQUEST_METHOD:
730 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
731 break;
732
733 case LFT_ICAP_BYTES_SENT:
734 outoff = al->icap.bytesSent;
735 dooff = 1;
736 break;
737
738 case LFT_ICAP_BYTES_READ:
739 outoff = al->icap.bytesRead;
740 dooff = 1;
741 break;
742
743 case LFT_ICAP_BODY_BYTES_READ:
744 if (al->icap.bodyBytesRead >= 0) {
745 outoff = al->icap.bodyBytesRead;
746 dooff = 1;
747 }
748 // else if icap.bodyBytesRead < 0, we do not have any http data,
749 // so just print a "-" (204 responses etc)
750 break;
751
752 case LFT_ICAP_REQ_HEADER:
753 if (NULL != al->icap.request) {
754 sb = al->icap.request->header.getByName(fmt->data.header.header);
755 out = sb.termedBuf();
756 quote = 1;
757 }
758 break;
759
760 case LFT_ICAP_REQ_HEADER_ELEM:
7f0ceafc 761 if (al->icap.request)
38e16f92
AJ
762 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
763
764 out = sb.termedBuf();
765
766 quote = 1;
767
768 break;
769
770 case LFT_ICAP_REQ_ALL_HEADERS:
771 if (al->icap.request) {
772 HttpHeaderPos pos = HttpHeaderInitPos;
773 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
774 sb.append(e->name);
775 sb.append(": ");
776 sb.append(e->value);
777 sb.append("\r\n");
778 }
779 out = sb.termedBuf();
780 quote = 1;
781 }
782 break;
783
784 case LFT_ICAP_REP_HEADER:
785 if (NULL != al->icap.reply) {
786 sb = al->icap.reply->header.getByName(fmt->data.header.header);
787 out = sb.termedBuf();
788 quote = 1;
789 }
790 break;
791
792 case LFT_ICAP_REP_HEADER_ELEM:
793 if (NULL != al->icap.reply)
794 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
795
796 out = sb.termedBuf();
797
798 quote = 1;
799
800 break;
801
802 case LFT_ICAP_REP_ALL_HEADERS:
803 if (al->icap.reply) {
804 HttpHeaderPos pos = HttpHeaderInitPos;
805 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
806 sb.append(e->name);
807 sb.append(": ");
808 sb.append(e->value);
809 sb.append("\r\n");
810 }
811 out = sb.termedBuf();
812 quote = 1;
813 }
814 break;
815
816 case LFT_ICAP_TR_RESPONSE_TIME:
01bd87d8
CT
817 outtv = al->icap.trTime;
818 doMsec = 1;
38e16f92
AJ
819 break;
820
821 case LFT_ICAP_IO_TIME:
01bd87d8
CT
822 outtv = al->icap.ioTime;
823 doMsec = 1;
38e16f92
AJ
824 break;
825
826 case LFT_ICAP_STATUS_CODE:
827 outint = al->icap.resStatus;
828 doint = 1;
829 break;
830
831 case LFT_ICAP_OUTCOME:
832 out = al->icap.outcome;
833 break;
834
835 case LFT_ICAP_TOTAL_TIME:
01bd87d8
CT
836 outtv = al->icap.processingTime;
837 doMsec = 1;
38e16f92
AJ
838 break;
839#endif
840 case LFT_REQUEST_HEADER_ELEM:
bd59d61c
EB
841 if (const HttpMsg *msg = actualRequestHeader(al))
842 sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
38e16f92
AJ
843
844 out = sb.termedBuf();
845
846 quote = 1;
847
848 break;
849
850 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
851 if (al->adapted_request)
852 sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
853
854 out = sb.termedBuf();
855
856 quote = 1;
857
858 break;
859
bd59d61c
EB
860 case LFT_REPLY_HEADER_ELEM: {
861 if (const HttpMsg *msg = actualReplyHeader(al))
862 sb = msg->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
38e16f92
AJ
863
864 out = sb.termedBuf();
865
866 quote = 1;
bd59d61c
EB
867 }
868 break;
38e16f92
AJ
869
870 case LFT_REQUEST_ALL_HEADERS:
c529dfc7 871#if ICAP_CLIENT
bd59d61c
EB
872 if (al->icap.reqMethod == Adaptation::methodRespmod) {
873 // XXX: since AccessLogEntry::Headers lacks virgin response
874 // headers, do nothing for now
875 out = nullptr;
25dadb98
AR
876 } else
877#endif
878 {
bd59d61c
EB
879 out = al->headers.request;
880 }
38e16f92
AJ
881
882 quote = 1;
883
884 break;
885
886 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
887 out = al->headers.adapted_request;
888
889 quote = 1;
890
891 break;
892
893 case LFT_REPLY_ALL_HEADERS:
894 out = al->headers.reply;
c529dfc7 895#if ICAP_CLIENT
bd59d61c
EB
896 if (!out && al->icap.reqMethod == Adaptation::methodReqmod)
897 out = al->headers.adapted_request;
25dadb98 898#endif
38e16f92
AJ
899
900 quote = 1;
901
902 break;
903
904 case LFT_USER_NAME:
c0e8c76f
AJ
905#if USE_AUTH
906 if (al->request && al->request->auth_user_request != NULL)
907 out = strOrNull(al->request->auth_user_request->username());
908#endif
93cc83e7
AJ
909 if (!out && al->request && al->request->extacl_user.size()) {
910 if (const char *t = al->request->extacl_user.termedBuf())
911 out = t;
912 }
913
38e16f92 914 if (!out)
bd85ea1f 915 out = strOrNull(al->cache.extuser);
93cc83e7 916
cb4f4424 917#if USE_OPENSSL
38e16f92 918 if (!out)
bd85ea1f 919 out = strOrNull(al->cache.ssluser);
38e16f92 920#endif
38e16f92 921 if (!out)
bd85ea1f 922 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
923 break;
924
925 case LFT_USER_LOGIN:
c0e8c76f
AJ
926#if USE_AUTH
927 if (al->request && al->request->auth_user_request != NULL)
928 out = strOrNull(al->request->auth_user_request->username());
929#endif
38e16f92
AJ
930 break;
931
932 case LFT_USER_IDENT:
bd85ea1f 933 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
934 break;
935
936 case LFT_USER_EXTERNAL:
93cc83e7
AJ
937 if (al->request && al->request->extacl_user.size()) {
938 if (const char *t = al->request->extacl_user.termedBuf())
939 out = t;
940 }
4e56d7f6
AJ
941
942 if (!out)
943 out = strOrNull(al->cache.extuser);
38e16f92
AJ
944 break;
945
f53969cc
SM
946 /* case LFT_USER_REALM: */
947 /* case LFT_USER_SCHEME: */
38e16f92 948
f53969cc
SM
949 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
950 // but compiler complains if ommited
38e16f92
AJ
951 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
952 case LFT_HTTP_SENT_STATUS_CODE:
953 outint = al->http.code;
954
955 doint = 1;
956
957 break;
958
959 case LFT_HTTP_RECEIVED_STATUS_CODE:
955394ce 960 if (al->hier.peer_reply_status == Http::scNone) {
38e16f92
AJ
961 out = "-";
962 } else {
963 outint = al->hier.peer_reply_status;
964 doint = 1;
965 }
966 break;
f53969cc
SM
967 /* case LFT_HTTP_STATUS:
968 * out = statusline->text;
969 * quote = 1;
970 * break;
971 */
38e16f92
AJ
972 case LFT_HTTP_BODY_BYTES_READ:
973 if (al->hier.bodyBytesRead >= 0) {
974 outoff = al->hier.bodyBytesRead;
975 dooff = 1;
976 }
977 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
978 // a peer server so just print a "-" (eg requests served from cache,
979 // or internal error messages).
980 break;
981
982 case LFT_SQUID_STATUS:
a981b360 983 out = al->cache.code.c_str();
38e16f92
AJ
984 break;
985
986 case LFT_SQUID_ERROR:
987 if (al->request && al->request->errType != ERR_NONE)
988 out = errorPageName(al->request->errType);
989 break;
990
991 case LFT_SQUID_ERROR_DETAIL:
cb4f4424 992#if USE_OPENSSL
2f3e52b5 993 if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
7598eb63
CT
994 if (! (out = Ssl::GetErrorName(al->request->errDetail)))
995 out = sslErrorName(al->request->errDetail, tmp, sizeof(tmp));
e83cdc25 996 } else
2f3e52b5 997#endif
e83cdc25 998 if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
4e56d7f6 999 if (al->request->errDetail > ERR_DETAIL_START && al->request->errDetail < ERR_DETAIL_MAX)
e83cdc25
A
1000 out = errorDetailName(al->request->errDetail);
1001 else {
1002 if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
1003 snprintf(tmp, sizeof(tmp), "%s=0x%X",
1004 errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
1005 else
1006 snprintf(tmp, sizeof(tmp), "%s=%d",
1007 errorDetailName(al->request->errDetail), al->request->errDetail);
1008 out = tmp;
1009 }
38e16f92 1010 }
38e16f92
AJ
1011 break;
1012
1013 case LFT_SQUID_HIERARCHY:
1014 if (al->hier.ping.timedout)
1015 mb.append("TIMEOUT_", 8);
1016
1017 out = hier_code_str[al->hier.code];
1018
1019 break;
1020
1021 case LFT_MIME_TYPE:
1022 out = al->http.content_type;
1023
1024 break;
1025
1026 case LFT_CLIENT_REQ_METHOD:
1027 if (al->request) {
7f06a3d8
AJ
1028 const SBuf &s = al->request->method.image();
1029 sb.append(s.rawContent(), s.length());
1030 out = sb.termedBuf();
38e16f92
AJ
1031 quote = 1;
1032 }
1033 break;
1034
1035 case LFT_CLIENT_REQ_URI:
1036 // original client URI
1037 if (al->request) {
851feda6
AJ
1038 const SBuf &s = al->request->effectiveRequestUri();
1039 sb.append(s.rawContent(), s.length());
1040 out = sb.termedBuf();
38e16f92
AJ
1041 quote = 1;
1042 }
1043 break;
1044
5aca9cf2
AJ
1045 case LFT_CLIENT_REQ_URLSCHEME:
1046 if (al->request) {
d31d59d8
AJ
1047 const SBuf s(al->request->url.getScheme().image());
1048 sb.append(s.rawContent(), s.length());
1049 out = sb.termedBuf();
5aca9cf2
AJ
1050 quote = 1;
1051 }
1052 break;
1053
fa450988
AJ
1054 case LFT_CLIENT_REQ_URLDOMAIN:
1055 if (al->request) {
5c51bffb 1056 out = al->request->url.host();
fa450988
AJ
1057 quote = 1;
1058 }
1059 break;
1060
5aca9cf2
AJ
1061 case LFT_CLIENT_REQ_URLPORT:
1062 if (al->request) {
5c51bffb 1063 outint = al->request->url.port();
5aca9cf2
AJ
1064 doint = 1;
1065 }
1066 break;
1067
38e16f92
AJ
1068 case LFT_REQUEST_URLPATH_OLD_31:
1069 case LFT_CLIENT_REQ_URLPATH:
1070 if (al->request) {
51b5dcf5
AJ
1071 SBuf s = al->request->url.path();
1072 out = s.c_str();
38e16f92
AJ
1073 quote = 1;
1074 }
1075 break;
1076
1077 case LFT_CLIENT_REQ_VERSION:
1078 if (al->request) {
1079 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
1080 out = tmp;
1081 }
1082 break;
1083
1084 case LFT_REQUEST_METHOD:
3736fdd6
SM
1085 {
1086 const SBuf s(al->getLogMethod());
1087 sb.append(s.rawContent(), s.length());
1088 out = sb.termedBuf();
1089 quote = 1;
1090 }
1091 break;
38e16f92
AJ
1092
1093 case LFT_REQUEST_URI:
f57ae909
NH
1094 if (!al->url.isEmpty()) {
1095 const SBuf &s = al->url;
1096 sb.append(s.rawContent(), s.length());
1097 out = sb.termedBuf();
1098 }
38e16f92
AJ
1099 break;
1100
1101 case LFT_REQUEST_VERSION_OLD_2X:
1102 case LFT_REQUEST_VERSION:
1103 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
1104 out = tmp;
1105 break;
1106
1107 case LFT_SERVER_REQ_METHOD:
1108 if (al->adapted_request) {
7f06a3d8
AJ
1109 const SBuf &s = al->adapted_request->method.image();
1110 sb.append(s.rawContent(), s.length());
1111 out = sb.termedBuf();
38e16f92
AJ
1112 quote = 1;
1113 }
1114 break;
1115
1116 case LFT_SERVER_REQ_URI:
1117 // adapted request URI sent to server/peer
1118 if (al->adapted_request) {
851feda6
AJ
1119 const SBuf &s = al->adapted_request->effectiveRequestUri();
1120 sb.append(s.rawContent(), s.length());
1121 out = sb.termedBuf();
38e16f92
AJ
1122 quote = 1;
1123 }
1124 break;
1125
5aca9cf2
AJ
1126 case LFT_SERVER_REQ_URLSCHEME:
1127 if (al->adapted_request) {
d31d59d8
AJ
1128 const SBuf s(al->adapted_request->url.getScheme().image());
1129 sb.append(s.rawContent(), s.length());
1130 out = sb.termedBuf();
5aca9cf2
AJ
1131 quote = 1;
1132 }
1133 break;
1134
1135 case LFT_SERVER_REQ_URLDOMAIN:
1136 if (al->adapted_request) {
5c51bffb 1137 out = al->adapted_request->url.host();
5aca9cf2
AJ
1138 quote = 1;
1139 }
1140 break;
1141
1142 case LFT_SERVER_REQ_URLPORT:
1143 if (al->adapted_request) {
5c51bffb 1144 outint = al->adapted_request->url.port();
5aca9cf2
AJ
1145 doint = 1;
1146 }
1147 break;
1148
38e16f92
AJ
1149 case LFT_SERVER_REQ_URLPATH:
1150 if (al->adapted_request) {
51b5dcf5
AJ
1151 SBuf s = al->adapted_request->url.path();
1152 out = s.c_str();
38e16f92
AJ
1153 quote = 1;
1154 }
1155 break;
1156
1157 case LFT_SERVER_REQ_VERSION:
1158 if (al->adapted_request) {
1159 snprintf(tmp, sizeof(tmp), "%d.%d",
1160 (int) al->adapted_request->http_ver.major,
1161 (int) al->adapted_request->http_ver.minor);
1162 out = tmp;
1163 }
1164 break;
1165
d6df21d2 1166 case LFT_CLIENT_REQUEST_SIZE_TOTAL:
cc0ca3b9 1167 outoff = al->http.clientRequestSz.messageTotal();
38e16f92
AJ
1168 dooff = 1;
1169 break;
1170
d6df21d2 1171 case LFT_CLIENT_REQUEST_SIZE_HEADERS:
cc0ca3b9 1172 outoff = al->http.clientRequestSz.header;
38e16f92
AJ
1173 dooff =1;
1174 break;
d6df21d2 1175
f53969cc
SM
1176 /*case LFT_REQUEST_SIZE_BODY: */
1177 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
38e16f92 1178
d6df21d2 1179 case LFT_ADAPTED_REPLY_SIZE_TOTAL:
cc0ca3b9 1180 outoff = al->http.clientReplySz.messageTotal();
38e16f92
AJ
1181 dooff = 1;
1182 break;
1183
1184 case LFT_REPLY_HIGHOFFSET:
1185 outoff = al->cache.highOffset;
1186
1187 dooff = 1;
1188
1189 break;
1190
1191 case LFT_REPLY_OBJECTSIZE:
1192 outoff = al->cache.objectSize;
1193
1194 dooff = 1;
1195
1196 break;
1197
d6df21d2 1198 case LFT_ADAPTED_REPLY_SIZE_HEADERS:
cc0ca3b9 1199 outint = al->http.clientReplySz.header;
38e16f92
AJ
1200 doint = 1;
1201 break;
d6df21d2 1202
f53969cc
SM
1203 /*case LFT_REPLY_SIZE_BODY: */
1204 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
38e16f92 1205
d6df21d2 1206 case LFT_CLIENT_IO_SIZE_TOTAL:
cc0ca3b9 1207 outint = al->http.clientRequestSz.messageTotal() + al->http.clientReplySz.messageTotal();
d6df21d2
AJ
1208 doint = 1;
1209 break;
f53969cc 1210 /*case LFT_SERVER_IO_SIZE_TOTAL: */
d6df21d2 1211
38e16f92
AJ
1212 case LFT_TAG:
1213 if (al->request)
1214 out = al->request->tag.termedBuf();
1215
1216 quote = 1;
1217
1218 break;
1219
38e16f92
AJ
1220 case LFT_EXT_LOG:
1221 if (al->request)
1222 out = al->request->extacl_log.termedBuf();
1223
1224 quote = 1;
1225
1226 break;
1227
1228 case LFT_SEQUENCE_NUMBER:
1229 outoff = logSequenceNumber;
1230 dooff = 1;
1231 break;
1232
cb4f4424 1233#if USE_OPENSSL
08097970
AR
1234 case LFT_SSL_BUMP_MODE: {
1235 const Ssl::BumpMode mode = static_cast<Ssl::BumpMode>(al->ssl.bumpMode);
1236 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1237 out = Ssl::bumpMode(mode);
08097970 1238 }
3736fdd6 1239 break;
4e56d7f6
AJ
1240
1241 case LFT_EXT_ACL_USER_CERT_RAW:
1242 if (al->request) {
1243 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1244 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1245 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
4e56d7f6
AJ
1246 out = sslGetUserCertificatePEM(ssl);
1247 }
1248 }
1249 break;
1250
1251 case LFT_EXT_ACL_USER_CERTCHAIN_RAW:
1252 if (al->request) {
1253 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1254 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1255 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
4e56d7f6
AJ
1256 out = sslGetUserCertificatePEM(ssl);
1257 }
1258 }
1259 break;
1260
1261 case LFT_EXT_ACL_USER_CERT:
1262 if (al->request) {
1263 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1264 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1265 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
4e56d7f6
AJ
1266 out = sslGetUserAttribute(ssl, format->data.header.header);
1267 }
1268 }
1269 break;
1270
1271 case LFT_EXT_ACL_USER_CA_CERT:
1272 if (al->request) {
1273 ConnStateData *conn = al->request->clientConnectionManager.get();
33cc0629
AJ
1274 if (conn && Comm::IsConnOpen(conn->clientConnection)) {
1275 if (auto ssl = fd_table[conn->clientConnection->fd].ssl.get())
3736fdd6 1276 out = sslGetCAAttribute(ssl, format->data.header.header);
4e56d7f6
AJ
1277 }
1278 }
1279 break;
71cae389 1280
f4698e0b
CT
1281 case LFT_SSL_USER_CERT_SUBJECT:
1282 if (X509 *cert = al->cache.sslClientCert.get()) {
1283 if (X509_NAME *subject = X509_get_subject_name(cert)) {
1284 X509_NAME_oneline(subject, tmp, sizeof(tmp));
1285 out = tmp;
1286 }
1287 }
1288 break;
1289
1290 case LFT_SSL_USER_CERT_ISSUER:
1291 if (X509 *cert = al->cache.sslClientCert.get()) {
1292 if (X509_NAME *issuer = X509_get_issuer_name(cert)) {
1293 X509_NAME_oneline(issuer, tmp, sizeof(tmp));
1294 out = tmp;
1295 }
1296 }
1297 break;
4e56d7f6 1298
cedca6e7
CT
1299 case LFT_SSL_CLIENT_SNI:
1300 if (al->request && al->request->clientConnectionManager.valid()) {
1301 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1302 if (!srvBump->clientSni.isEmpty())
1303 out = srvBump->clientSni.c_str();
1304 }
1305 }
1306 break;
789dda8d 1307
7598eb63
CT
1308 case LFT_SSL_SERVER_CERT_ERRORS:
1309 if (al->request && al->request->clientConnectionManager.valid()) {
1310 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1311 const char *separator = fmt->data.string ? fmt->data.string : ":";
92e3827b 1312 for (const Security::CertErrors *sslError = srvBump->sslErrors(); sslError != nullptr; sslError = sslError->next) {
7598eb63
CT
1313 if (sb.size())
1314 sb.append(separator);
1315 if (const char *errorName = Ssl::GetErrorName(sslError->element.code))
1316 sb.append(errorName);
1317 else
1318 sb.append(sslErrorName(sslError->element.code, tmp, sizeof(tmp)));
b4e6a8d4
CT
1319 if (sslError->element.depth >= 0) {
1320 snprintf(tmp, sizeof(tmp), "@depth=%d", sslError->element.depth);
1321 sb.append(tmp);
1322 }
7598eb63
CT
1323 }
1324 if (sb.size())
1325 out = sb.termedBuf();
1326 }
1327 }
cedca6e7 1328 break;
789dda8d
CT
1329
1330 case LFT_SSL_SERVER_CERT_ISSUER:
1331 case LFT_SSL_SERVER_CERT_SUBJECT:
d4ddb3e6
CT
1332 if (al->request && al->request->clientConnectionManager.valid()) {
1333 if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
1334 if (X509 *serverCert = srvBump->serverCert.get()) {
1335 if (fmt->type == LFT_SSL_SERVER_CERT_SUBJECT)
1336 out = Ssl::GetX509UserAttribute(serverCert, "DN");
1337 else
1338 out = Ssl::GetX509CAAttribute(serverCert, "DN");
1339 }
1340 }
1341 }
789dda8d 1342 break;
2bcab852
CT
1343
1344 case LFT_TLS_CLIENT_NEGOTIATED_VERSION:
1345 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1346 out = al->tcpClient->hasTlsNegotiations()->negotiatedVersion();
1347 break;
1348
1349 case LFT_TLS_SERVER_NEGOTIATED_VERSION:
1350 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1351 out = al->hier.tcpServer->hasTlsNegotiations()->negotiatedVersion();
1352 break;
1353
1354 case LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION:
1355 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1356 out = al->tcpClient->hasTlsNegotiations()->helloVersion();
1357 break;
1358
1359 case LFT_TLS_SERVER_RECEIVED_HELLO_VERSION:
1360 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1361 out = al->hier.tcpServer->hasTlsNegotiations()->helloVersion();
1362 break;
1363
1364 case LFT_TLS_CLIENT_SUPPORTED_VERSION:
1365 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1366 out = al->tcpClient->hasTlsNegotiations()->supportedVersion();
1367 break;
1368
1369 case LFT_TLS_SERVER_SUPPORTED_VERSION:
1370 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1371 out = al->hier.tcpServer->hasTlsNegotiations()->supportedVersion();
1372 break;
1373
1374 case LFT_TLS_CLIENT_NEGOTIATED_CIPHER:
1375 if (al->tcpClient != nullptr && al->tcpClient->hasTlsNegotiations())
1376 out = al->tcpClient->hasTlsNegotiations()->cipherName();
1377 break;
1378
1379 case LFT_TLS_SERVER_NEGOTIATED_CIPHER:
1380 if (al->hier.tcpServer != nullptr && al->hier.tcpServer->hasTlsNegotiations())
1381 out = al->hier.tcpServer->hasTlsNegotiations()->cipherName();
1382 break;
08097970 1383#endif
f123f5e9 1384
d074f918
TT
1385 case LFT_REQUEST_URLGROUP_OLD_2X:
1386 assert(LFT_REQUEST_URLGROUP_OLD_2X == 0); // should never happen.
1387
d7f4a0b7 1388 case LFT_NOTE:
c7bcf010
CT
1389 tmp[0] = fmt->data.header.separator;
1390 tmp[1] = '\0';
1391 if (fmt->data.header.header && *fmt->data.header.header) {
1392 const char *separator = tmp;
cf9f0261 1393#if USE_ADAPTATION
7f0ceafc 1394 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
cf9f0261 1395 if (ah != NULL && ah->metaHeaders != NULL) {
c7bcf010 1396 if (const char *meta = ah->metaHeaders->find(fmt->data.header.header, separator))
cf9f0261
CT
1397 sb.append(meta);
1398 }
1399#endif
f4f55a21 1400 if (al->notes != NULL) {
c7bcf010 1401 if (const char *note = al->notes->find(fmt->data.header.header, separator)) {
cf9f0261 1402 if (sb.size())
c7bcf010 1403 sb.append(separator);
cf9f0261
CT
1404 sb.append(note);
1405 }
1406 }
d7f4a0b7
CT
1407 out = sb.termedBuf();
1408 quote = 1;
1409 } else {
c7bcf010
CT
1410 // if no argument given use default "\r\n" as notes separator
1411 const char *separator = fmt->data.string ? tmp : "\r\n";
cf9f0261 1412#if USE_ADAPTATION
7f0ceafc 1413 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
cf9f0261 1414 if (ah != NULL && ah->metaHeaders != NULL && !ah->metaHeaders->empty())
c7bcf010 1415 sb.append(ah->metaHeaders->toString(separator));
cf9f0261 1416#endif
f4f55a21 1417 if (al->notes != NULL && !al->notes->empty())
c7bcf010 1418 sb.append(al->notes->toString(separator));
f4f55a21 1419
d7f4a0b7
CT
1420 out = sb.termedBuf();
1421 quote = 1;
1422 }
1423 break;
08097970 1424
d4806c91
CT
1425 case LFT_CREDENTIALS:
1426#if USE_AUTH
1427 if (al->request && al->request->auth_user_request != NULL)
1428 out = strOrNull(al->request->auth_user_request->credentialsStr());
1429#endif
1430
1431 break;
1432
38e16f92
AJ
1433 case LFT_PERCENT:
1434 out = "%";
5aca9cf2 1435 break;
38e16f92 1436
5aca9cf2 1437 case LFT_EXT_ACL_NAME:
4ff6370b 1438 out = al->lastAclName;
4e56d7f6
AJ
1439 break;
1440
5aca9cf2 1441 case LFT_EXT_ACL_DATA:
b0e14ce2
NH
1442 if (!al->lastAclData.isEmpty())
1443 out = al->lastAclData.c_str();
38e16f92
AJ
1444 break;
1445 }
1446
1447 if (dooff) {
8846a2b4 1448 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff);
38e16f92
AJ
1449 out = tmp;
1450
1451 } else if (doint) {
8846a2b4 1452 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
38e16f92 1453 out = tmp;
01bd87d8
CT
1454 } else if (doMsec) {
1455 if (fmt->widthMax < 0) {
1456 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->widthMin , tvToMsec(outtv));
1457 } else {
1458 int precision = fmt->widthMax;
1459 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)));
1460 }
1461 out = tmp;
1462 } else if (doSec) {
1463 int precision = fmt->widthMax >=0 ? fmt->widthMax :3;
1464 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));
1465 out = tmp;
38e16f92
AJ
1466 }
1467
1468 if (out && *out) {
1469 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1470 char *newout = NULL;
1471 int newfree = 0;
1472
1473 switch (fmt->quote) {
1474
1475 case LOG_QUOTE_NONE:
1476 newout = rfc1738_escape_unescaped(out);
1477 break;
1478
1479 case LOG_QUOTE_QUOTES: {
1480 size_t out_len = static_cast<size_t>(strlen(out)) * 2 + 1;
1481 if (out_len >= sizeof(tmp)) {
1482 newout = (char *)xmalloc(out_len);
1483 newfree = 1;
1484 } else
1485 newout = tmp;
1486 log_quoted_string(out, newout);
1487 }
1488 break;
1489
1490 case LOG_QUOTE_MIMEBLOB:
1491 newout = QuoteMimeBlob(out);
1492 newfree = 1;
1493 break;
1494
1495 case LOG_QUOTE_URL:
1496 newout = rfc1738_escape(out);
1497 break;
1498
95d78f10
AJ
1499 case LOG_QUOTE_SHELL: {
1500 MemBuf mbq;
1501 mbq.init();
1502 strwordquote(&mbq, out);
1503 newout = mbq.content();
1504 mbq.stolen = 1;
1505 newfree = 1;
3736fdd6
SM
1506 }
1507 break;
95d78f10 1508
38e16f92
AJ
1509 case LOG_QUOTE_RAW:
1510 break;
1511 }
1512
1513 if (newout) {
1514 if (dofree)
1515 safe_free(out);
1516
1517 out = newout;
1518
1519 dofree = newfree;
1520 }
1521 }
1522
c32c6db7 1523 // enforce width limits if configured
01bd87d8 1524 const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff && !doMsec && !doSec;
8846a2b4
CT
1525 if (haveMaxWidth || fmt->widthMin) {
1526 const int minWidth = fmt->widthMin >= 0 ?
b8ad91f5 1527 fmt->widthMin :0;
c32c6db7 1528 const int maxWidth = haveMaxWidth ?
8846a2b4 1529 fmt->widthMax : strlen(out);
c32c6db7 1530
38e16f92 1531 if (fmt->left)
4391cd15 1532 mb.appendf("%-*.*s", minWidth, maxWidth, out);
38e16f92 1533 else
4391cd15 1534 mb.appendf("%*.*s", minWidth, maxWidth, out);
38e16f92
AJ
1535 } else
1536 mb.append(out, strlen(out));
1537 } else {
1538 mb.append("-", 1);
1539 }
1540
1541 if (fmt->space)
1542 mb.append(" ", 1);
1543
1544 sb.clean();
1545
1546 if (dofree)
1547 safe_free(out);
1548 }
1549}
f53969cc 1550