]> git.ipfire.org Git - thirdparty/squid.git/blame - src/format/Format.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / format / Format.cc
CommitLineData
38e16f92
AJ
1#include "config.h"
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
374 const bool interceptedAtKnownPort = (al->request->flags.spoof_client_ip ||
375 al->request->flags.intercepted) && al->cache.port;
376 if (interceptedAtKnownPort) {
377 const bool portAddressConfigured = !al->cache.port->s.IsAnyAddr();
378 if (portAddressConfigured)
379 out = al->cache.port->s.NtoA(tmp, sizeof(tmp));
380 } else if (al->tcpClient != NULL)
381 out = al->tcpClient->local.NtoA(tmp, sizeof(tmp));
382 }
383 break;
384
8652f8e7 385 case LFT_CLIENT_LOCAL_IP:
a14f38d0
AJ
386 if (al->tcpClient != NULL) {
387 out = al->tcpClient->local.NtoA(tmp,sizeof(tmp));
38e16f92 388 }
38e16f92
AJ
389 break;
390
28417506
CT
391 case LFT_LOCAL_LISTENING_PORT:
392 if (al->cache.port) {
393 outint = al->cache.port->s.GetPort();
394 doint = 1;
395 }
396 break;
397
8652f8e7 398 case LFT_CLIENT_LOCAL_PORT:
a14f38d0
AJ
399 if (al->tcpClient != NULL) {
400 outint = al->tcpClient->local.GetPort();
38e16f92
AJ
401 doint = 1;
402 }
38e16f92
AJ
403 break;
404
8652f8e7
AJ
405 case LFT_SERVER_LOCAL_IP_OLD_27:
406 case LFT_SERVER_LOCAL_IP:
a14f38d0
AJ
407 if (al->hier.tcpServer != NULL) {
408 out = al->hier.tcpServer->local.NtoA(tmp,sizeof(tmp));
38e16f92
AJ
409 }
410 break;
411
8652f8e7 412 case LFT_SERVER_LOCAL_PORT:
a14f38d0
AJ
413 if (al->hier.tcpServer != NULL) {
414 outint = al->hier.tcpServer->local.GetPort();
38e16f92
AJ
415 doint = 1;
416 }
417
418 break;
419
420 case LFT_TIME_SECONDS_SINCE_EPOCH:
421 // some platforms store time in 32-bit, some 64-bit...
422 outoff = static_cast<int64_t>(current_time.tv_sec);
423 dooff = 1;
424 break;
425
426 case LFT_TIME_SUBSECOND:
427 outint = current_time.tv_usec / fmt->divisor;
428 doint = 1;
429 break;
430
431
432 case LFT_TIME_LOCALTIME:
433
434 case LFT_TIME_GMT: {
435 const char *spec;
436
437 struct tm *t;
438 spec = fmt->data.timespec;
439
440 if (fmt->type == LFT_TIME_LOCALTIME) {
441 if (!spec)
442 spec = "%d/%b/%Y:%H:%M:%S %z";
443 t = localtime(&squid_curtime);
444 } else {
445 if (!spec)
446 spec = "%d/%b/%Y:%H:%M:%S";
447
448 t = gmtime(&squid_curtime);
449 }
450
451 strftime(tmp, sizeof(tmp), spec, t);
452
453 out = tmp;
454 }
455
456 break;
457
458 case LFT_TIME_TO_HANDLE_REQUEST:
459 outint = al->cache.msec;
460 doint = 1;
461 break;
462
463 case LFT_PEER_RESPONSE_TIME:
464 if (al->hier.peer_response_time < 0) {
465 out = "-";
466 } else {
467 outoff = al->hier.peer_response_time;
468 dooff = 1;
469 }
470 break;
471
472 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME:
473 if (al->hier.total_response_time < 0) {
474 out = "-";
475 } else {
476 outoff = al->hier.total_response_time;
477 dooff = 1;
478 }
479 break;
480
481 case LFT_DNS_WAIT_TIME:
482 if (al->request && al->request->dnsWait >= 0) {
483 outint = al->request->dnsWait;
484 doint = 1;
485 }
486 break;
487
488 case LFT_REQUEST_HEADER:
489
490 if (al->request)
491 sb = al->request->header.getByName(fmt->data.header.header);
492
493 out = sb.termedBuf();
494
495 quote = 1;
496
497 break;
498
499 case LFT_ADAPTED_REQUEST_HEADER:
500
501 if (al->request)
502 sb = al->adapted_request->header.getByName(fmt->data.header.header);
503
504 out = sb.termedBuf();
505
506 quote = 1;
507
508 break;
509
510 case LFT_REPLY_HEADER:
511 if (al->reply)
512 sb = al->reply->header.getByName(fmt->data.header.header);
513
514 out = sb.termedBuf();
515
516 quote = 1;
517
518 break;
519
520#if USE_ADAPTATION
31971e6a 521 case LFT_ADAPTATION_SUM_XACT_TIMES:
38e16f92
AJ
522 if (al->request) {
523 Adaptation::History::Pointer ah = al->request->adaptHistory();
524 if (ah != NULL)
525 ah->sumLogString(fmt->data.string, sb);
526 out = sb.termedBuf();
527 }
528 break;
529
31971e6a 530 case LFT_ADAPTATION_ALL_XACT_TIMES:
38e16f92
AJ
531 if (al->request) {
532 Adaptation::History::Pointer ah = al->request->adaptHistory();
533 if (ah != NULL)
534 ah->allLogString(fmt->data.string, sb);
535 out = sb.termedBuf();
536 }
537 break;
538
539 case LFT_ADAPTATION_LAST_HEADER:
540 if (al->request) {
541 const Adaptation::History::Pointer ah = al->request->adaptHistory();
542 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
543 sb = ah->allMeta.getByName(fmt->data.header.header);
544 }
545
546 // XXX: here and elsewhere: move such code inside the if guard
547 out = sb.termedBuf();
548
549 quote = 1;
550
551 break;
552
553 case LFT_ADAPTATION_LAST_HEADER_ELEM:
554 if (al->request) {
555 const Adaptation::History::Pointer ah = al->request->adaptHistory();
556 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
557 sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
558 }
559
560 out = sb.termedBuf();
561
562 quote = 1;
563
564 break;
565
566 case LFT_ADAPTATION_LAST_ALL_HEADERS:
567 out = al->adapt.last_meta;
568
569 quote = 1;
570
571 break;
572#endif
573
574#if ICAP_CLIENT
575 case LFT_ICAP_ADDR:
576 if (!out)
577 out = al->icap.hostAddr.NtoA(tmp,1024);
578 break;
579
580 case LFT_ICAP_SERV_NAME:
581 out = al->icap.serviceName.termedBuf();
582 break;
583
584 case LFT_ICAP_REQUEST_URI:
585 out = al->icap.reqUri.termedBuf();
586 break;
587
588 case LFT_ICAP_REQUEST_METHOD:
589 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
590 break;
591
592 case LFT_ICAP_BYTES_SENT:
593 outoff = al->icap.bytesSent;
594 dooff = 1;
595 break;
596
597 case LFT_ICAP_BYTES_READ:
598 outoff = al->icap.bytesRead;
599 dooff = 1;
600 break;
601
602 case LFT_ICAP_BODY_BYTES_READ:
603 if (al->icap.bodyBytesRead >= 0) {
604 outoff = al->icap.bodyBytesRead;
605 dooff = 1;
606 }
607 // else if icap.bodyBytesRead < 0, we do not have any http data,
608 // so just print a "-" (204 responses etc)
609 break;
610
611 case LFT_ICAP_REQ_HEADER:
612 if (NULL != al->icap.request) {
613 sb = al->icap.request->header.getByName(fmt->data.header.header);
614 out = sb.termedBuf();
615 quote = 1;
616 }
617 break;
618
619 case LFT_ICAP_REQ_HEADER_ELEM:
620 if (al->request)
621 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
622
623 out = sb.termedBuf();
624
625 quote = 1;
626
627 break;
628
629 case LFT_ICAP_REQ_ALL_HEADERS:
630 if (al->icap.request) {
631 HttpHeaderPos pos = HttpHeaderInitPos;
632 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
633 sb.append(e->name);
634 sb.append(": ");
635 sb.append(e->value);
636 sb.append("\r\n");
637 }
638 out = sb.termedBuf();
639 quote = 1;
640 }
641 break;
642
643 case LFT_ICAP_REP_HEADER:
644 if (NULL != al->icap.reply) {
645 sb = al->icap.reply->header.getByName(fmt->data.header.header);
646 out = sb.termedBuf();
647 quote = 1;
648 }
649 break;
650
651 case LFT_ICAP_REP_HEADER_ELEM:
652 if (NULL != al->icap.reply)
653 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
654
655 out = sb.termedBuf();
656
657 quote = 1;
658
659 break;
660
661 case LFT_ICAP_REP_ALL_HEADERS:
662 if (al->icap.reply) {
663 HttpHeaderPos pos = HttpHeaderInitPos;
664 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
665 sb.append(e->name);
666 sb.append(": ");
667 sb.append(e->value);
668 sb.append("\r\n");
669 }
670 out = sb.termedBuf();
671 quote = 1;
672 }
673 break;
674
675 case LFT_ICAP_TR_RESPONSE_TIME:
676 outint = al->icap.trTime;
677 doint = 1;
678 break;
679
680 case LFT_ICAP_IO_TIME:
681 outint = al->icap.ioTime;
682 doint = 1;
683 break;
684
685 case LFT_ICAP_STATUS_CODE:
686 outint = al->icap.resStatus;
687 doint = 1;
688 break;
689
690 case LFT_ICAP_OUTCOME:
691 out = al->icap.outcome;
692 break;
693
694 case LFT_ICAP_TOTAL_TIME:
695 outint = al->icap.processingTime;
696 doint = 1;
697 break;
698#endif
699 case LFT_REQUEST_HEADER_ELEM:
700 if (al->request)
701 sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
702
703 out = sb.termedBuf();
704
705 quote = 1;
706
707 break;
708
709 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
710 if (al->adapted_request)
711 sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
712
713 out = sb.termedBuf();
714
715 quote = 1;
716
717 break;
718
719 case LFT_REPLY_HEADER_ELEM:
720 if (al->reply)
721 sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
722
723 out = sb.termedBuf();
724
725 quote = 1;
726
727 break;
728
729 case LFT_REQUEST_ALL_HEADERS:
730 out = al->headers.request;
731
732 quote = 1;
733
734 break;
735
736 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
737 out = al->headers.adapted_request;
738
739 quote = 1;
740
741 break;
742
743 case LFT_REPLY_ALL_HEADERS:
744 out = al->headers.reply;
745
746 quote = 1;
747
748 break;
749
750 case LFT_USER_NAME:
bd85ea1f 751 out = strOrNull(al->cache.authuser);
38e16f92 752 if (!out)
bd85ea1f 753 out = strOrNull(al->cache.extuser);
38e16f92 754#if USE_SSL
38e16f92 755 if (!out)
bd85ea1f 756 out = strOrNull(al->cache.ssluser);
38e16f92 757#endif
38e16f92 758 if (!out)
bd85ea1f 759 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
760 break;
761
762 case LFT_USER_LOGIN:
bd85ea1f 763 out = strOrNull(al->cache.authuser);
38e16f92
AJ
764 break;
765
766 case LFT_USER_IDENT:
bd85ea1f 767 out = strOrNull(al->cache.rfc931);
38e16f92
AJ
768 break;
769
770 case LFT_USER_EXTERNAL:
bd85ea1f 771 out = strOrNull(al->cache.extuser);
38e16f92
AJ
772 break;
773
774 /* case LFT_USER_REALM: */
775 /* case LFT_USER_SCHEME: */
776
777 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
778 // but compiler complains if ommited
779 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
780 case LFT_HTTP_SENT_STATUS_CODE:
781 outint = al->http.code;
782
783 doint = 1;
784
785 break;
786
787 case LFT_HTTP_RECEIVED_STATUS_CODE:
788 if (al->hier.peer_reply_status == HTTP_STATUS_NONE) {
789 out = "-";
790 } else {
791 outint = al->hier.peer_reply_status;
792 doint = 1;
793 }
794 break;
795 /* case LFT_HTTP_STATUS:
796 * out = statusline->text;
797 * quote = 1;
798 * break;
799 */
800 case LFT_HTTP_BODY_BYTES_READ:
801 if (al->hier.bodyBytesRead >= 0) {
802 outoff = al->hier.bodyBytesRead;
803 dooff = 1;
804 }
805 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
806 // a peer server so just print a "-" (eg requests served from cache,
807 // or internal error messages).
808 break;
809
810 case LFT_SQUID_STATUS:
811 if (al->http.timedout || al->http.aborted) {
812 snprintf(tmp, sizeof(tmp), "%s%s", log_tags[al->cache.code],
813 al->http.statusSfx());
814 out = tmp;
815 } else {
816 out = log_tags[al->cache.code];
817 }
818
819 break;
820
821 case LFT_SQUID_ERROR:
822 if (al->request && al->request->errType != ERR_NONE)
823 out = errorPageName(al->request->errType);
824 break;
825
826 case LFT_SQUID_ERROR_DETAIL:
2f3e52b5
CT
827#if USE_SSL
828 if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
829 if (! (out = Ssl::GetErrorName(al->request->errDetail))) {
830 snprintf(tmp, sizeof(tmp), "SSL_ERR=%d", al->request->errDetail);
831 out = tmp;
832 }
e83cdc25 833 } else
2f3e52b5 834#endif
e83cdc25
A
835 if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
836 if (al->request->errDetail > ERR_DETAIL_START &&
837 al->request->errDetail < ERR_DETAIL_MAX)
838 out = errorDetailName(al->request->errDetail);
839 else {
840 if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
841 snprintf(tmp, sizeof(tmp), "%s=0x%X",
842 errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
843 else
844 snprintf(tmp, sizeof(tmp), "%s=%d",
845 errorDetailName(al->request->errDetail), al->request->errDetail);
846 out = tmp;
847 }
38e16f92 848 }
38e16f92
AJ
849 break;
850
851 case LFT_SQUID_HIERARCHY:
852 if (al->hier.ping.timedout)
853 mb.append("TIMEOUT_", 8);
854
855 out = hier_code_str[al->hier.code];
856
857 break;
858
859 case LFT_MIME_TYPE:
860 out = al->http.content_type;
861
862 break;
863
864 case LFT_CLIENT_REQ_METHOD:
865 if (al->request) {
866 out = al->request->method.image();
867 quote = 1;
868 }
869 break;
870
871 case LFT_CLIENT_REQ_URI:
872 // original client URI
873 if (al->request) {
874 out = urlCanonical(al->request);
875 quote = 1;
876 }
877 break;
878
879 case LFT_REQUEST_URLPATH_OLD_31:
880 case LFT_CLIENT_REQ_URLPATH:
881 if (al->request) {
882 out = al->request->urlpath.termedBuf();
883 quote = 1;
884 }
885 break;
886
887 case LFT_CLIENT_REQ_VERSION:
888 if (al->request) {
889 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
890 out = tmp;
891 }
892 break;
893
894 case LFT_REQUEST_METHOD:
895 out = al->_private.method_str;
896 break;
897
898 case LFT_REQUEST_URI:
899 out = al->url;
900 break;
901
902 case LFT_REQUEST_VERSION_OLD_2X:
903 case LFT_REQUEST_VERSION:
904 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
905 out = tmp;
906 break;
907
908 case LFT_SERVER_REQ_METHOD:
909 if (al->adapted_request) {
910 out = al->adapted_request->method.image();
911 quote = 1;
912 }
913 break;
914
915 case LFT_SERVER_REQ_URI:
916 // adapted request URI sent to server/peer
917 if (al->adapted_request) {
918 out = urlCanonical(al->adapted_request);
919 quote = 1;
920 }
921 break;
922
923 case LFT_SERVER_REQ_URLPATH:
924 if (al->adapted_request) {
925 out = al->adapted_request->urlpath.termedBuf();
926 quote = 1;
927 }
928 break;
929
930 case LFT_SERVER_REQ_VERSION:
931 if (al->adapted_request) {
932 snprintf(tmp, sizeof(tmp), "%d.%d",
933 (int) al->adapted_request->http_ver.major,
934 (int) al->adapted_request->http_ver.minor);
935 out = tmp;
936 }
937 break;
938
939 case LFT_REQUEST_SIZE_TOTAL:
940 outoff = al->cache.requestSize;
941 dooff = 1;
942 break;
943
944 /*case LFT_REQUEST_SIZE_LINE: */
945 case LFT_REQUEST_SIZE_HEADERS:
946 outoff = al->cache.requestHeadersSize;
947 dooff =1;
948 break;
949 /*case LFT_REQUEST_SIZE_BODY: */
950 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
951
952 case LFT_REPLY_SIZE_TOTAL:
953 outoff = al->cache.replySize;
954 dooff = 1;
955 break;
956
957 case LFT_REPLY_HIGHOFFSET:
958 outoff = al->cache.highOffset;
959
960 dooff = 1;
961
962 break;
963
964 case LFT_REPLY_OBJECTSIZE:
965 outoff = al->cache.objectSize;
966
967 dooff = 1;
968
969 break;
970
971 /*case LFT_REPLY_SIZE_LINE: */
972 case LFT_REPLY_SIZE_HEADERS:
973 outint = al->cache.replyHeadersSize;
974 doint = 1;
975 break;
976 /*case LFT_REPLY_SIZE_BODY: */
977 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
978
979 case LFT_TAG:
980 if (al->request)
981 out = al->request->tag.termedBuf();
982
983 quote = 1;
984
985 break;
986
987 case LFT_IO_SIZE_TOTAL:
988 outint = al->cache.requestSize + al->cache.replySize;
989 doint = 1;
990 break;
991
992 case LFT_EXT_LOG:
993 if (al->request)
994 out = al->request->extacl_log.termedBuf();
995
996 quote = 1;
997
998 break;
999
1000 case LFT_SEQUENCE_NUMBER:
1001 outoff = logSequenceNumber;
1002 dooff = 1;
1003 break;
1004
1005 case LFT_PERCENT:
1006 out = "%";
1007
1008 break;
1009 }
1010
1011 if (dooff) {
8846a2b4 1012 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff);
38e16f92
AJ
1013 out = tmp;
1014
1015 } else if (doint) {
8846a2b4 1016 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
38e16f92
AJ
1017 out = tmp;
1018 }
1019
1020 if (out && *out) {
1021 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1022 char *newout = NULL;
1023 int newfree = 0;
1024
1025 switch (fmt->quote) {
1026
1027 case LOG_QUOTE_NONE:
1028 newout = rfc1738_escape_unescaped(out);
1029 break;
1030
1031 case LOG_QUOTE_QUOTES: {
1032 size_t out_len = static_cast<size_t>(strlen(out)) * 2 + 1;
1033 if (out_len >= sizeof(tmp)) {
1034 newout = (char *)xmalloc(out_len);
1035 newfree = 1;
1036 } else
1037 newout = tmp;
1038 log_quoted_string(out, newout);
1039 }
1040 break;
1041
1042 case LOG_QUOTE_MIMEBLOB:
1043 newout = QuoteMimeBlob(out);
1044 newfree = 1;
1045 break;
1046
1047 case LOG_QUOTE_URL:
1048 newout = rfc1738_escape(out);
1049 break;
1050
1051 case LOG_QUOTE_RAW:
1052 break;
1053 }
1054
1055 if (newout) {
1056 if (dofree)
1057 safe_free(out);
1058
1059 out = newout;
1060
1061 dofree = newfree;
1062 }
1063 }
1064
c32c6db7 1065 // enforce width limits if configured
8846a2b4
CT
1066 const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff;
1067 if (haveMaxWidth || fmt->widthMin) {
1068 const int minWidth = fmt->widthMin >= 0 ?
b8ad91f5 1069 fmt->widthMin :0;
c32c6db7 1070 const int maxWidth = haveMaxWidth ?
8846a2b4 1071 fmt->widthMax : strlen(out);
c32c6db7 1072
38e16f92 1073 if (fmt->left)
c32c6db7 1074 mb.Printf("%-*.*s", minWidth, maxWidth, out);
38e16f92 1075 else
c32c6db7 1076 mb.Printf("%*.*s", minWidth, maxWidth, out);
38e16f92
AJ
1077 } else
1078 mb.append(out, strlen(out));
1079 } else {
1080 mb.append("-", 1);
1081 }
1082
1083 if (fmt->space)
1084 mb.append(" ", 1);
1085
1086 sb.clean();
1087
1088 if (dofree)
1089 safe_free(out);
1090 }
1091}