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