]> git.ipfire.org Git - thirdparty/squid.git/blame - src/format/Format.cc
Moved wordlist prototypes from protos.h to wordlist.h
[thirdparty/squid.git] / src / format / Format.cc
CommitLineData
f7f3304a 1#include "squid.h"
38e16f92 2#include "AccessLogEntry.h"
582c2af2 3#include "client_side.h"
38e16f92
AJ
4#include "comm/Connection.h"
5#include "err_detail_type.h"
6#include "errorpage.h"
f4698e0b 7#include "fde.h"
38e16f92
AJ
8#include "format/Format.h"
9#include "format/Quoting.h"
31971e6a 10#include "format/Token.h"
38e16f92
AJ
11#include "HttpRequest.h"
12#include "MemBuf.h"
582c2af2 13#include "protos.h"
38e16f92
AJ
14#include "rfc1738.h"
15#include "SquidTime.h"
16#include "Store.h"
2f3e52b5
CT
17#if USE_SSL
18#include "ssl/ErrorDetail.h"
19#endif
20
38e16f92 21
bd85ea1f
AJ
22/// Convert a string to NULL pointer if it is ""
23#define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
38e16f92
AJ
24
25Format::Format::Format(const char *n) :
26 format(NULL),
27 next(NULL)
28{
29 name = xstrdup(n);
30}
31
32Format::Format::~Format()
33{
34 // erase the list without consuming stack space
35 while (next) {
36 // unlink the next entry for deletion
37 Format *temp = next;
38 next = temp->next;
39 temp->next = NULL;
40 delete temp;
41 }
42
43 // remove locals
44 xfree(name);
45 delete format;
46}
47
48bool
f4698e0b 49Format::Format::parse(const char *def)
38e16f92 50{
f4698e0b 51 const char *cur, *eos;
38e16f92
AJ
52 Token *new_lt, *last_lt;
53 enum Quoting quote = LOG_QUOTE_NONE;
54
55 debugs(46, 2, HERE << "got definition '" << def << "'");
56
57 if (format) {
58 debugs(46, DBG_IMPORTANT, "WARNING: existing format for '" << name << " " << def << "'");
59 return false;
60 }
61
62 /* very inefficent parser, but who cares, this needs to be simple */
63 /* First off, let's tokenize, we'll optimize in a second pass.
64 * A token can either be a %-prefixed sequence (usually a dynamic
65 * token but it can be an escaped sequence), or a string. */
66 cur = def;
67 eos = def + strlen(def);
68 format = new_lt = last_lt = new Token;
69 cur += new_lt->parse(cur, &quote);
70
71 while (cur < eos) {
72 new_lt = new Token;
73 last_lt->next = new_lt;
74 last_lt = new_lt;
75 cur += new_lt->parse(cur, &quote);
76 }
77
78 return true;
79}
80
81void
82Format::Format::dump(StoreEntry * entry, const char *name)
83{
84 debugs(46, 4, HERE);
85
86 // loop rather than recursing to conserve stack space.
87 for (Format *format = this; format; format = format->next) {
88 debugs(46, 3, HERE << "Dumping format definition for " << format->name);
89 storeAppendPrintf(entry, "format %s ", format->name);
90
91 for (Token *t = format->format; t; t = t->next) {
92 if (t->type == LFT_STRING)
93 storeAppendPrintf(entry, "%s", t->data.string);
94 else {
95 char argbuf[256];
96 char *arg = NULL;
97 ByteCode_t type = t->type;
98
99 switch (type) {
100 /* special cases */
101
102 case LFT_STRING:
103 break;
104#if USE_ADAPTATION
105 case LFT_ADAPTATION_LAST_HEADER_ELEM:
106#endif
107#if ICAP_CLIENT
108 case LFT_ICAP_REQ_HEADER_ELEM:
109 case LFT_ICAP_REP_HEADER_ELEM:
110#endif
111 case LFT_REQUEST_HEADER_ELEM:
112 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
113 case LFT_REPLY_HEADER_ELEM:
114
115 if (t->data.header.separator != ',')
116 snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
117 else
118 snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
119
120 arg = argbuf;
121
122 switch (type) {
123 case LFT_REQUEST_HEADER_ELEM:
124 type = LFT_REQUEST_HEADER_ELEM; // XXX: remove _ELEM?
125 break;
126 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
127 type = LFT_ADAPTED_REQUEST_HEADER_ELEM; // XXX: remove _ELEM?
128 break;
129 case LFT_REPLY_HEADER_ELEM:
130 type = LFT_REPLY_HEADER_ELEM; // XXX: remove _ELEM?
131 break;
132#if USE_ADAPTATION
133 case LFT_ADAPTATION_LAST_HEADER_ELEM:
134 type = LFT_ADAPTATION_LAST_HEADER;
135 break;
136#endif
137#if ICAP_CLIENT
138 case LFT_ICAP_REQ_HEADER_ELEM:
139 type = LFT_ICAP_REQ_HEADER;
140 break;
141 case LFT_ICAP_REP_HEADER_ELEM:
142 type = LFT_ICAP_REP_HEADER;
143 break;
144#endif
145 default:
146 break;
147 }
148
149 break;
150
151 case LFT_REQUEST_ALL_HEADERS:
152 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
153 case LFT_REPLY_ALL_HEADERS:
154
155#if USE_ADAPTATION
156 case LFT_ADAPTATION_LAST_ALL_HEADERS:
157#endif
158#if ICAP_CLIENT
159 case LFT_ICAP_REQ_ALL_HEADERS:
160 case LFT_ICAP_REP_ALL_HEADERS:
161#endif
162
163 switch (type) {
164 case LFT_REQUEST_ALL_HEADERS:
165 type = LFT_REQUEST_HEADER;
166 break;
167 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
168 type = LFT_ADAPTED_REQUEST_HEADER;
169 break;
170 case LFT_REPLY_ALL_HEADERS:
171 type = LFT_REPLY_HEADER;
172 break;
173#if USE_ADAPTATION
174 case LFT_ADAPTATION_LAST_ALL_HEADERS:
175 type = LFT_ADAPTATION_LAST_HEADER;
176 break;
177#endif
178#if ICAP_CLIENT
179 case LFT_ICAP_REQ_ALL_HEADERS:
180 type = LFT_ICAP_REQ_HEADER;
181 break;
182 case LFT_ICAP_REP_ALL_HEADERS:
183 type = LFT_ICAP_REP_HEADER;
184 break;
185#endif
186 default:
187 break;
188 }
189
190 break;
191
192 default:
193 if (t->data.string)
194 arg = t->data.string;
195
196 break;
197 }
198
199 entry->append("%", 1);
200
201 switch (t->quote) {
202
203 case LOG_QUOTE_QUOTES:
204 entry->append("\"", 1);
205 break;
206
207 case LOG_QUOTE_MIMEBLOB:
208 entry->append("[", 1);
209 break;
210
211 case LOG_QUOTE_URL:
212 entry->append("#", 1);
213 break;
214
215 case LOG_QUOTE_RAW:
216 entry->append("'", 1);
217 break;
218
219 case LOG_QUOTE_NONE:
220 break;
221 }
222
223 if (t->left)
224 entry->append("-", 1);
225
226 if (t->zero)
227 entry->append("0", 1);
228
8846a2b4
CT
229 if (t->widthMin >= 0)
230 storeAppendPrintf(entry, "%d", t->widthMin);
38e16f92 231
8846a2b4
CT
232 if (t->widthMax >= 0)
233 storeAppendPrintf(entry, ".%d", t->widthMax);
38e16f92
AJ
234
235 if (arg)
236 storeAppendPrintf(entry, "{%s}", arg);
237
aa99e35e 238 storeAppendPrintf(entry, "%s", t->label);
38e16f92
AJ
239
240 if (t->space)
241 entry->append(" ", 1);
242 }
243 }
244
245 entry->append("\n", 1);
246 }
247
248}
249
250static void
251log_quoted_string(const char *str, char *out)
252{
253 char *p = out;
254
255 while (*str) {
256 int l = strcspn(str, "\"\\\r\n\t");
257 memcpy(p, str, l);
258 str += l;
259 p += l;
260
261 switch (*str) {
262
263 case '\0':
264 break;
265
266 case '\r':
a38ec4b1
FC
267 *p = '\\';
268 ++p;
269 *p = 'r';
270 ++p;
cb4185f1 271 ++str;
38e16f92
AJ
272 break;
273
274 case '\n':
a38ec4b1
FC
275 *p = '\\';
276 ++p;
277 *p = 'n';
278 ++p;
cb4185f1 279 ++str;
38e16f92
AJ
280 break;
281
282 case '\t':
a38ec4b1
FC
283 *p = '\\';
284 ++p;
285 *p = 't';
286 ++p;
cb4185f1 287 ++str;
38e16f92
AJ
288 break;
289
290 default:
a38ec4b1
FC
291 *p = '\\';
292 ++p;
293 *p = *str;
294 ++p;
cb4185f1 295 ++str;
38e16f92
AJ
296 break;
297 }
298 }
299
cb4185f1 300 *p = '\0';
38e16f92
AJ
301}
302
303void
f4698e0b 304Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logSequenceNumber) const
38e16f92
AJ
305{
306 char tmp[1024];
307 String sb;
308
309 for (Token *fmt = format; fmt != NULL; fmt = fmt->next) { /* for each token */
310 const char *out = NULL;
311 int quote = 0;
312 long int outint = 0;
313 int doint = 0;
314 int dofree = 0;
315 int64_t outoff = 0;
316 int dooff = 0;
317
318 switch (fmt->type) {
319
320 case LFT_NONE:
321 out = "";
322 break;
323
324 case LFT_STRING:
325 out = fmt->data.string;
326 break;
327
328 case LFT_CLIENT_IP_ADDRESS:
d4204018
AJ
329 al->getLogClientIp(tmp, sizeof(tmp));
330 out = tmp;
38e16f92
AJ
331 break;
332
333 case LFT_CLIENT_FQDN:
334 if (al->cache.caddr.IsAnyAddr()) // e.g., ICAP OPTIONS lack client
335 out = "-";
336 else
337 out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
338 if (!out) {
339 out = al->cache.caddr.NtoA(tmp,1024);
340 }
341
342 break;
343
344 case LFT_CLIENT_PORT:
345 if (al->request) {
346 outint = al->request->client_addr.GetPort();
347 doint = 1;
348 }
349 break;
350
38e16f92 351 case LFT_CLIENT_EUI:
8652f8e7 352#if USE_SQUID_EUI
38e16f92
AJ
353 // TODO make the ACL checklist have a direct link to any TCP details.
354 if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) {
355 if (al->request->clientConnectionManager->clientConnection->remote.IsIPv4())
356 al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024);
357 else
358 al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024);
359 out = tmp;
360 }
8652f8e7
AJ
361#else
362 out = "-";
38e16f92 363#endif
8652f8e7 364 break;
38e16f92 365
8652f8e7
AJ
366 case LFT_SERVER_IP_ADDRESS:
367 if (al->hier.tcpServer != NULL) {
368 out = al->hier.tcpServer->remote.NtoA(tmp,sizeof(tmp));
369 }
370 break;
38e16f92 371
8652f8e7 372 case LFT_SERVER_FQDN_OR_PEER_NAME:
38e16f92 373 out = al->hier.host;
38e16f92
AJ
374 break;
375
8652f8e7
AJ
376 case LFT_SERVER_PORT:
377 if (al->hier.tcpServer != NULL) {
378 outint = al->hier.tcpServer->remote.GetPort();
379 doint = 1;
380 }
381 break;
38e16f92 382
28417506
CT
383 case LFT_LOCAL_LISTENING_IP: {
384 // avoid logging a dash if we have reliable info
47176c0b
CT
385 const bool interceptedAtKnownPort = al->request ?
386 (al->request->flags.spoof_client_ip ||
387 al->request->flags.intercepted) && al->cache.port :
388 false;
28417506
CT
389 if (interceptedAtKnownPort) {
390 const bool portAddressConfigured = !al->cache.port->s.IsAnyAddr();
391 if (portAddressConfigured)
392 out = al->cache.port->s.NtoA(tmp, sizeof(tmp));
393 } else if (al->tcpClient != NULL)
394 out = al->tcpClient->local.NtoA(tmp, sizeof(tmp));
395 }
396 break;
397
8652f8e7 398 case LFT_CLIENT_LOCAL_IP:
a14f38d0
AJ
399 if (al->tcpClient != NULL) {
400 out = al->tcpClient->local.NtoA(tmp,sizeof(tmp));
38e16f92 401 }
38e16f92
AJ
402 break;
403
28417506
CT
404 case LFT_LOCAL_LISTENING_PORT:
405 if (al->cache.port) {
406 outint = al->cache.port->s.GetPort();
407 doint = 1;
408 }
409 break;
410
8652f8e7 411 case LFT_CLIENT_LOCAL_PORT:
a14f38d0
AJ
412 if (al->tcpClient != NULL) {
413 outint = al->tcpClient->local.GetPort();
38e16f92
AJ
414 doint = 1;
415 }
38e16f92
AJ
416 break;
417
8652f8e7
AJ
418 case LFT_SERVER_LOCAL_IP_OLD_27:
419 case LFT_SERVER_LOCAL_IP:
a14f38d0
AJ
420 if (al->hier.tcpServer != NULL) {
421 out = al->hier.tcpServer->local.NtoA(tmp,sizeof(tmp));
38e16f92
AJ
422 }
423 break;
424
8652f8e7 425 case LFT_SERVER_LOCAL_PORT:
a14f38d0
AJ
426 if (al->hier.tcpServer != NULL) {
427 outint = al->hier.tcpServer->local.GetPort();
38e16f92
AJ
428 doint = 1;
429 }
430
431 break;
432
433 case LFT_TIME_SECONDS_SINCE_EPOCH:
434 // some platforms store time in 32-bit, some 64-bit...
435 outoff = static_cast<int64_t>(current_time.tv_sec);
436 dooff = 1;
437 break;
438
439 case LFT_TIME_SUBSECOND:
440 outint = current_time.tv_usec / fmt->divisor;
441 doint = 1;
442 break;
443
444
445 case LFT_TIME_LOCALTIME:
446
447 case LFT_TIME_GMT: {
448 const char *spec;
449
450 struct tm *t;
451 spec = fmt->data.timespec;
452
453 if (fmt->type == LFT_TIME_LOCALTIME) {
454 if (!spec)
455 spec = "%d/%b/%Y:%H:%M:%S %z";
456 t = localtime(&squid_curtime);
457 } else {
458 if (!spec)
459 spec = "%d/%b/%Y:%H:%M:%S";
460
461 t = gmtime(&squid_curtime);
462 }
463
464 strftime(tmp, sizeof(tmp), spec, t);
465
466 out = tmp;
467 }
468
469 break;
470
471 case LFT_TIME_TO_HANDLE_REQUEST:
472 outint = al->cache.msec;
473 doint = 1;
474 break;
475
476 case LFT_PEER_RESPONSE_TIME:
477 if (al->hier.peer_response_time < 0) {
478 out = "-";
479 } else {
480 outoff = al->hier.peer_response_time;
481 dooff = 1;
482 }
483 break;
484
485 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME:
486 if (al->hier.total_response_time < 0) {
487 out = "-";
488 } else {
489 outoff = al->hier.total_response_time;
490 dooff = 1;
491 }
492 break;
493
494 case LFT_DNS_WAIT_TIME:
495 if (al->request && al->request->dnsWait >= 0) {
496 outint = al->request->dnsWait;
497 doint = 1;
498 }
499 break;
500
501 case LFT_REQUEST_HEADER:
502
503 if (al->request)
504 sb = al->request->header.getByName(fmt->data.header.header);
505
506 out = sb.termedBuf();
507
508 quote = 1;
509
510 break;
511
512 case LFT_ADAPTED_REQUEST_HEADER:
513
514 if (al->request)
515 sb = al->adapted_request->header.getByName(fmt->data.header.header);
516
517 out = sb.termedBuf();
518
519 quote = 1;
520
521 break;
522
523 case LFT_REPLY_HEADER:
524 if (al->reply)
525 sb = al->reply->header.getByName(fmt->data.header.header);
526
527 out = sb.termedBuf();
528
529 quote = 1;
530
531 break;
532
533#if USE_ADAPTATION
31971e6a 534 case LFT_ADAPTATION_SUM_XACT_TIMES:
38e16f92
AJ
535 if (al->request) {
536 Adaptation::History::Pointer ah = al->request->adaptHistory();
537 if (ah != NULL)
538 ah->sumLogString(fmt->data.string, sb);
539 out = sb.termedBuf();
540 }
541 break;
542
31971e6a 543 case LFT_ADAPTATION_ALL_XACT_TIMES:
38e16f92
AJ
544 if (al->request) {
545 Adaptation::History::Pointer ah = al->request->adaptHistory();
546 if (ah != NULL)
547 ah->allLogString(fmt->data.string, sb);
548 out = sb.termedBuf();
549 }
550 break;
551
552 case LFT_ADAPTATION_LAST_HEADER:
553 if (al->request) {
554 const Adaptation::History::Pointer ah = al->request->adaptHistory();
555 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
556 sb = ah->allMeta.getByName(fmt->data.header.header);
557 }
558
559 // XXX: here and elsewhere: move such code inside the if guard
560 out = sb.termedBuf();
561
562 quote = 1;
563
564 break;
565
566 case LFT_ADAPTATION_LAST_HEADER_ELEM:
567 if (al->request) {
568 const Adaptation::History::Pointer ah = al->request->adaptHistory();
569 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
570 sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
571 }
572
573 out = sb.termedBuf();
574
575 quote = 1;
576
577 break;
578
579 case LFT_ADAPTATION_LAST_ALL_HEADERS:
580 out = al->adapt.last_meta;
581
582 quote = 1;
583
584 break;
585#endif
586
587#if ICAP_CLIENT
588 case LFT_ICAP_ADDR:
589 if (!out)
590 out = al->icap.hostAddr.NtoA(tmp,1024);
591 break;
592
593 case LFT_ICAP_SERV_NAME:
594 out = al->icap.serviceName.termedBuf();
595 break;
596
597 case LFT_ICAP_REQUEST_URI:
598 out = al->icap.reqUri.termedBuf();
599 break;
600
601 case LFT_ICAP_REQUEST_METHOD:
602 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
603 break;
604
605 case LFT_ICAP_BYTES_SENT:
606 outoff = al->icap.bytesSent;
607 dooff = 1;
608 break;
609
610 case LFT_ICAP_BYTES_READ:
611 outoff = al->icap.bytesRead;
612 dooff = 1;
613 break;
614
615 case LFT_ICAP_BODY_BYTES_READ:
616 if (al->icap.bodyBytesRead >= 0) {
617 outoff = al->icap.bodyBytesRead;
618 dooff = 1;
619 }
620 // else if icap.bodyBytesRead < 0, we do not have any http data,
621 // so just print a "-" (204 responses etc)
622 break;
623
624 case LFT_ICAP_REQ_HEADER:
625 if (NULL != al->icap.request) {
626 sb = al->icap.request->header.getByName(fmt->data.header.header);
627 out = sb.termedBuf();
628 quote = 1;
629 }
630 break;
631
632 case LFT_ICAP_REQ_HEADER_ELEM:
633 if (al->request)
634 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
635
636 out = sb.termedBuf();
637
638 quote = 1;
639
640 break;
641
642 case LFT_ICAP_REQ_ALL_HEADERS:
643 if (al->icap.request) {
644 HttpHeaderPos pos = HttpHeaderInitPos;
645 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
646 sb.append(e->name);
647 sb.append(": ");
648 sb.append(e->value);
649 sb.append("\r\n");
650 }
651 out = sb.termedBuf();
652 quote = 1;
653 }
654 break;
655
656 case LFT_ICAP_REP_HEADER:
657 if (NULL != al->icap.reply) {
658 sb = al->icap.reply->header.getByName(fmt->data.header.header);
659 out = sb.termedBuf();
660 quote = 1;
661 }
662 break;
663
664 case LFT_ICAP_REP_HEADER_ELEM:
665 if (NULL != al->icap.reply)
666 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
667
668 out = sb.termedBuf();
669
670 quote = 1;
671
672 break;
673
674 case LFT_ICAP_REP_ALL_HEADERS:
675 if (al->icap.reply) {
676 HttpHeaderPos pos = HttpHeaderInitPos;
677 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
678 sb.append(e->name);
679 sb.append(": ");
680 sb.append(e->value);
681 sb.append("\r\n");
682 }
683 out = sb.termedBuf();
684 quote = 1;
685 }
686 break;
687
688 case LFT_ICAP_TR_RESPONSE_TIME:
689 outint = al->icap.trTime;
690 doint = 1;
691 break;
692
693 case LFT_ICAP_IO_TIME:
694 outint = al->icap.ioTime;
695 doint = 1;
696 break;
697
698 case LFT_ICAP_STATUS_CODE:
699 outint = al->icap.resStatus;
700 doint = 1;
701 break;
702
703 case LFT_ICAP_OUTCOME:
704 out = al->icap.outcome;
705 break;
706
707 case LFT_ICAP_TOTAL_TIME:
708 outint = al->icap.processingTime;
709 doint = 1;
710 break;
711#endif
712 case LFT_REQUEST_HEADER_ELEM:
713 if (al->request)
714 sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
715
716 out = sb.termedBuf();
717
718 quote = 1;
719
720 break;
721
722 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
723 if (al->adapted_request)
724 sb = al->adapted_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_REPLY_HEADER_ELEM:
733 if (al->reply)
734 sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
735
736 out = sb.termedBuf();
737
738 quote = 1;
739
740 break;
741
742 case LFT_REQUEST_ALL_HEADERS:
743 out = al->headers.request;
744
745 quote = 1;
746
747 break;
748
749 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
750 out = al->headers.adapted_request;
751
752 quote = 1;
753
754 break;
755
756 case LFT_REPLY_ALL_HEADERS:
757 out = al->headers.reply;
758
759 quote = 1;
760
761 break;
762
763 case LFT_USER_NAME:
bd85ea1f 764 out = strOrNull(al->cache.authuser);
38e16f92 765 if (!out)
bd85ea1f 766 out = strOrNull(al->cache.extuser);
38e16f92 767#if USE_SSL
38e16f92 768 if (!out)
bd85ea1f 769 out = strOrNull(al->cache.ssluser);
38e16f92 770#endif
38e16f92 771 if (!out)
bd85ea1f 772 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
773 break;
774
775 case LFT_USER_LOGIN:
bd85ea1f 776 out = strOrNull(al->cache.authuser);
38e16f92
AJ
777 break;
778
779 case LFT_USER_IDENT:
bd85ea1f 780 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
781 break;
782
783 case LFT_USER_EXTERNAL:
bd85ea1f 784 out = strOrNull(al->cache.extuser);
38e16f92
AJ
785 break;
786
787 /* case LFT_USER_REALM: */
788 /* case LFT_USER_SCHEME: */
789
790 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
791 // but compiler complains if ommited
792 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
793 case LFT_HTTP_SENT_STATUS_CODE:
794 outint = al->http.code;
795
796 doint = 1;
797
798 break;
799
800 case LFT_HTTP_RECEIVED_STATUS_CODE:
801 if (al->hier.peer_reply_status == HTTP_STATUS_NONE) {
802 out = "-";
803 } else {
804 outint = al->hier.peer_reply_status;
805 doint = 1;
806 }
807 break;
808 /* case LFT_HTTP_STATUS:
809 * out = statusline->text;
810 * quote = 1;
811 * break;
812 */
813 case LFT_HTTP_BODY_BYTES_READ:
814 if (al->hier.bodyBytesRead >= 0) {
815 outoff = al->hier.bodyBytesRead;
816 dooff = 1;
817 }
818 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
819 // a peer server so just print a "-" (eg requests served from cache,
820 // or internal error messages).
821 break;
822
823 case LFT_SQUID_STATUS:
824 if (al->http.timedout || al->http.aborted) {
825 snprintf(tmp, sizeof(tmp), "%s%s", log_tags[al->cache.code],
826 al->http.statusSfx());
827 out = tmp;
828 } else {
829 out = log_tags[al->cache.code];
830 }
831
832 break;
833
834 case LFT_SQUID_ERROR:
835 if (al->request && al->request->errType != ERR_NONE)
836 out = errorPageName(al->request->errType);
837 break;
838
839 case LFT_SQUID_ERROR_DETAIL:
2f3e52b5
CT
840#if USE_SSL
841 if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
842 if (! (out = Ssl::GetErrorName(al->request->errDetail))) {
843 snprintf(tmp, sizeof(tmp), "SSL_ERR=%d", al->request->errDetail);
844 out = tmp;
845 }
e83cdc25 846 } else
2f3e52b5 847#endif
e83cdc25
A
848 if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
849 if (al->request->errDetail > ERR_DETAIL_START &&
850 al->request->errDetail < ERR_DETAIL_MAX)
851 out = errorDetailName(al->request->errDetail);
852 else {
853 if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
854 snprintf(tmp, sizeof(tmp), "%s=0x%X",
855 errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
856 else
857 snprintf(tmp, sizeof(tmp), "%s=%d",
858 errorDetailName(al->request->errDetail), al->request->errDetail);
859 out = tmp;
860 }
38e16f92 861 }
38e16f92
AJ
862 break;
863
864 case LFT_SQUID_HIERARCHY:
865 if (al->hier.ping.timedout)
866 mb.append("TIMEOUT_", 8);
867
868 out = hier_code_str[al->hier.code];
869
870 break;
871
872 case LFT_MIME_TYPE:
873 out = al->http.content_type;
874
875 break;
876
877 case LFT_CLIENT_REQ_METHOD:
878 if (al->request) {
879 out = al->request->method.image();
880 quote = 1;
881 }
882 break;
883
884 case LFT_CLIENT_REQ_URI:
885 // original client URI
886 if (al->request) {
887 out = urlCanonical(al->request);
888 quote = 1;
889 }
890 break;
891
892 case LFT_REQUEST_URLPATH_OLD_31:
893 case LFT_CLIENT_REQ_URLPATH:
894 if (al->request) {
895 out = al->request->urlpath.termedBuf();
896 quote = 1;
897 }
898 break;
899
900 case LFT_CLIENT_REQ_VERSION:
901 if (al->request) {
902 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
903 out = tmp;
904 }
905 break;
906
907 case LFT_REQUEST_METHOD:
908 out = al->_private.method_str;
909 break;
910
911 case LFT_REQUEST_URI:
912 out = al->url;
913 break;
914
915 case LFT_REQUEST_VERSION_OLD_2X:
916 case LFT_REQUEST_VERSION:
917 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
918 out = tmp;
919 break;
920
921 case LFT_SERVER_REQ_METHOD:
922 if (al->adapted_request) {
923 out = al->adapted_request->method.image();
924 quote = 1;
925 }
926 break;
927
928 case LFT_SERVER_REQ_URI:
929 // adapted request URI sent to server/peer
930 if (al->adapted_request) {
931 out = urlCanonical(al->adapted_request);
932 quote = 1;
933 }
934 break;
935
936 case LFT_SERVER_REQ_URLPATH:
937 if (al->adapted_request) {
938 out = al->adapted_request->urlpath.termedBuf();
939 quote = 1;
940 }
941 break;
942
943 case LFT_SERVER_REQ_VERSION:
944 if (al->adapted_request) {
945 snprintf(tmp, sizeof(tmp), "%d.%d",
946 (int) al->adapted_request->http_ver.major,
947 (int) al->adapted_request->http_ver.minor);
948 out = tmp;
949 }
950 break;
951
952 case LFT_REQUEST_SIZE_TOTAL:
953 outoff = al->cache.requestSize;
954 dooff = 1;
955 break;
956
957 /*case LFT_REQUEST_SIZE_LINE: */
958 case LFT_REQUEST_SIZE_HEADERS:
959 outoff = al->cache.requestHeadersSize;
960 dooff =1;
961 break;
962 /*case LFT_REQUEST_SIZE_BODY: */
963 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
964
965 case LFT_REPLY_SIZE_TOTAL:
966 outoff = al->cache.replySize;
967 dooff = 1;
968 break;
969
970 case LFT_REPLY_HIGHOFFSET:
971 outoff = al->cache.highOffset;
972
973 dooff = 1;
974
975 break;
976
977 case LFT_REPLY_OBJECTSIZE:
978 outoff = al->cache.objectSize;
979
980 dooff = 1;
981
982 break;
983
984 /*case LFT_REPLY_SIZE_LINE: */
985 case LFT_REPLY_SIZE_HEADERS:
986 outint = al->cache.replyHeadersSize;
987 doint = 1;
988 break;
989 /*case LFT_REPLY_SIZE_BODY: */
990 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
991
992 case LFT_TAG:
993 if (al->request)
994 out = al->request->tag.termedBuf();
995
996 quote = 1;
997
998 break;
999
1000 case LFT_IO_SIZE_TOTAL:
1001 outint = al->cache.requestSize + al->cache.replySize;
1002 doint = 1;
1003 break;
1004
1005 case LFT_EXT_LOG:
1006 if (al->request)
1007 out = al->request->extacl_log.termedBuf();
1008
1009 quote = 1;
1010
1011 break;
1012
1013 case LFT_SEQUENCE_NUMBER:
1014 outoff = logSequenceNumber;
1015 dooff = 1;
1016 break;
1017
08097970
AR
1018#if USE_SSL
1019 case LFT_SSL_BUMP_MODE: {
1020 const Ssl::BumpMode mode = static_cast<Ssl::BumpMode>(al->ssl.bumpMode);
1021 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1022 out = Ssl::bumpMode(mode);
1023 break;
1024 }
71cae389 1025
f4698e0b
CT
1026 case LFT_SSL_USER_CERT_SUBJECT:
1027 if (X509 *cert = al->cache.sslClientCert.get()) {
1028 if (X509_NAME *subject = X509_get_subject_name(cert)) {
1029 X509_NAME_oneline(subject, tmp, sizeof(tmp));
1030 out = tmp;
1031 }
1032 }
1033 break;
1034
1035 case LFT_SSL_USER_CERT_ISSUER:
1036 if (X509 *cert = al->cache.sslClientCert.get()) {
1037 if (X509_NAME *issuer = X509_get_issuer_name(cert)) {
1038 X509_NAME_oneline(issuer, tmp, sizeof(tmp));
1039 out = tmp;
1040 }
1041 }
1042 break;
08097970
AR
1043#endif
1044
38e16f92
AJ
1045 case LFT_PERCENT:
1046 out = "%";
1047
1048 break;
1049 }
1050
1051 if (dooff) {
8846a2b4 1052 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff);
38e16f92
AJ
1053 out = tmp;
1054
1055 } else if (doint) {
8846a2b4 1056 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
38e16f92
AJ
1057 out = tmp;
1058 }
1059
1060 if (out && *out) {
1061 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1062 char *newout = NULL;
1063 int newfree = 0;
1064
1065 switch (fmt->quote) {
1066
1067 case LOG_QUOTE_NONE:
1068 newout = rfc1738_escape_unescaped(out);
1069 break;
1070
1071 case LOG_QUOTE_QUOTES: {
1072 size_t out_len = static_cast<size_t>(strlen(out)) * 2 + 1;
1073 if (out_len >= sizeof(tmp)) {
1074 newout = (char *)xmalloc(out_len);
1075 newfree = 1;
1076 } else
1077 newout = tmp;
1078 log_quoted_string(out, newout);
1079 }
1080 break;
1081
1082 case LOG_QUOTE_MIMEBLOB:
1083 newout = QuoteMimeBlob(out);
1084 newfree = 1;
1085 break;
1086
1087 case LOG_QUOTE_URL:
1088 newout = rfc1738_escape(out);
1089 break;
1090
1091 case LOG_QUOTE_RAW:
1092 break;
1093 }
1094
1095 if (newout) {
1096 if (dofree)
1097 safe_free(out);
1098
1099 out = newout;
1100
1101 dofree = newfree;
1102 }
1103 }
1104
c32c6db7 1105 // enforce width limits if configured
8846a2b4
CT
1106 const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff;
1107 if (haveMaxWidth || fmt->widthMin) {
1108 const int minWidth = fmt->widthMin >= 0 ?
b8ad91f5 1109 fmt->widthMin :0;
c32c6db7 1110 const int maxWidth = haveMaxWidth ?
8846a2b4 1111 fmt->widthMax : strlen(out);
c32c6db7 1112
38e16f92 1113 if (fmt->left)
c32c6db7 1114 mb.Printf("%-*.*s", minWidth, maxWidth, out);
38e16f92 1115 else
c32c6db7 1116 mb.Printf("%*.*s", minWidth, maxWidth, out);
38e16f92
AJ
1117 } else
1118 mb.append(out, strlen(out));
1119 } else {
1120 mb.append("-", 1);
1121 }
1122
1123 if (fmt->space)
1124 mb.append(" ", 1);
1125
1126 sb.clean();
1127
1128 if (dofree)
1129 safe_free(out);
1130 }
1131}