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