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