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