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