]> git.ipfire.org Git - thirdparty/squid.git/blob - src/format/Format.cc
Merged from trunk 13199.
[thirdparty/squid.git] / src / format / Format.cc
1 #include "squid.h"
2 #include "AccessLogEntry.h"
3 #include "client_side.h"
4 #include "comm/Connection.h"
5 #include "err_detail_type.h"
6 #include "errorpage.h"
7 #include "fde.h"
8 #include "format/Format.h"
9 #include "format/Quoting.h"
10 #include "format/Token.h"
11 #include "fqdncache.h"
12 #include "HttpRequest.h"
13 #include "MemBuf.h"
14 #include "rfc1738.h"
15 #include "SquidTime.h"
16 #include "Store.h"
17 #include "URL.h"
18 #if USE_SSL
19 #include "ssl/ErrorDetail.h"
20 #endif
21
22 /// Convert a string to NULL pointer if it is ""
23 #define strOrNull(s) ((s)==NULL||(s)[0]=='\0'?NULL:(s))
24
25 Format::Format::Format(const char *n) :
26 format(NULL),
27 next(NULL)
28 {
29 name = xstrdup(n);
30 }
31
32 Format::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
48 bool
49 Format::Format::parse(const char *def)
50 {
51 const char *cur, *eos;
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
81 void
82 Format::Format::dump(StoreEntry * entry, const char *directiveName)
83 {
84 debugs(46, 4, HERE);
85
86 // loop rather than recursing to conserve stack space.
87 for (Format *fmt = this; fmt; fmt = fmt->next) {
88 debugs(46, 3, HERE << "Dumping format definition for " << fmt->name);
89 storeAppendPrintf(entry, "%s %s ", directiveName, fmt->name);
90
91 for (Token *t = fmt->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
229 if (t->widthMin >= 0)
230 storeAppendPrintf(entry, "%d", t->widthMin);
231
232 if (t->widthMax >= 0)
233 storeAppendPrintf(entry, ".%d", t->widthMax);
234
235 if (arg)
236 storeAppendPrintf(entry, "{%s}", arg);
237
238 storeAppendPrintf(entry, "%s", t->label);
239
240 if (t->space)
241 entry->append(" ", 1);
242 }
243 }
244
245 entry->append("\n", 1);
246 }
247
248 }
249
250 static void
251 log_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':
267 *p = '\\';
268 ++p;
269 *p = 'r';
270 ++p;
271 ++str;
272 break;
273
274 case '\n':
275 *p = '\\';
276 ++p;
277 *p = 'n';
278 ++p;
279 ++str;
280 break;
281
282 case '\t':
283 *p = '\\';
284 ++p;
285 *p = 't';
286 ++p;
287 ++str;
288 break;
289
290 default:
291 *p = '\\';
292 ++p;
293 *p = *str;
294 ++p;
295 ++str;
296 break;
297 }
298 }
299
300 *p = '\0';
301 }
302
303 void
304 Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logSequenceNumber) const
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:
329 al->getLogClientIp(tmp, sizeof(tmp));
330 out = tmp;
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.toStr(tmp,1024);
340 }
341
342 break;
343
344 case LFT_CLIENT_PORT:
345 if (al->request) {
346 outint = al->request->client_addr.port();
347 doint = 1;
348 }
349 break;
350
351 case LFT_CLIENT_EUI:
352 #if USE_SQUID_EUI
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 }
361 #else
362 out = "-";
363 #endif
364 break;
365
366 case LFT_SERVER_IP_ADDRESS:
367 if (al->hier.tcpServer != NULL) {
368 out = al->hier.tcpServer->remote.toStr(tmp,sizeof(tmp));
369 }
370 break;
371
372 case LFT_SERVER_FQDN_OR_PEER_NAME:
373 out = al->hier.host;
374 break;
375
376 case LFT_SERVER_PORT:
377 if (al->hier.tcpServer != NULL) {
378 outint = al->hier.tcpServer->remote.port();
379 doint = 1;
380 }
381 break;
382
383 case LFT_LOCAL_LISTENING_IP: {
384 // avoid logging a dash if we have reliable info
385 const bool interceptedAtKnownPort = al->request ?
386 (al->request->flags.interceptTproxy ||
387 al->request->flags.intercepted) && al->cache.port :
388 false;
389 if (interceptedAtKnownPort) {
390 const bool portAddressConfigured = !al->cache.port->s.isAnyAddr();
391 if (portAddressConfigured)
392 out = al->cache.port->s.toStr(tmp, sizeof(tmp));
393 } else if (al->tcpClient != NULL)
394 out = al->tcpClient->local.toStr(tmp, sizeof(tmp));
395 }
396 break;
397
398 case LFT_CLIENT_LOCAL_IP:
399 if (al->tcpClient != NULL) {
400 out = al->tcpClient->local.toStr(tmp,sizeof(tmp));
401 }
402 break;
403
404 case LFT_CLIENT_LOCAL_TOS:
405 if (al->tcpClient != NULL) {
406 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->tcpClient->tos);
407 out = tmp;
408 }
409 break;
410
411 case LFT_CLIENT_LOCAL_NFMARK:
412 if (al->tcpClient != NULL) {
413 snprintf(tmp, sizeof(tmp), "0x%x", al->tcpClient->nfmark);
414 out = tmp;
415 }
416 break;
417
418 case LFT_LOCAL_LISTENING_PORT:
419 if (al->cache.port) {
420 outint = al->cache.port->s.port();
421 doint = 1;
422 }
423 break;
424
425 case LFT_CLIENT_LOCAL_PORT:
426 if (al->tcpClient != NULL) {
427 outint = al->tcpClient->local.port();
428 doint = 1;
429 }
430 break;
431
432 case LFT_SERVER_LOCAL_IP_OLD_27:
433 case LFT_SERVER_LOCAL_IP:
434 if (al->hier.tcpServer != NULL) {
435 out = al->hier.tcpServer->local.toStr(tmp,sizeof(tmp));
436 }
437 break;
438
439 case LFT_SERVER_LOCAL_PORT:
440 if (al->hier.tcpServer != NULL) {
441 outint = al->hier.tcpServer->local.port();
442 doint = 1;
443 }
444
445 break;
446
447 case LFT_SERVER_LOCAL_TOS:
448 if (al->hier.tcpServer != NULL) {
449 snprintf(tmp, sizeof(tmp), "0x%x", (uint32_t)al->hier.tcpServer->tos);
450 out = tmp;
451 }
452 break;
453
454 case LFT_SERVER_LOCAL_NFMARK:
455 if (al->hier.tcpServer != NULL) {
456 snprintf(tmp, sizeof(tmp), "0x%x", al->hier.tcpServer->nfmark);
457 out = tmp;
458 }
459 break;
460
461 case LFT_TIME_SECONDS_SINCE_EPOCH:
462 // some platforms store time in 32-bit, some 64-bit...
463 outoff = static_cast<int64_t>(current_time.tv_sec);
464 dooff = 1;
465 break;
466
467 case LFT_TIME_SUBSECOND:
468 outint = current_time.tv_usec / fmt->divisor;
469 doint = 1;
470 break;
471
472 case LFT_TIME_LOCALTIME:
473
474 case LFT_TIME_GMT: {
475 const char *spec;
476
477 struct tm *t;
478 spec = fmt->data.timespec;
479
480 if (fmt->type == LFT_TIME_LOCALTIME) {
481 if (!spec)
482 spec = "%d/%b/%Y:%H:%M:%S %z";
483 t = localtime(&squid_curtime);
484 } else {
485 if (!spec)
486 spec = "%d/%b/%Y:%H:%M:%S";
487
488 t = gmtime(&squid_curtime);
489 }
490
491 strftime(tmp, sizeof(tmp), spec, t);
492
493 out = tmp;
494 }
495
496 break;
497
498 case LFT_TIME_START: {
499 int precision = fmt->widthMax >=0 ? fmt->widthMax : 3;
500 snprintf(tmp, sizeof(tmp), "%0*" PRId64 ".%0*d", fmt->zero && (fmt->widthMin - precision - 1 >= 0) ? fmt->widthMin - precision - 1 : 0, static_cast<int64_t>(al->cache.start_time.tv_sec), precision, (int)(al->cache.start_time.tv_usec / fmt->divisor));
501 out = tmp;
502 }
503 break;
504
505 case LFT_TIME_TO_HANDLE_REQUEST:
506 outint = al->cache.msec;
507 doint = 1;
508 break;
509
510 case LFT_PEER_RESPONSE_TIME:
511 if (al->hier.peer_response_time < 0) {
512 out = "-";
513 } else {
514 outoff = al->hier.peer_response_time;
515 dooff = 1;
516 }
517 break;
518
519 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME:
520 if (al->hier.total_response_time < 0) {
521 out = "-";
522 } else {
523 outoff = al->hier.total_response_time;
524 dooff = 1;
525 }
526 break;
527
528 case LFT_DNS_WAIT_TIME:
529 if (al->request && al->request->dnsWait >= 0) {
530 outint = al->request->dnsWait;
531 doint = 1;
532 }
533 break;
534
535 case LFT_REQUEST_HEADER:
536
537 if (al->request)
538 sb = al->request->header.getByName(fmt->data.header.header);
539
540 out = sb.termedBuf();
541
542 quote = 1;
543
544 break;
545
546 case LFT_ADAPTED_REQUEST_HEADER:
547
548 if (al->adapted_request)
549 sb = al->adapted_request->header.getByName(fmt->data.header.header);
550
551 out = sb.termedBuf();
552
553 quote = 1;
554
555 break;
556
557 case LFT_REPLY_HEADER:
558 if (al->reply)
559 sb = al->reply->header.getByName(fmt->data.header.header);
560
561 out = sb.termedBuf();
562
563 quote = 1;
564
565 break;
566
567 #if USE_ADAPTATION
568 case LFT_ADAPTATION_SUM_XACT_TIMES:
569 if (al->request) {
570 Adaptation::History::Pointer ah = al->request->adaptHistory();
571 if (ah != NULL)
572 ah->sumLogString(fmt->data.string, sb);
573 out = sb.termedBuf();
574 }
575 break;
576
577 case LFT_ADAPTATION_ALL_XACT_TIMES:
578 if (al->request) {
579 Adaptation::History::Pointer ah = al->request->adaptHistory();
580 if (ah != NULL)
581 ah->allLogString(fmt->data.string, sb);
582 out = sb.termedBuf();
583 }
584 break;
585
586 case LFT_ADAPTATION_LAST_HEADER:
587 if (al->request) {
588 const Adaptation::History::Pointer ah = al->request->adaptHistory();
589 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
590 sb = ah->allMeta.getByName(fmt->data.header.header);
591 }
592
593 // XXX: here and elsewhere: move such code inside the if guard
594 out = sb.termedBuf();
595
596 quote = 1;
597
598 break;
599
600 case LFT_ADAPTATION_LAST_HEADER_ELEM:
601 if (al->request) {
602 const Adaptation::History::Pointer ah = al->request->adaptHistory();
603 if (ah != NULL) // XXX: add adapt::<all_h but use lastMeta here
604 sb = ah->allMeta.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
605 }
606
607 out = sb.termedBuf();
608
609 quote = 1;
610
611 break;
612
613 case LFT_ADAPTATION_LAST_ALL_HEADERS:
614 out = al->adapt.last_meta;
615
616 quote = 1;
617
618 break;
619 #endif
620
621 #if ICAP_CLIENT
622 case LFT_ICAP_ADDR:
623 if (!out)
624 out = al->icap.hostAddr.toStr(tmp,1024);
625 break;
626
627 case LFT_ICAP_SERV_NAME:
628 out = al->icap.serviceName.termedBuf();
629 break;
630
631 case LFT_ICAP_REQUEST_URI:
632 out = al->icap.reqUri.termedBuf();
633 break;
634
635 case LFT_ICAP_REQUEST_METHOD:
636 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
637 break;
638
639 case LFT_ICAP_BYTES_SENT:
640 outoff = al->icap.bytesSent;
641 dooff = 1;
642 break;
643
644 case LFT_ICAP_BYTES_READ:
645 outoff = al->icap.bytesRead;
646 dooff = 1;
647 break;
648
649 case LFT_ICAP_BODY_BYTES_READ:
650 if (al->icap.bodyBytesRead >= 0) {
651 outoff = al->icap.bodyBytesRead;
652 dooff = 1;
653 }
654 // else if icap.bodyBytesRead < 0, we do not have any http data,
655 // so just print a "-" (204 responses etc)
656 break;
657
658 case LFT_ICAP_REQ_HEADER:
659 if (NULL != al->icap.request) {
660 sb = al->icap.request->header.getByName(fmt->data.header.header);
661 out = sb.termedBuf();
662 quote = 1;
663 }
664 break;
665
666 case LFT_ICAP_REQ_HEADER_ELEM:
667 if (al->icap.request)
668 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
669
670 out = sb.termedBuf();
671
672 quote = 1;
673
674 break;
675
676 case LFT_ICAP_REQ_ALL_HEADERS:
677 if (al->icap.request) {
678 HttpHeaderPos pos = HttpHeaderInitPos;
679 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
680 sb.append(e->name);
681 sb.append(": ");
682 sb.append(e->value);
683 sb.append("\r\n");
684 }
685 out = sb.termedBuf();
686 quote = 1;
687 }
688 break;
689
690 case LFT_ICAP_REP_HEADER:
691 if (NULL != al->icap.reply) {
692 sb = al->icap.reply->header.getByName(fmt->data.header.header);
693 out = sb.termedBuf();
694 quote = 1;
695 }
696 break;
697
698 case LFT_ICAP_REP_HEADER_ELEM:
699 if (NULL != al->icap.reply)
700 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
701
702 out = sb.termedBuf();
703
704 quote = 1;
705
706 break;
707
708 case LFT_ICAP_REP_ALL_HEADERS:
709 if (al->icap.reply) {
710 HttpHeaderPos pos = HttpHeaderInitPos;
711 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
712 sb.append(e->name);
713 sb.append(": ");
714 sb.append(e->value);
715 sb.append("\r\n");
716 }
717 out = sb.termedBuf();
718 quote = 1;
719 }
720 break;
721
722 case LFT_ICAP_TR_RESPONSE_TIME:
723 outint = al->icap.trTime;
724 doint = 1;
725 break;
726
727 case LFT_ICAP_IO_TIME:
728 outint = al->icap.ioTime;
729 doint = 1;
730 break;
731
732 case LFT_ICAP_STATUS_CODE:
733 outint = al->icap.resStatus;
734 doint = 1;
735 break;
736
737 case LFT_ICAP_OUTCOME:
738 out = al->icap.outcome;
739 break;
740
741 case LFT_ICAP_TOTAL_TIME:
742 outint = al->icap.processingTime;
743 doint = 1;
744 break;
745 #endif
746 case LFT_REQUEST_HEADER_ELEM:
747 if (al->request)
748 sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
749
750 out = sb.termedBuf();
751
752 quote = 1;
753
754 break;
755
756 case LFT_ADAPTED_REQUEST_HEADER_ELEM:
757 if (al->adapted_request)
758 sb = al->adapted_request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
759
760 out = sb.termedBuf();
761
762 quote = 1;
763
764 break;
765
766 case LFT_REPLY_HEADER_ELEM:
767 if (al->reply)
768 sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
769
770 out = sb.termedBuf();
771
772 quote = 1;
773
774 break;
775
776 case LFT_REQUEST_ALL_HEADERS:
777 out = al->headers.request;
778
779 quote = 1;
780
781 break;
782
783 case LFT_ADAPTED_REQUEST_ALL_HEADERS:
784 out = al->headers.adapted_request;
785
786 quote = 1;
787
788 break;
789
790 case LFT_REPLY_ALL_HEADERS:
791 out = al->headers.reply;
792
793 quote = 1;
794
795 break;
796
797 case LFT_USER_NAME:
798 #if USE_AUTH
799 if (al->request && al->request->auth_user_request != NULL)
800 out = strOrNull(al->request->auth_user_request->username());
801 #endif
802 if (!out)
803 out = strOrNull(al->cache.extuser);
804 #if USE_SSL
805 if (!out)
806 out = strOrNull(al->cache.ssluser);
807 #endif
808 if (!out)
809 out = strOrNull(al->cache.rfc931);
810 break;
811
812 case LFT_USER_LOGIN:
813 #if USE_AUTH
814 if (al->request && al->request->auth_user_request != NULL)
815 out = strOrNull(al->request->auth_user_request->username());
816 #endif
817 break;
818
819 case LFT_USER_IDENT:
820 out = strOrNull(al->cache.rfc931);
821 break;
822
823 case LFT_USER_EXTERNAL:
824 out = strOrNull(al->cache.extuser);
825 break;
826
827 /* case LFT_USER_REALM: */
828 /* case LFT_USER_SCHEME: */
829
830 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
831 // but compiler complains if ommited
832 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
833 case LFT_HTTP_SENT_STATUS_CODE:
834 outint = al->http.code;
835
836 doint = 1;
837
838 break;
839
840 case LFT_HTTP_RECEIVED_STATUS_CODE:
841 if (al->hier.peer_reply_status == Http::scNone) {
842 out = "-";
843 } else {
844 outint = al->hier.peer_reply_status;
845 doint = 1;
846 }
847 break;
848 /* case LFT_HTTP_STATUS:
849 * out = statusline->text;
850 * quote = 1;
851 * break;
852 */
853 case LFT_HTTP_BODY_BYTES_READ:
854 if (al->hier.bodyBytesRead >= 0) {
855 outoff = al->hier.bodyBytesRead;
856 dooff = 1;
857 }
858 // else if hier.bodyBytesRead < 0 we did not have any data exchange with
859 // a peer server so just print a "-" (eg requests served from cache,
860 // or internal error messages).
861 break;
862
863 case LFT_SQUID_STATUS:
864 if (al->http.timedout || al->http.aborted) {
865 snprintf(tmp, sizeof(tmp), "%s%s", LogTags_str[al->cache.code],
866 al->http.statusSfx());
867 out = tmp;
868 } else {
869 out = LogTags_str[al->cache.code];
870 }
871
872 break;
873
874 case LFT_SQUID_ERROR:
875 if (al->request && al->request->errType != ERR_NONE)
876 out = errorPageName(al->request->errType);
877 break;
878
879 case LFT_SQUID_ERROR_DETAIL:
880 #if USE_SSL
881 if (al->request && al->request->errType == ERR_SECURE_CONNECT_FAIL) {
882 if (! (out = Ssl::GetErrorName(al->request->errDetail))) {
883 snprintf(tmp, sizeof(tmp), "SSL_ERR=%d", al->request->errDetail);
884 out = tmp;
885 }
886 } else
887 #endif
888 if (al->request && al->request->errDetail != ERR_DETAIL_NONE) {
889 if (al->request->errDetail > ERR_DETAIL_START &&
890 al->request->errDetail < ERR_DETAIL_MAX)
891 out = errorDetailName(al->request->errDetail);
892 else {
893 if (al->request->errDetail >= ERR_DETAIL_EXCEPTION_START)
894 snprintf(tmp, sizeof(tmp), "%s=0x%X",
895 errorDetailName(al->request->errDetail), (uint32_t) al->request->errDetail);
896 else
897 snprintf(tmp, sizeof(tmp), "%s=%d",
898 errorDetailName(al->request->errDetail), al->request->errDetail);
899 out = tmp;
900 }
901 }
902 break;
903
904 case LFT_SQUID_HIERARCHY:
905 if (al->hier.ping.timedout)
906 mb.append("TIMEOUT_", 8);
907
908 out = hier_code_str[al->hier.code];
909
910 break;
911
912 case LFT_MIME_TYPE:
913 out = al->http.content_type;
914
915 break;
916
917 case LFT_CLIENT_REQ_METHOD:
918 if (al->request) {
919 out = al->request->method.image();
920 quote = 1;
921 }
922 break;
923
924 case LFT_CLIENT_REQ_URI:
925 // original client URI
926 if (al->request) {
927 out = urlCanonical(al->request);
928 quote = 1;
929 }
930 break;
931
932 case LFT_REQUEST_URLPATH_OLD_31:
933 case LFT_CLIENT_REQ_URLPATH:
934 if (al->request) {
935 out = al->request->urlpath.termedBuf();
936 quote = 1;
937 }
938 break;
939
940 case LFT_CLIENT_REQ_VERSION:
941 if (al->request) {
942 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->request->http_ver.major, (int) al->request->http_ver.minor);
943 out = tmp;
944 }
945 break;
946
947 case LFT_REQUEST_METHOD:
948 out = al->_private.method_str;
949 break;
950
951 case LFT_REQUEST_URI:
952 out = al->url;
953 break;
954
955 case LFT_REQUEST_VERSION_OLD_2X:
956 case LFT_REQUEST_VERSION:
957 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
958 out = tmp;
959 break;
960
961 case LFT_SERVER_REQ_METHOD:
962 if (al->adapted_request) {
963 out = al->adapted_request->method.image();
964 quote = 1;
965 }
966 break;
967
968 case LFT_SERVER_REQ_URI:
969 // adapted request URI sent to server/peer
970 if (al->adapted_request) {
971 out = urlCanonical(al->adapted_request);
972 quote = 1;
973 }
974 break;
975
976 case LFT_SERVER_REQ_URLPATH:
977 if (al->adapted_request) {
978 out = al->adapted_request->urlpath.termedBuf();
979 quote = 1;
980 }
981 break;
982
983 case LFT_SERVER_REQ_VERSION:
984 if (al->adapted_request) {
985 snprintf(tmp, sizeof(tmp), "%d.%d",
986 (int) al->adapted_request->http_ver.major,
987 (int) al->adapted_request->http_ver.minor);
988 out = tmp;
989 }
990 break;
991
992 case LFT_CLIENT_REQUEST_SIZE_TOTAL:
993 outoff = al->http.clientRequestSz.messageTotal();
994 dooff = 1;
995 break;
996
997 case LFT_CLIENT_REQUEST_SIZE_HEADERS:
998 outoff = al->http.clientRequestSz.header;
999 dooff =1;
1000 break;
1001
1002 /*case LFT_REQUEST_SIZE_BODY: */
1003 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1004
1005 case LFT_ADAPTED_REPLY_SIZE_TOTAL:
1006 outoff = al->http.clientReplySz.messageTotal();
1007 dooff = 1;
1008 break;
1009
1010 case LFT_REPLY_HIGHOFFSET:
1011 outoff = al->cache.highOffset;
1012
1013 dooff = 1;
1014
1015 break;
1016
1017 case LFT_REPLY_OBJECTSIZE:
1018 outoff = al->cache.objectSize;
1019
1020 dooff = 1;
1021
1022 break;
1023
1024 case LFT_ADAPTED_REPLY_SIZE_HEADERS:
1025 outint = al->http.clientReplySz.header;
1026 doint = 1;
1027 break;
1028
1029 /*case LFT_REPLY_SIZE_BODY: */
1030 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1031
1032 case LFT_CLIENT_IO_SIZE_TOTAL:
1033 outint = al->http.clientRequestSz.messageTotal() + al->http.clientReplySz.messageTotal();
1034 doint = 1;
1035 break;
1036 /*case LFT_SERVER_IO_SIZE_TOTAL: */
1037
1038 case LFT_TAG:
1039 if (al->request)
1040 out = al->request->tag.termedBuf();
1041
1042 quote = 1;
1043
1044 break;
1045
1046 case LFT_EXT_LOG:
1047 if (al->request)
1048 out = al->request->extacl_log.termedBuf();
1049
1050 quote = 1;
1051
1052 break;
1053
1054 case LFT_SEQUENCE_NUMBER:
1055 outoff = logSequenceNumber;
1056 dooff = 1;
1057 break;
1058
1059 #if USE_SSL
1060 case LFT_SSL_BUMP_MODE: {
1061 const Ssl::BumpMode mode = static_cast<Ssl::BumpMode>(al->ssl.bumpMode);
1062 // for Ssl::bumpEnd, Ssl::bumpMode() returns NULL and we log '-'
1063 out = Ssl::bumpMode(mode);
1064 break;
1065 }
1066
1067 case LFT_SSL_USER_CERT_SUBJECT:
1068 if (X509 *cert = al->cache.sslClientCert.get()) {
1069 if (X509_NAME *subject = X509_get_subject_name(cert)) {
1070 X509_NAME_oneline(subject, tmp, sizeof(tmp));
1071 out = tmp;
1072 }
1073 }
1074 break;
1075
1076 case LFT_SSL_USER_CERT_ISSUER:
1077 if (X509 *cert = al->cache.sslClientCert.get()) {
1078 if (X509_NAME *issuer = X509_get_issuer_name(cert)) {
1079 X509_NAME_oneline(issuer, tmp, sizeof(tmp));
1080 out = tmp;
1081 }
1082 }
1083 break;
1084 #endif
1085
1086 case LFT_NOTE:
1087 if (fmt->data.string) {
1088 #if USE_ADAPTATION
1089 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
1090 if (ah != NULL && ah->metaHeaders != NULL) {
1091 if (const char *meta = ah->metaHeaders->find(fmt->data.string))
1092 sb.append(meta);
1093 }
1094 #endif
1095 if (al->notes != NULL) {
1096 if (const char *note = al->notes->find(fmt->data.string)) {
1097 if (sb.size())
1098 sb.append(", ");
1099 sb.append(note);
1100 }
1101 }
1102 out = sb.termedBuf();
1103 quote = 1;
1104 } else {
1105 #if USE_ADAPTATION
1106 Adaptation::History::Pointer ah = al->request ? al->request->adaptHistory() : Adaptation::History::Pointer();
1107 if (ah != NULL && ah->metaHeaders != NULL && !ah->metaHeaders->empty())
1108 sb.append(ah->metaHeaders->toString());
1109 #endif
1110 if (al->notes != NULL && !al->notes->empty())
1111 sb.append(al->notes->toString());
1112
1113 out = sb.termedBuf();
1114 quote = 1;
1115 }
1116 break;
1117
1118 case LFT_CREDENTIALS:
1119 #if USE_AUTH
1120 if (al->request && al->request->auth_user_request != NULL)
1121 out = strOrNull(al->request->auth_user_request->credentialsStr());
1122 #endif
1123
1124 break;
1125
1126 case LFT_PERCENT:
1127 out = "%";
1128
1129 break;
1130 }
1131
1132 if (dooff) {
1133 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outoff);
1134 out = tmp;
1135
1136 } else if (doint) {
1137 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero && fmt->widthMin >= 0 ? fmt->widthMin : 0, outint);
1138 out = tmp;
1139 }
1140
1141 if (out && *out) {
1142 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1143 char *newout = NULL;
1144 int newfree = 0;
1145
1146 switch (fmt->quote) {
1147
1148 case LOG_QUOTE_NONE:
1149 newout = rfc1738_escape_unescaped(out);
1150 break;
1151
1152 case LOG_QUOTE_QUOTES: {
1153 size_t out_len = static_cast<size_t>(strlen(out)) * 2 + 1;
1154 if (out_len >= sizeof(tmp)) {
1155 newout = (char *)xmalloc(out_len);
1156 newfree = 1;
1157 } else
1158 newout = tmp;
1159 log_quoted_string(out, newout);
1160 }
1161 break;
1162
1163 case LOG_QUOTE_MIMEBLOB:
1164 newout = QuoteMimeBlob(out);
1165 newfree = 1;
1166 break;
1167
1168 case LOG_QUOTE_URL:
1169 newout = rfc1738_escape(out);
1170 break;
1171
1172 case LOG_QUOTE_RAW:
1173 break;
1174 }
1175
1176 if (newout) {
1177 if (dofree)
1178 safe_free(out);
1179
1180 out = newout;
1181
1182 dofree = newfree;
1183 }
1184 }
1185
1186 // enforce width limits if configured
1187 const bool haveMaxWidth = fmt->widthMax >=0 && !doint && !dooff && !fmt->divisor;
1188 if (haveMaxWidth || fmt->widthMin) {
1189 const int minWidth = fmt->widthMin >= 0 ?
1190 fmt->widthMin :0;
1191 const int maxWidth = haveMaxWidth ?
1192 fmt->widthMax : strlen(out);
1193
1194 if (fmt->left)
1195 mb.Printf("%-*.*s", minWidth, maxWidth, out);
1196 else
1197 mb.Printf("%*.*s", minWidth, maxWidth, out);
1198 } else
1199 mb.append(out, strlen(out));
1200 } else {
1201 mb.append("-", 1);
1202 }
1203
1204 if (fmt->space)
1205 mb.append(" ", 1);
1206
1207 sb.clean();
1208
1209 if (dofree)
1210 safe_free(out);
1211 }
1212 }