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