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