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