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