]> git.ipfire.org Git - thirdparty/squid.git/blob - src/access_log.cc
15e497e391cb0e606958d4df98ada72f1ac659bf
[thirdparty/squid.git] / src / access_log.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 46 Access Log
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35
36 #include "squid.h"
37 #include "AccessLogEntry.h"
38
39 // Store.h Required by configuration directives parsing/dumping only
40 #include "Store.h"
41
42 #include "acl/Checklist.h"
43
44 #include "hier_code.h"
45 #include "HttpReply.h"
46 #include "HttpRequest.h"
47 #include "MemBuf.h"
48 #include "SquidTime.h"
49 #include "CacheManager.h"
50
51 static void accessLogSquid(AccessLogEntry * al, Logfile * logfile);
52 static void accessLogCommon(AccessLogEntry * al, Logfile * logfile);
53 static void accessLogCustom(AccessLogEntry * al, customlog * log);
54 #if HEADERS_LOG
55 static Logfile *headerslog = NULL;
56 #endif
57
58 #if MULTICAST_MISS_STREAM
59 static int mcast_miss_fd = -1;
60
61 static struct sockaddr_in mcast_miss_to;
62 static void mcast_encode(unsigned int *, size_t, const unsigned int *);
63 #endif
64
65 const char *log_tags[] = {
66 "NONE",
67 "TCP_HIT",
68 "TCP_MISS",
69 "TCP_REFRESH_UNMODIFIED",
70 "TCP_REFRESH_FAIL",
71 "TCP_REFRESH_MODIFIED",
72 "TCP_CLIENT_REFRESH_MISS",
73 "TCP_IMS_HIT",
74 "TCP_SWAPFAIL_MISS",
75 "TCP_NEGATIVE_HIT",
76 "TCP_MEM_HIT",
77 "TCP_DENIED",
78 "TCP_DENIED_REPLY",
79 "TCP_OFFLINE_HIT",
80 #if LOG_TCP_REDIRECTS
81 "TCP_REDIRECT",
82 #endif
83 "UDP_HIT",
84 "UDP_MISS",
85 "UDP_DENIED",
86 "UDP_INVALID",
87 "UDP_MISS_NOFETCH",
88 "ICP_QUERY",
89 "LOG_TYPE_MAX"
90 };
91
92 #if FORW_VIA_DB
93
94 typedef struct {
95 hash_link hash;
96 int n;
97 } fvdb_entry;
98 static hash_table *via_table = NULL;
99 static hash_table *forw_table = NULL;
100 static void fvdbInit();
101 static void fvdbDumpTable(StoreEntry * e, hash_table * hash);
102 static void fvdbCount(hash_table * hash, const char *key);
103 static OBJH fvdbDumpVia;
104 static OBJH fvdbDumpForw;
105 static FREE fvdbFreeEntry;
106 static void fvdbClear(void);
107 static void fvdbRegisterWithCacheManager();
108 #endif
109
110 int LogfileStatus = LOG_DISABLE;
111
112 #if USE_ADAPTATION
113 bool alLogformatHasAdaptToken = false;
114 #endif
115
116 #if ICAP_CLIENT
117 bool alLogformatHasIcapToken = false;
118 #endif
119
120 #define LOG_BUF_SZ (MAX_URL<<2)
121
122 static const char c2x[] =
123 "000102030405060708090a0b0c0d0e0f"
124 "101112131415161718191a1b1c1d1e1f"
125 "202122232425262728292a2b2c2d2e2f"
126 "303132333435363738393a3b3c3d3e3f"
127 "404142434445464748494a4b4c4d4e4f"
128 "505152535455565758595a5b5c5d5e5f"
129 "606162636465666768696a6b6c6d6e6f"
130 "707172737475767778797a7b7c7d7e7f"
131 "808182838485868788898a8b8c8d8e8f"
132 "909192939495969798999a9b9c9d9e9f"
133 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
134 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
135 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
136 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
137 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
138 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
139
140 /* log_quote -- URL-style encoding on MIME headers. */
141
142 char *
143 log_quote(const char *header)
144 {
145 int c;
146 int i;
147 char *buf;
148 char *buf_cursor;
149
150 if (header == NULL) {
151 buf = static_cast<char *>(xcalloc(1, 1));
152 *buf = '\0';
153 return buf;
154 }
155
156 buf = static_cast<char *>(xcalloc(1, (strlen(header) * 3) + 1));
157 buf_cursor = buf;
158 /*
159 * We escape: \x00-\x1F"#%;<>?{}|\\\\^~`\[\]\x7F-\xFF
160 * which is the default escape list for the CPAN Perl5 URI module
161 * modulo the inclusion of space (x40) to make the raw logs a bit
162 * more readable.
163 */
164
165 while ((c = *(const unsigned char *) header++) != '\0') {
166 #if !OLD_LOG_MIME
167
168 if (c == '\r') {
169 *buf_cursor++ = '\\';
170 *buf_cursor++ = 'r';
171 } else if (c == '\n') {
172 *buf_cursor++ = '\\';
173 *buf_cursor++ = 'n';
174 } else
175 #endif
176 if (c <= 0x1F
177 || c >= 0x7F
178 || c == '%'
179 #if OLD_LOG_MIME
180 || c == '"'
181 || c == '#'
182 || c == ';'
183 || c == '<'
184 || c == '>'
185 || c == '?'
186 || c == '{'
187 || c == '}'
188 || c == '|'
189 || c == '\\'
190 || c == '^'
191 || c == '~'
192 || c == '`'
193 #endif
194 || c == '['
195 || c == ']') {
196 *buf_cursor++ = '%';
197 i = c * 2;
198 *buf_cursor++ = c2x[i];
199 *buf_cursor++ = c2x[i + 1];
200 #if !OLD_LOG_MIME
201
202 } else if (c == '\\') {
203 *buf_cursor++ = '\\';
204 *buf_cursor++ = '\\';
205 #endif
206
207 } else {
208 *buf_cursor++ = (char) c;
209 }
210 }
211
212 *buf_cursor = '\0';
213 return buf;
214 }
215
216 static char *
217 username_quote(const char *header)
218 /* copy of log_quote. Bugs there will be found here */
219 {
220 int c;
221 int i;
222 char *buf;
223 char *buf_cursor;
224
225 if (header == NULL) {
226 buf = static_cast<char *>(xcalloc(1, 1));
227 *buf = '\0';
228 return buf;
229 }
230
231 buf = static_cast<char *>(xcalloc(1, (strlen(header) * 3) + 1));
232 buf_cursor = buf;
233 /*
234 * We escape: space \x00-\x1F and space (0x40) and \x7F-\xFF
235 * to prevent garbage in the logs. CR and LF are also there just in case.
236 */
237
238 while ((c = *(const unsigned char *) header++) != '\0') {
239 if (c == '\r') {
240 *buf_cursor++ = '\\';
241 *buf_cursor++ = 'r';
242 } else if (c == '\n') {
243 *buf_cursor++ = '\\';
244 *buf_cursor++ = 'n';
245 } else if (c <= 0x1F
246 || c >= 0x7F
247 || c == '%'
248 || c == ' ') {
249 *buf_cursor++ = '%';
250 i = c * 2;
251 *buf_cursor++ = c2x[i];
252 *buf_cursor++ = c2x[i + 1];
253 } else {
254 *buf_cursor++ = (char) c;
255 }
256 }
257
258 *buf_cursor = '\0';
259 return buf;
260 }
261
262 static char *
263 accessLogFormatName(const char *name)
264 {
265 if (NULL == name)
266 return NULL;
267
268 if (name[0] == '\0')
269 return NULL;
270
271 return username_quote(name);
272 }
273
274 static char *
275 log_quoted_string(const char *str)
276 {
277 char *out = (char *)xmalloc(strlen(str) * 2 + 1);
278 char *p = out;
279
280 while (*str) {
281 int l = strcspn(str, "\"\\\r\n\t");
282 memcpy(p, str, l);
283 str += l;
284 p += l;
285
286 switch (*str) {
287
288 case '\0':
289 break;
290
291 case '\r':
292 *p++ = '\\';
293 *p++ = 'r';
294 str++;
295 break;
296
297 case '\n':
298 *p++ = '\\';
299 *p++ = 'n';
300 str++;
301 break;
302
303 case '\t':
304 *p++ = '\\';
305 *p++ = 't';
306 str++;
307 break;
308
309 default:
310 *p++ = '\\';
311 *p++ = *str;
312 str++;
313 break;
314 }
315 }
316
317 *p++ = '\0';
318 return out;
319 }
320
321 /*
322 * Bytecodes for the configureable logformat stuff
323 */
324 typedef enum {
325 LFT_NONE, /* dummy */
326 LFT_STRING,
327
328 LFT_CLIENT_IP_ADDRESS,
329 LFT_CLIENT_FQDN,
330 LFT_CLIENT_PORT,
331
332 /*LFT_SERVER_IP_ADDRESS, */
333 LFT_SERVER_IP_OR_PEER_NAME,
334 /*LFT_SERVER_PORT, */
335
336 LFT_LOCAL_IP,
337 LFT_LOCAL_PORT,
338 /*LFT_LOCAL_NAME, */
339
340 LFT_TIME_SECONDS_SINCE_EPOCH,
341 LFT_TIME_SUBSECOND,
342 LFT_TIME_LOCALTIME,
343 LFT_TIME_GMT,
344 LFT_TIME_TO_HANDLE_REQUEST,
345
346 LFT_PEER_RESPONSE_TIME,
347 LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME,
348 LFT_DNS_WAIT_TIME,
349
350 LFT_REQUEST_HEADER,
351 LFT_REQUEST_HEADER_ELEM,
352 LFT_REQUEST_ALL_HEADERS,
353
354 LFT_REPLY_HEADER,
355 LFT_REPLY_HEADER_ELEM,
356 LFT_REPLY_ALL_HEADERS,
357
358 LFT_USER_NAME,
359 LFT_USER_LOGIN,
360 LFT_USER_IDENT,
361 /*LFT_USER_REALM, */
362 /*LFT_USER_SCHEME, */
363 LFT_USER_EXTERNAL,
364
365 LFT_HTTP_SENT_STATUS_CODE_OLD_30,
366 LFT_HTTP_SENT_STATUS_CODE,
367 LFT_HTTP_RECEIVED_STATUS_CODE,
368 /*LFT_HTTP_STATUS, */
369
370 LFT_SQUID_STATUS,
371 /*LFT_SQUID_ERROR, */
372 LFT_SQUID_HIERARCHY,
373
374 LFT_MIME_TYPE,
375
376 LFT_REQUEST_METHOD,
377 LFT_REQUEST_URI,
378 LFT_REQUEST_URLPATH,
379 /*LFT_REQUEST_QUERY, * // * this is not needed. see strip_query_terms */
380 LFT_REQUEST_VERSION,
381
382 LFT_REQUEST_SIZE_TOTAL,
383 /*LFT_REQUEST_SIZE_LINE, */
384 LFT_REQUEST_SIZE_HEADERS,
385 /*LFT_REQUEST_SIZE_BODY, */
386 /*LFT_REQUEST_SIZE_BODY_NO_TE, */
387
388 LFT_REPLY_SIZE_TOTAL,
389 LFT_REPLY_HIGHOFFSET,
390 LFT_REPLY_OBJECTSIZE,
391 /*LFT_REPLY_SIZE_LINE, */
392 LFT_REPLY_SIZE_HEADERS,
393 /*LFT_REPLY_SIZE_BODY, */
394 /*LFT_REPLY_SIZE_BODY_NO_TE, */
395
396 LFT_TAG,
397 LFT_IO_SIZE_TOTAL,
398 LFT_EXT_LOG,
399
400 #if USE_ADAPTATION
401 LTF_ADAPTATION_SUM_XACT_TIMES,
402 LTF_ADAPTATION_ALL_XACT_TIMES,
403 #endif
404
405 #if ICAP_CLIENT
406
407 LFT_ICAP_TOTAL_TIME,
408 LFT_ICAP_LAST_MATCHED_HEADER,
409 LFT_ICAP_LAST_MATCHED_HEADER_ELEM,
410 LFT_ICAP_LAST_MATCHED_ALL_HEADERS,
411
412 LFT_ICAP_ADDR,
413 LFT_ICAP_SERV_NAME,
414 LFT_ICAP_REQUEST_URI,
415 LFT_ICAP_REQUEST_METHOD,
416 LFT_ICAP_BYTES_SENT,
417 LFT_ICAP_BYTES_READ,
418
419 LFT_ICAP_REQ_HEADER,
420 LFT_ICAP_REQ_HEADER_ELEM,
421 LFT_ICAP_REQ_ALL_HEADERS,
422
423 LFT_ICAP_REP_HEADER,
424 LFT_ICAP_REP_HEADER_ELEM,
425 LFT_ICAP_REP_ALL_HEADERS,
426
427 LFT_ICAP_TR_RESPONSE_TIME,
428 LFT_ICAP_IO_TIME,
429 LFT_ICAP_OUTCOME,
430 LFT_ICAP_STATUS_CODE,
431 #endif
432
433 LFT_PERCENT /* special string cases for escaped chars */
434 } logformat_bcode_t;
435
436 enum log_quote {
437 LOG_QUOTE_NONE = 0,
438 LOG_QUOTE_QUOTES,
439 LOG_QUOTE_BRAKETS,
440 LOG_QUOTE_URL,
441 LOG_QUOTE_RAW
442 };
443
444 /* FIXME: public class so we can pre-define its type. */
445 class logformat_token
446 {
447 public:
448 logformat_bcode_t type;
449 union {
450 char *string;
451
452 struct {
453 char *header;
454 char *element;
455 char separator;
456 } header;
457 char *timespec;
458 } data;
459 unsigned char width;
460 unsigned char precision;
461 enum log_quote quote;
462 unsigned int left:1;
463 unsigned int space:1;
464 unsigned int zero:1;
465 int divisor;
466 logformat_token *next; /* todo: move from linked list to array */
467 };
468
469 struct logformat_token_table_entry {
470 const char *config;
471 logformat_bcode_t token_type;
472 int options;
473 };
474
475 struct logformat_token_table_entry logformat_token_table[] = {
476
477 {">a", LFT_CLIENT_IP_ADDRESS},
478
479 { ">p", LFT_CLIENT_PORT},
480 {">A", LFT_CLIENT_FQDN},
481
482 /*{ "<a", LFT_SERVER_IP_ADDRESS }, */
483 /*{ "<p", LFT_SERVER_PORT }, */
484 {"<A", LFT_SERVER_IP_OR_PEER_NAME},
485
486 /* {"oa", LFT_OUTGOING_IP}, */
487 /* {"ot", LFT_OUTGOING_TOS}, */
488
489 {"la", LFT_LOCAL_IP},
490 {"lp", LFT_LOCAL_PORT},
491 /*{ "lA", LFT_LOCAL_NAME }, */
492
493 {"ts", LFT_TIME_SECONDS_SINCE_EPOCH},
494 {"tu", LFT_TIME_SUBSECOND},
495 {"tl", LFT_TIME_LOCALTIME},
496 {"tg", LFT_TIME_GMT},
497 {"tr", LFT_TIME_TO_HANDLE_REQUEST},
498
499 {"<pt", LFT_PEER_RESPONSE_TIME},
500 {"<tt", LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME},
501 {"dt", LFT_DNS_WAIT_TIME},
502
503 {">h", LFT_REQUEST_HEADER},
504 {">h", LFT_REQUEST_ALL_HEADERS},
505 {"<h", LFT_REPLY_HEADER},
506 {"<h", LFT_REPLY_ALL_HEADERS},
507
508 {"un", LFT_USER_NAME},
509 {"ul", LFT_USER_LOGIN},
510 /*{ "ur", LFT_USER_REALM }, */
511 /*{ "us", LFT_USER_SCHEME }, */
512 {"ui", LFT_USER_IDENT},
513 {"ue", LFT_USER_EXTERNAL},
514
515 {"Hs", LFT_HTTP_SENT_STATUS_CODE_OLD_30},
516 {">Hs", LFT_HTTP_SENT_STATUS_CODE},
517 {"<Hs", LFT_HTTP_RECEIVED_STATUS_CODE},
518 /*{ "Ht", LFT_HTTP_STATUS }, */
519
520 {"Ss", LFT_SQUID_STATUS},
521 /*{ "Se", LFT_SQUID_ERROR }, */
522 {"Sh", LFT_SQUID_HIERARCHY},
523
524 {"mt", LFT_MIME_TYPE},
525
526 {"rm", LFT_REQUEST_METHOD},
527 {"ru", LFT_REQUEST_URI}, /* doesn't include the query-string */
528 {"rp", LFT_REQUEST_URLPATH}, /* doesn't include the host */
529 /* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */
530 {">v", LFT_REQUEST_VERSION},
531 {"rv", LFT_REQUEST_VERSION},
532
533 { ">st", LFT_REQUEST_SIZE_TOTAL },
534 /*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */
535 { ">sh", LFT_REQUEST_SIZE_HEADERS },
536 /*{ ">sb", LFT_REQUEST_SIZE_BODY }, */
537 /*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */
538
539 {"<st", LFT_REPLY_SIZE_TOTAL},
540 {"<sH", LFT_REPLY_HIGHOFFSET},
541 {"<sS", LFT_REPLY_OBJECTSIZE},
542 /*{ "<sl", LFT_REPLY_SIZE_LINE }, * / / * the reply line (protocol, code, text) */
543 { "<sh", LFT_REPLY_SIZE_HEADERS },
544 /*{ "<sb", LFT_REPLY_SIZE_BODY }, */
545 /*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */
546
547 {"et", LFT_TAG},
548 {"st", LFT_IO_SIZE_TOTAL},
549 {"ea", LFT_EXT_LOG},
550
551 {"%", LFT_PERCENT},
552
553 #if USE_ADAPTATION
554 {"adapt::all_trs", LTF_ADAPTATION_ALL_XACT_TIMES},
555 {"adapt::sum_trs", LTF_ADAPTATION_SUM_XACT_TIMES},
556 #endif
557
558 #if ICAP_CLIENT
559 {"icap::tt", LFT_ICAP_TOTAL_TIME},
560 {"icap::<last_h", LFT_ICAP_LAST_MATCHED_HEADER},
561
562 {"icap::<A", LFT_ICAP_ADDR},
563 {"icap::<service_name", LFT_ICAP_SERV_NAME},
564 {"icap::ru", LFT_ICAP_REQUEST_URI},
565 {"icap::rm", LFT_ICAP_REQUEST_METHOD},
566 {"icap::>st", LFT_ICAP_BYTES_SENT},
567 {"icap::<st", LFT_ICAP_BYTES_READ},
568
569 {"icap::>h", LFT_ICAP_REQ_HEADER},
570 {"icap::<h", LFT_ICAP_REP_HEADER},
571
572 {"icap::tr", LFT_ICAP_TR_RESPONSE_TIME},
573 {"icap::tio", LFT_ICAP_IO_TIME},
574 {"icap::to", LFT_ICAP_OUTCOME},
575 {"icap::Hs", LFT_ICAP_STATUS_CODE},
576 #endif
577
578 {NULL, LFT_NONE} /* this must be last */
579 };
580
581 static void
582 accessLogCustom(AccessLogEntry * al, customlog * log)
583 {
584 logformat *lf;
585 Logfile *logfile;
586 logformat_token *fmt;
587 static MemBuf mb;
588 char tmp[1024];
589 String sb;
590
591 mb.reset();
592
593 lf = log->logFormat;
594 logfile = log->logfile;
595
596 for (fmt = lf->format; fmt != NULL; fmt = fmt->next) { /* for each token */
597 const char *out = NULL;
598 int quote = 0;
599 long int outint = 0;
600 int doint = 0;
601 int dofree = 0;
602 int64_t outoff = 0;
603 int dooff = 0;
604
605 switch (fmt->type) {
606
607 case LFT_NONE:
608 out = "";
609 break;
610
611 case LFT_STRING:
612 out = fmt->data.string;
613 break;
614
615 case LFT_CLIENT_IP_ADDRESS:
616 if (al->cache.caddr.IsNoAddr()) // e.g., ICAP OPTIONS lack client
617 out = "-";
618 else
619 out = al->cache.caddr.NtoA(tmp,1024);
620 break;
621
622 case LFT_CLIENT_FQDN:
623 if (al->cache.caddr.IsAnyAddr()) // e.g., ICAP OPTIONS lack client
624 out = "-";
625 else
626 out = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
627 if (!out) {
628 out = al->cache.caddr.NtoA(tmp,1024);
629 }
630
631 break;
632
633 case LFT_CLIENT_PORT:
634 if (al->request) {
635 outint = al->request->client_addr.GetPort();
636 doint = 1;
637 }
638 break;
639
640 /* case LFT_SERVER_IP_ADDRESS: */
641
642 case LFT_SERVER_IP_OR_PEER_NAME:
643 out = al->hier.host;
644
645 break;
646
647 /* case LFT_SERVER_PORT: */
648
649 case LFT_LOCAL_IP:
650 if (al->request) {
651 out = al->request->my_addr.NtoA(tmp,1024);
652 }
653
654 break;
655
656 case LFT_LOCAL_PORT:
657 if (al->request) {
658 outint = al->request->my_addr.GetPort();
659 doint = 1;
660 }
661
662 break;
663
664 case LFT_TIME_SECONDS_SINCE_EPOCH:
665 // some platforms store time in 32-bit, some 64-bit...
666 outoff = static_cast<int64_t>(current_time.tv_sec);
667 dooff = 1;
668 break;
669
670 case LFT_TIME_SUBSECOND:
671 outint = current_time.tv_usec / fmt->divisor;
672 doint = 1;
673 break;
674
675
676 case LFT_TIME_LOCALTIME:
677
678 case LFT_TIME_GMT: {
679 const char *spec;
680
681 struct tm *t;
682 spec = fmt->data.timespec;
683
684 if (fmt->type == LFT_TIME_LOCALTIME) {
685 if (!spec)
686 spec = "%d/%b/%Y:%H:%M:%S %z";
687 t = localtime(&squid_curtime);
688 } else {
689 if (!spec)
690 spec = "%d/%b/%Y:%H:%M:%S";
691
692 t = gmtime(&squid_curtime);
693 }
694
695 strftime(tmp, sizeof(tmp), spec, t);
696
697 out = tmp;
698 }
699
700 break;
701
702 case LFT_TIME_TO_HANDLE_REQUEST:
703 outint = al->cache.msec;
704 doint = 1;
705 break;
706
707 case LFT_PEER_RESPONSE_TIME:
708 if (al->hier.peer_response_time < 0) {
709 out = "-";
710 } else {
711 outoff = al->hier.peer_response_time;
712 dooff = 1;
713 }
714 break;
715
716 case LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME:
717 if (al->hier.total_response_time < 0) {
718 out = "-";
719 } else {
720 outoff = al->hier.total_response_time;
721 dooff = 1;
722 }
723 break;
724
725 case LFT_DNS_WAIT_TIME:
726 if (al->request && al->request->dnsWait >= 0) {
727 outint = al->request->dnsWait;
728 doint = 1;
729 }
730 break;
731
732 case LFT_REQUEST_HEADER:
733
734 if (al->request)
735 sb = al->request->header.getByName(fmt->data.header.header);
736
737 out = sb.termedBuf();
738
739 quote = 1;
740
741 break;
742
743 case LFT_REPLY_HEADER:
744 if (al->reply)
745 sb = al->reply->header.getByName(fmt->data.header.header);
746
747 out = sb.termedBuf();
748
749 quote = 1;
750
751 break;
752
753 #if USE_ADAPTATION
754 case LTF_ADAPTATION_SUM_XACT_TIMES:
755 if (al->request) {
756 Adaptation::History::Pointer ah = al->request->adaptHistory();
757 if (ah != NULL)
758 ah->sumLogString(fmt->data.string, sb);
759 out = sb.termedBuf();
760 }
761 break;
762
763 case LTF_ADAPTATION_ALL_XACT_TIMES:
764 if (al->request) {
765 Adaptation::History::Pointer ah = al->request->adaptHistory();
766 if (ah != NULL)
767 ah->allLogString(fmt->data.string, sb);
768 out = sb.termedBuf();
769 }
770 break;
771 #endif
772
773 #if ICAP_CLIENT
774 case LFT_ICAP_LAST_MATCHED_HEADER:
775 if (al->request) {
776 Adaptation::Icap::History::Pointer ih = al->request->icapHistory();
777 if (ih != NULL)
778 sb = ih->mergeOfIcapHeaders.getByName(fmt->data.header.header);
779 }
780
781 out = sb.termedBuf();
782
783 quote = 1;
784
785 break;
786
787 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM:
788 if (al->request) {
789 Adaptation::Icap::History::Pointer ih = al->request->icapHistory();
790 if (ih != NULL)
791 sb = ih->mergeOfIcapHeaders.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
792 }
793
794 out = sb.termedBuf();
795
796 quote = 1;
797
798 break;
799
800 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS:
801 out = al->headers.icap;
802
803 quote = 1;
804
805 break;
806
807 case LFT_ICAP_ADDR:
808 if (!out)
809 out = al->icap.hostAddr.NtoA(tmp,1024);
810 break;
811
812 case LFT_ICAP_SERV_NAME:
813 out = al->icap.serviceName.termedBuf();
814 break;
815
816 case LFT_ICAP_REQUEST_URI:
817 out = al->icap.reqUri.termedBuf();
818 break;
819
820 case LFT_ICAP_REQUEST_METHOD:
821 out = Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod);
822 break;
823
824 case LFT_ICAP_BYTES_SENT:
825 outint = al->icap.bytesSent;
826 doint = 1;
827 break;
828
829 case LFT_ICAP_BYTES_READ:
830 outint = al->icap.bytesRead;
831 doint = 1;
832 break;
833
834 case LFT_ICAP_REQ_HEADER:
835 if (NULL != al->icap.request) {
836 sb = al->icap.request->header.getByName(fmt->data.header.header);
837 out = sb.termedBuf();
838 quote = 1;
839 }
840 break;
841
842 case LFT_ICAP_REQ_HEADER_ELEM:
843 if (al->request)
844 sb = al->icap.request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
845
846 out = sb.termedBuf();
847
848 quote = 1;
849
850 break;
851
852 case LFT_ICAP_REQ_ALL_HEADERS:
853 if (al->icap.request) {
854 HttpHeaderPos pos = HttpHeaderInitPos;
855 while (const HttpHeaderEntry *e = al->icap.request->header.getEntry(&pos)) {
856 sb.append(e->name);
857 sb.append(": ");
858 sb.append(e->value);
859 sb.append("\r\n");
860 }
861 out = sb.termedBuf();
862 quote = 1;
863 }
864 break;
865
866 case LFT_ICAP_REP_HEADER:
867 if (NULL != al->icap.reply) {
868 sb = al->icap.reply->header.getByName(fmt->data.header.header);
869 out = sb.termedBuf();
870 quote = 1;
871 }
872 break;
873
874 case LFT_ICAP_REP_HEADER_ELEM:
875 if (NULL != al->icap.reply)
876 sb = al->icap.reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
877
878 out = sb.termedBuf();
879
880 quote = 1;
881
882 break;
883
884 case LFT_ICAP_REP_ALL_HEADERS:
885 if (al->icap.reply) {
886 HttpHeaderPos pos = HttpHeaderInitPos;
887 while (const HttpHeaderEntry *e = al->icap.reply->header.getEntry(&pos)) {
888 sb.append(e->name);
889 sb.append(": ");
890 sb.append(e->value);
891 sb.append("\r\n");
892 }
893 out = sb.termedBuf();
894 quote = 1;
895 }
896 break;
897
898 case LFT_ICAP_TR_RESPONSE_TIME:
899 outint = al->icap.trTime;
900 doint = 1;
901 break;
902
903 case LFT_ICAP_IO_TIME:
904 outint = al->icap.ioTime;
905 doint = 1;
906 break;
907
908 case LFT_ICAP_STATUS_CODE:
909 outint = al->icap.resStatus;
910 doint = 1;
911 break;
912
913 case LFT_ICAP_OUTCOME:
914 out = al->icap.outcome;
915 break;
916
917 case LFT_ICAP_TOTAL_TIME:
918 outint = al->icap.processingTime;
919 doint = 1;
920 break;
921 #endif
922 case LFT_REQUEST_HEADER_ELEM:
923 if (al->request)
924 sb = al->request->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
925
926 out = sb.termedBuf();
927
928 quote = 1;
929
930 break;
931
932 case LFT_REPLY_HEADER_ELEM:
933 if (al->reply)
934 sb = al->reply->header.getByNameListMember(fmt->data.header.header, fmt->data.header.element, fmt->data.header.separator);
935
936 out = sb.termedBuf();
937
938 quote = 1;
939
940 break;
941
942 case LFT_REQUEST_ALL_HEADERS:
943 out = al->headers.request;
944
945 quote = 1;
946
947 break;
948
949 case LFT_REPLY_ALL_HEADERS:
950 out = al->headers.reply;
951
952 quote = 1;
953
954 break;
955
956 case LFT_USER_NAME:
957 out = accessLogFormatName(al->cache.authuser);
958
959 if (!out)
960 out = accessLogFormatName(al->cache.extuser);
961
962 #if USE_SSL
963
964 if (!out)
965 out = accessLogFormatName(al->cache.ssluser);
966
967 #endif
968
969 if (!out)
970 out = accessLogFormatName(al->cache.rfc931);
971
972 dofree = 1;
973
974 break;
975
976 case LFT_USER_LOGIN:
977 out = accessLogFormatName(al->cache.authuser);
978
979 dofree = 1;
980
981 break;
982
983 case LFT_USER_IDENT:
984 out = accessLogFormatName(al->cache.rfc931);
985
986 dofree = 1;
987
988 break;
989
990 case LFT_USER_EXTERNAL:
991 out = accessLogFormatName(al->cache.extuser);
992
993 dofree = 1;
994
995 break;
996
997 /* case LFT_USER_REALM: */
998 /* case LFT_USER_SCHEME: */
999
1000 // the fmt->type can not be LFT_HTTP_SENT_STATUS_CODE_OLD_30
1001 // but compiler complains if ommited
1002 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
1003 case LFT_HTTP_SENT_STATUS_CODE:
1004 outint = al->http.code;
1005
1006 doint = 1;
1007
1008 break;
1009
1010 case LFT_HTTP_RECEIVED_STATUS_CODE:
1011 if(al->hier.peer_reply_status == HTTP_STATUS_NONE) {
1012 out = "-";
1013 }
1014 else {
1015 outint = al->hier.peer_reply_status;
1016 doint = 1;
1017 }
1018 break;
1019 /* case LFT_HTTP_STATUS:
1020 * out = statusline->text;
1021 * quote = 1;
1022 * break;
1023 */
1024
1025 case LFT_SQUID_STATUS:
1026 out = log_tags[al->cache.code];
1027
1028 break;
1029
1030 /* case LFT_SQUID_ERROR: */
1031
1032 case LFT_SQUID_HIERARCHY:
1033 if (al->hier.ping.timedout)
1034 mb.append("TIMEOUT_", 8);
1035
1036 out = hier_code_str[al->hier.code];
1037
1038 break;
1039
1040 case LFT_MIME_TYPE:
1041 out = al->http.content_type;
1042
1043 break;
1044
1045 case LFT_REQUEST_METHOD:
1046 out = al->_private.method_str;
1047
1048 break;
1049
1050 case LFT_REQUEST_URI:
1051 out = al->url;
1052
1053 break;
1054
1055 case LFT_REQUEST_URLPATH:
1056 if (al->request) {
1057 out = al->request->urlpath.termedBuf();
1058 quote = 1;
1059 }
1060 break;
1061
1062 case LFT_REQUEST_VERSION:
1063 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
1064 out = tmp;
1065 break;
1066
1067 case LFT_REQUEST_SIZE_TOTAL:
1068 outoff = al->cache.requestSize;
1069 dooff = 1;
1070 break;
1071
1072 /*case LFT_REQUEST_SIZE_LINE: */
1073 case LFT_REQUEST_SIZE_HEADERS:
1074 outoff = al->cache.requestHeadersSize;
1075 dooff =1;
1076 break;
1077 /*case LFT_REQUEST_SIZE_BODY: */
1078 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1079
1080 case LFT_REPLY_SIZE_TOTAL:
1081 outoff = al->cache.replySize;
1082 dooff = 1;
1083 break;
1084
1085 case LFT_REPLY_HIGHOFFSET:
1086 outoff = al->cache.highOffset;
1087
1088 dooff = 1;
1089
1090 break;
1091
1092 case LFT_REPLY_OBJECTSIZE:
1093 outoff = al->cache.objectSize;
1094
1095 dooff = 1;
1096
1097 break;
1098
1099 /*case LFT_REPLY_SIZE_LINE: */
1100 case LFT_REPLY_SIZE_HEADERS:
1101 outint = al->cache.replyHeadersSize;
1102 doint = 1;
1103 /*case LFT_REPLY_SIZE_BODY: */
1104 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1105
1106 case LFT_TAG:
1107 if (al->request)
1108 out = al->request->tag.termedBuf();
1109
1110 quote = 1;
1111
1112 break;
1113
1114 case LFT_IO_SIZE_TOTAL:
1115 outint = al->cache.requestSize + al->cache.replySize;
1116 doint = 1;
1117 break;
1118
1119 case LFT_EXT_LOG:
1120 if (al->request)
1121 out = al->request->extacl_log.termedBuf();
1122
1123 quote = 1;
1124
1125 break;
1126
1127 case LFT_PERCENT:
1128 out = "%";
1129
1130 break;
1131 }
1132
1133 if (dooff) {
1134 snprintf(tmp, sizeof(tmp), "%0*" PRId64, fmt->zero ? (int) fmt->width : 0, outoff);
1135 out = tmp;
1136
1137 } else if (doint) {
1138 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 0, outint);
1139 out = tmp;
1140 }
1141
1142 if (out && *out) {
1143 if (quote || fmt->quote != LOG_QUOTE_NONE) {
1144 char *newout = NULL;
1145 int newfree = 0;
1146
1147 switch (fmt->quote) {
1148
1149 case LOG_QUOTE_NONE:
1150 newout = rfc1738_escape_unescaped(out);
1151 break;
1152
1153 case LOG_QUOTE_QUOTES:
1154 newout = log_quoted_string(out);
1155 newfree = 1;
1156 break;
1157
1158 case LOG_QUOTE_BRAKETS:
1159 newout = log_quote(out);
1160 newfree = 1;
1161 break;
1162
1163 case LOG_QUOTE_URL:
1164 newout = rfc1738_escape(out);
1165 break;
1166
1167 case LOG_QUOTE_RAW:
1168 break;
1169 }
1170
1171 if (newout) {
1172 if (dofree)
1173 safe_free(out);
1174
1175 out = newout;
1176
1177 dofree = newfree;
1178 }
1179 }
1180
1181 if (fmt->width) {
1182 if (fmt->left)
1183 mb.Printf("%-*s", (int) fmt->width, out);
1184 else
1185 mb.Printf("%*s", (int) fmt->width, out);
1186 } else
1187 mb.append(out, strlen(out));
1188 } else {
1189 mb.append("-", 1);
1190 }
1191
1192 if (fmt->space)
1193 mb.append(" ", 1);
1194
1195 sb.clean();
1196
1197 if (dofree)
1198 safe_free(out);
1199 }
1200
1201 logfilePrintf(logfile, "%s\n", mb.buf);
1202 }
1203
1204 /* parses a single token. Returns the token length in characters,
1205 * and fills in the lt item with the token information.
1206 * def is for sure null-terminated
1207 */
1208 static int
1209 accessLogGetNewLogFormatToken(logformat_token * lt, char *def, enum log_quote *quote)
1210 {
1211 char *cur = def;
1212
1213 struct logformat_token_table_entry *lte;
1214 int l;
1215
1216 memset(lt, 0, sizeof(*lt));
1217 l = strcspn(cur, "%");
1218
1219 if (l > 0) {
1220 char *cp;
1221 /* it's a string for sure, until \0 or the next % */
1222 cp = (char *)xmalloc(l + 1);
1223 xstrncpy(cp, cur, l + 1);
1224 lt->type = LFT_STRING;
1225 lt->data.string = cp;
1226
1227 while (l > 0) {
1228 switch (*cur) {
1229
1230 case '"':
1231
1232 if (*quote == LOG_QUOTE_NONE)
1233 *quote = LOG_QUOTE_QUOTES;
1234 else if (*quote == LOG_QUOTE_QUOTES)
1235 *quote = LOG_QUOTE_NONE;
1236
1237 break;
1238
1239 case '[':
1240 if (*quote == LOG_QUOTE_NONE)
1241 *quote = LOG_QUOTE_BRAKETS;
1242
1243 break;
1244
1245 case ']':
1246 if (*quote == LOG_QUOTE_BRAKETS)
1247 *quote = LOG_QUOTE_NONE;
1248
1249 break;
1250 }
1251
1252 cur++;
1253 l--;
1254 }
1255
1256 goto done;
1257 }
1258
1259 if (!*cur)
1260 goto done;
1261
1262 cur++;
1263
1264 switch (*cur) {
1265
1266 case '"':
1267 lt->quote = LOG_QUOTE_QUOTES;
1268 cur++;
1269 break;
1270
1271 case '\'':
1272 lt->quote = LOG_QUOTE_RAW;
1273 cur++;
1274 break;
1275
1276 case '[':
1277 lt->quote = LOG_QUOTE_BRAKETS;
1278 cur++;
1279 break;
1280
1281 case '#':
1282 lt->quote = LOG_QUOTE_URL;
1283 cur++;
1284 break;
1285
1286 default:
1287 lt->quote = *quote;
1288 break;
1289 }
1290
1291 if (*cur == '-') {
1292 lt->left = 1;
1293 cur++;
1294 }
1295
1296 if (*cur == '0') {
1297 lt->zero = 1;
1298 cur++;
1299 }
1300
1301 if (xisdigit(*cur))
1302 lt->width = strtol(cur, &cur, 10);
1303
1304 if (*cur == '.')
1305 lt->precision = strtol(cur + 1, &cur, 10);
1306
1307 if (*cur == '{') {
1308 char *cp;
1309 cur++;
1310 l = strcspn(cur, "}");
1311 cp = (char *)xmalloc(l + 1);
1312 xstrncpy(cp, cur, l + 1);
1313 lt->data.string = cp;
1314 cur += l;
1315
1316 if (*cur == '}')
1317 cur++;
1318 }
1319
1320 // For upward compatibility, assume "http::" prefix as default prefix
1321 // for all log access formating codes, except those starting
1322 // from "icap::", "adapt::" and "%"
1323 if (strncmp(cur,"http::", 6) == 0 &&
1324 strncmp(cur+6, "icap::", 6) != 0 &&
1325 strncmp(cur+6, "adapt::", 12) != 0 && *(cur+6) != '%' ) {
1326 cur += 6;
1327 }
1328
1329 lt->type = LFT_NONE;
1330
1331 for (lte = logformat_token_table; lte->config != NULL; lte++) {
1332 if (strncmp(lte->config, cur, strlen(lte->config)) == 0) {
1333 lt->type = lte->token_type;
1334 cur += strlen(lte->config);
1335 break;
1336 }
1337 }
1338
1339 if (lt->type == LFT_NONE) {
1340 fatalf("Can't parse configuration token: '%s'\n",
1341 def);
1342 }
1343
1344 if (*cur == ' ') {
1345 lt->space = 1;
1346 cur++;
1347 }
1348
1349 done:
1350
1351 switch (lt->type) {
1352
1353 #if ICAP_CLIENT
1354 case LFT_ICAP_LAST_MATCHED_HEADER:
1355
1356 case LFT_ICAP_REQ_HEADER:
1357
1358 case LFT_ICAP_REP_HEADER:
1359 #endif
1360
1361 case LFT_REQUEST_HEADER:
1362
1363 case LFT_REPLY_HEADER:
1364
1365 if (lt->data.string) {
1366 char *header = lt->data.string;
1367 char *cp = strchr(header, ':');
1368
1369 if (cp) {
1370 *cp++ = '\0';
1371
1372 if (*cp == ',' || *cp == ';' || *cp == ':')
1373 lt->data.header.separator = *cp++;
1374 else
1375 lt->data.header.separator = ',';
1376
1377 lt->data.header.element = cp;
1378
1379 switch(lt->type) {
1380 case LFT_REQUEST_HEADER: lt->type = LFT_REQUEST_HEADER_ELEM; break;
1381 case LFT_REPLY_HEADER: lt->type = LFT_REPLY_HEADER_ELEM; break;
1382 #if ICAP_CLIENT
1383 case LFT_ICAP_LAST_MATCHED_HEADER: lt->type = LFT_ICAP_LAST_MATCHED_HEADER_ELEM; break;
1384 case LFT_ICAP_REQ_HEADER: lt->type = LFT_ICAP_REQ_HEADER_ELEM; break;
1385 case LFT_ICAP_REP_HEADER: lt->type = LFT_ICAP_REP_HEADER_ELEM; break;
1386 #endif
1387 default:break;
1388 }
1389 }
1390
1391 lt->data.header.header = header;
1392 } else {
1393 switch(lt->type) {
1394 case LFT_REQUEST_HEADER: lt->type = LFT_REQUEST_ALL_HEADERS; break;
1395 case LFT_REPLY_HEADER: lt->type = LFT_REPLY_ALL_HEADERS; break;
1396 #if ICAP_CLIENT
1397 case LFT_ICAP_LAST_MATCHED_HEADER: lt->type = LFT_ICAP_LAST_MATCHED_ALL_HEADERS; break;
1398 case LFT_ICAP_REQ_HEADER: lt->type = LFT_ICAP_REQ_ALL_HEADERS; break;
1399 case LFT_ICAP_REP_HEADER: lt->type = LFT_ICAP_REP_ALL_HEADERS; break;
1400 #endif
1401 default:break;
1402 }
1403 Config.onoff.log_mime_hdrs = 1;
1404 }
1405
1406 break;
1407
1408 case LFT_CLIENT_FQDN:
1409 Config.onoff.log_fqdn = 1;
1410 break;
1411
1412 case LFT_TIME_SUBSECOND:
1413 lt->divisor = 1000;
1414
1415 if (lt->precision) {
1416 int i;
1417 lt->divisor = 1000000;
1418
1419 for (i = lt->precision; i > 1; i--)
1420 lt->divisor /= 10;
1421
1422 if (!lt->divisor)
1423 lt->divisor = 0;
1424 }
1425
1426 break;
1427
1428 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
1429 debugs(46, 0, "WARNING: the \"Hs\" formating code is deprecated use the \">Hs\" instead");
1430 lt->type = LFT_HTTP_SENT_STATUS_CODE;
1431 break;
1432 default:
1433 break;
1434 }
1435
1436 return (cur - def);
1437 }
1438
1439 int
1440 accessLogParseLogFormat(logformat_token ** fmt, char *def)
1441 {
1442 char *cur, *eos;
1443 logformat_token *new_lt, *last_lt;
1444 enum log_quote quote = LOG_QUOTE_NONE;
1445
1446 debugs(46, 2, "accessLogParseLogFormat: got definition '" << def << "'");
1447
1448 /* very inefficent parser, but who cares, this needs to be simple */
1449 /* First off, let's tokenize, we'll optimize in a second pass.
1450 * A token can either be a %-prefixed sequence (usually a dynamic
1451 * token but it can be an escaped sequence), or a string. */
1452 cur = def;
1453 eos = def + strlen(def);
1454 *fmt = new_lt = last_lt = (logformat_token *)xmalloc(sizeof(logformat_token));
1455 cur += accessLogGetNewLogFormatToken(new_lt, cur, &quote);
1456
1457 while (cur < eos) {
1458 new_lt = (logformat_token *)xmalloc(sizeof(logformat_token));
1459 last_lt->next = new_lt;
1460 last_lt = new_lt;
1461 cur += accessLogGetNewLogFormatToken(new_lt, cur, &quote);
1462 }
1463
1464 return 1;
1465 }
1466
1467 void
1468 accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions)
1469 {
1470 logformat_token *t;
1471 logformat *format;
1472
1473 struct logformat_token_table_entry *te;
1474 debugs(46, 0, "accessLogDumpLogFormat called");
1475
1476 for (format = definitions; format; format = format->next) {
1477 debugs(46, 0, "Dumping logformat definition for " << format->name);
1478 storeAppendPrintf(entry, "logformat %s ", format->name);
1479
1480 for (t = format->format; t; t = t->next) {
1481 if (t->type == LFT_STRING)
1482 storeAppendPrintf(entry, "%s", t->data.string);
1483 else {
1484 char argbuf[256];
1485 char *arg = NULL;
1486 logformat_bcode_t type = t->type;
1487
1488 switch (type) {
1489 /* special cases */
1490
1491 case LFT_STRING:
1492 break;
1493 #if ICAP_CLIENT
1494 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM:
1495 case LFT_ICAP_REQ_HEADER_ELEM:
1496 case LFT_ICAP_REP_HEADER_ELEM:
1497 #endif
1498 case LFT_REQUEST_HEADER_ELEM:
1499
1500 case LFT_REPLY_HEADER_ELEM:
1501
1502 if (t->data.header.separator != ',')
1503 snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
1504 else
1505 snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
1506
1507 arg = argbuf;
1508
1509 switch(type) {
1510 case LFT_REQUEST_HEADER_ELEM: type = LFT_REQUEST_HEADER_ELEM; break;
1511 case LFT_REPLY_HEADER_ELEM: type = LFT_REPLY_HEADER_ELEM; break;
1512 #if ICAP_CLIENT
1513 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM: type = LFT_ICAP_LAST_MATCHED_HEADER; break;
1514 case LFT_ICAP_REQ_HEADER_ELEM: type = LFT_ICAP_REQ_HEADER; break;
1515 case LFT_ICAP_REP_HEADER_ELEM: type = LFT_ICAP_REP_HEADER; break;
1516 #endif
1517 default:break;
1518 }
1519
1520 break;
1521
1522 case LFT_REQUEST_ALL_HEADERS:
1523
1524 case LFT_REPLY_ALL_HEADERS:
1525
1526 #if ICAP_CLIENT
1527 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS:
1528 case LFT_ICAP_REQ_ALL_HEADERS:
1529 case LFT_ICAP_REP_ALL_HEADERS:
1530 #endif
1531
1532 switch(type) {
1533 case LFT_REQUEST_ALL_HEADERS: type = LFT_REQUEST_HEADER; break;
1534 case LFT_REPLY_ALL_HEADERS: type = LFT_REPLY_HEADER; break;
1535 #if ICAP_CLIENT
1536 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS: type = LFT_ICAP_LAST_MATCHED_HEADER; break;
1537 case LFT_ICAP_REQ_ALL_HEADERS: type = LFT_ICAP_REQ_HEADER; break;
1538 case LFT_ICAP_REP_ALL_HEADERS: type = LFT_ICAP_REP_HEADER; break;
1539 #endif
1540 default:break;
1541 }
1542
1543 break;
1544
1545 default:
1546 if (t->data.string)
1547 arg = t->data.string;
1548
1549 break;
1550 }
1551
1552 entry->append("%", 1);
1553
1554 switch (t->quote) {
1555
1556 case LOG_QUOTE_QUOTES:
1557 entry->append("\"", 1);
1558 break;
1559
1560 case LOG_QUOTE_BRAKETS:
1561 entry->append("[", 1);
1562 break;
1563
1564 case LOG_QUOTE_URL:
1565 entry->append("#", 1);
1566 break;
1567
1568 case LOG_QUOTE_RAW:
1569 entry->append("'", 1);
1570 break;
1571
1572 case LOG_QUOTE_NONE:
1573 break;
1574 }
1575
1576 if (t->left)
1577 entry->append("-", 1);
1578
1579 if (t->zero)
1580 entry->append("0", 1);
1581
1582 if (t->width)
1583 storeAppendPrintf(entry, "%d", (int) t->width);
1584
1585 if (t->precision)
1586 storeAppendPrintf(entry, ".%d", (int) t->precision);
1587
1588 if (arg)
1589 storeAppendPrintf(entry, "{%s}", arg);
1590
1591 for (te = logformat_token_table; te->config != NULL; te++) {
1592 if (te->token_type == type) {
1593 storeAppendPrintf(entry, "%s", te->config);
1594 break;
1595 }
1596 }
1597
1598 if (t->space)
1599 entry->append(" ", 1);
1600
1601 assert(te->config != NULL);
1602 }
1603 }
1604
1605 entry->append("\n", 1);
1606 }
1607
1608 }
1609
1610 void
1611 accessLogFreeLogFormat(logformat_token ** tokens)
1612 {
1613 while (*tokens) {
1614 logformat_token *token = *tokens;
1615 *tokens = token->next;
1616 safe_free(token->data.string);
1617 xfree(token);
1618 }
1619 }
1620
1621 static void
1622 accessLogSquid(AccessLogEntry * al, Logfile * logfile)
1623 {
1624 const char *client = NULL;
1625 const char *user = NULL;
1626 char buf[MAX_IPSTRLEN];
1627
1628 if (Config.onoff.log_fqdn) {
1629 client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
1630 }
1631
1632 if (client == NULL) {
1633 client = al->cache.caddr.NtoA(buf,MAX_IPSTRLEN);
1634 }
1635
1636 user = accessLogFormatName(al->cache.authuser);
1637
1638 if (!user)
1639 user = accessLogFormatName(al->cache.extuser);
1640
1641 #if USE_SSL
1642
1643 if (!user)
1644 user = accessLogFormatName(al->cache.ssluser);
1645
1646 #endif
1647
1648 if (!user)
1649 user = accessLogFormatName(al->cache.rfc931);
1650
1651 if (user && !*user)
1652 safe_free(user);
1653
1654 if (!Config.onoff.log_mime_hdrs) {
1655 logfilePrintf(logfile, "%9ld.%03d %6d %s %s/%03d %"PRId64" %s %s %s %s%s/%s %s\n",
1656 (long int) current_time.tv_sec,
1657 (int) current_time.tv_usec / 1000,
1658 al->cache.msec,
1659 client,
1660 log_tags[al->cache.code],
1661 al->http.code,
1662 al->cache.replySize,
1663 al->_private.method_str,
1664 al->url,
1665 user ? user : dash_str,
1666 al->hier.ping.timedout ? "TIMEOUT_" : "",
1667 hier_code_str[al->hier.code],
1668 al->hier.host,
1669 al->http.content_type);
1670 } else {
1671 char *ereq = log_quote(al->headers.request);
1672 char *erep = log_quote(al->headers.reply);
1673 logfilePrintf(logfile, "%9ld.%03d %6d %s %s/%03d %"PRId64" %s %s %s %s%s/%s %s [%s] [%s]\n",
1674 (long int) current_time.tv_sec,
1675 (int) current_time.tv_usec / 1000,
1676 al->cache.msec,
1677 client,
1678 log_tags[al->cache.code],
1679 al->http.code,
1680 al->cache.replySize,
1681 al->_private.method_str,
1682 al->url,
1683 user ? user : dash_str,
1684 al->hier.ping.timedout ? "TIMEOUT_" : "",
1685 hier_code_str[al->hier.code],
1686 al->hier.host,
1687 al->http.content_type,
1688 ereq,
1689 erep);
1690 safe_free(ereq);
1691 safe_free(erep);
1692 }
1693 safe_free(user);
1694 }
1695
1696 static void
1697 accessLogCommon(AccessLogEntry * al, Logfile * logfile)
1698 {
1699 const char *client = NULL;
1700 char *user1 = NULL, *user2 = NULL;
1701 char buf[MAX_IPSTRLEN];
1702
1703 if (Config.onoff.log_fqdn) {
1704 client = fqdncache_gethostbyaddr(al->cache.caddr, 0);
1705 }
1706
1707 if (client == NULL) {
1708 client = al->cache.caddr.NtoA(buf,MAX_IPSTRLEN);
1709 }
1710
1711 user1 = accessLogFormatName(al->cache.authuser);
1712
1713 user2 = accessLogFormatName(al->cache.rfc931);
1714
1715 logfilePrintf(logfile, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %"PRId64" %s:%s",
1716 client,
1717 user2 ? user2 : dash_str,
1718 user1 ? user1 : dash_str,
1719 mkhttpdlogtime(&squid_curtime),
1720 al->_private.method_str,
1721 al->url,
1722 al->http.version.major, al->http.version.minor,
1723 al->http.code,
1724 al->cache.replySize,
1725 log_tags[al->cache.code],
1726 hier_code_str[al->hier.code]);
1727
1728 safe_free(user1);
1729
1730 safe_free(user2);
1731
1732 if (Config.onoff.log_mime_hdrs) {
1733 char *ereq = log_quote(al->headers.request);
1734 char *erep = log_quote(al->headers.reply);
1735 logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
1736 safe_free(ereq);
1737 safe_free(erep);
1738 } else {
1739 logfilePrintf(logfile, "\n");
1740 }
1741
1742 }
1743
1744 #if ICAP_CLIENT
1745 static void
1746 accessLogICAPSquid(AccessLogEntry * al, Logfile * logfile)
1747 {
1748 const char *client = NULL;
1749 const char *user = NULL;
1750 char tmp[MAX_IPSTRLEN], clientbuf[MAX_IPSTRLEN];
1751
1752 if (al->cache.caddr.IsAnyAddr()) { // ICAP OPTIONS xactions lack client
1753 client = "-";
1754 } else {
1755 if (Config.onoff.log_fqdn)
1756 client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
1757 if (!client)
1758 client = al->cache.caddr.NtoA(clientbuf, MAX_IPSTRLEN);
1759 }
1760
1761 user = accessLogFormatName(al->cache.authuser);
1762
1763 if (!user)
1764 user = accessLogFormatName(al->cache.extuser);
1765
1766 #if USE_SSL
1767
1768 if (!user)
1769 user = accessLogFormatName(al->cache.ssluser);
1770
1771 #endif
1772
1773 if (!user)
1774 user = accessLogFormatName(al->cache.rfc931);
1775
1776 if (user && !*user)
1777 safe_free(user);
1778
1779 logfilePrintf(logfile, "%9ld.%03d %6d %s -/%03d %"PRId64" %s %s %s -/%s -\n",
1780 (long int) current_time.tv_sec,
1781 (int) current_time.tv_usec / 1000,
1782
1783 al->icap.trTime,
1784 client,
1785
1786 al->icap.resStatus,
1787 al->icap.bytesRead,
1788 Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod),
1789 al->icap.reqUri.termedBuf(),
1790 user ? user : dash_str,
1791 al->icap.hostAddr.NtoA(tmp, MAX_IPSTRLEN));
1792 safe_free(user);
1793 }
1794 #endif
1795
1796 void
1797 accessLogLogTo(customlog* log, AccessLogEntry * al, ACLChecklist * checklist)
1798 {
1799
1800 if (al->url == NULL)
1801 al->url = dash_str;
1802
1803 if (!al->http.content_type || *al->http.content_type == '\0')
1804 al->http.content_type = dash_str;
1805
1806 if (al->icp.opcode)
1807 al->_private.method_str = icp_opcode_str[al->icp.opcode];
1808 else if (al->htcp.opcode)
1809 al->_private.method_str = al->htcp.opcode;
1810 else
1811 al->_private.method_str = RequestMethodStr(al->http.method);
1812
1813 if (al->hier.host[0] == '\0')
1814 xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
1815
1816 for (; log; log = log->next) {
1817 if (checklist && log->aclList && !checklist->matchAclListFast(log->aclList))
1818 continue;
1819
1820 switch (log->type) {
1821
1822 case CLF_AUTO:
1823
1824 if (Config.onoff.common_log)
1825 accessLogCommon(al, log->logfile);
1826 else
1827 accessLogSquid(al, log->logfile);
1828
1829 break;
1830
1831 case CLF_SQUID:
1832 accessLogSquid(al, log->logfile);
1833
1834 break;
1835
1836 case CLF_COMMON:
1837 accessLogCommon(al, log->logfile);
1838
1839 break;
1840
1841 case CLF_CUSTOM:
1842 accessLogCustom(al, log);
1843
1844 break;
1845
1846 #if ICAP_CLIENT
1847 case CLF_ICAP_SQUID:
1848 accessLogICAPSquid(al, log->logfile);
1849
1850 break;
1851 #endif
1852
1853 case CLF_NONE:
1854 goto last;
1855
1856 default:
1857 fatalf("Unknown log format %d\n", log->type);
1858
1859 break;
1860 }
1861
1862 logfileFlush(log->logfile);
1863
1864 if (!checklist)
1865 break;
1866 }
1867
1868 last:
1869 (void)0; /* NULL statement for label */
1870 }
1871
1872 void
1873 accessLogLog(AccessLogEntry * al, ACLChecklist * checklist)
1874 {
1875 if (LogfileStatus != LOG_ENABLE)
1876 return;
1877
1878 accessLogLogTo(Config.Log.accesslogs, al, checklist);
1879 #if MULTICAST_MISS_STREAM
1880
1881 if (al->cache.code != LOG_TCP_MISS)
1882 (void) 0;
1883 else if (al->http.method != METHOD_GET)
1884 (void) 0;
1885 else if (mcast_miss_fd < 0)
1886 (void) 0;
1887 else {
1888 unsigned int ibuf[365];
1889 size_t isize;
1890 xstrncpy((char *) ibuf, al->url, 364 * sizeof(int));
1891 isize = ((strlen(al->url) + 8) / 8) * 2;
1892
1893 if (isize > 364)
1894 isize = 364;
1895
1896 mcast_encode((unsigned int *) ibuf, isize,
1897 (const unsigned int *) Config.mcast_miss.encode_key);
1898
1899 comm_udp_sendto(mcast_miss_fd,
1900 &mcast_miss_to, sizeof(mcast_miss_to),
1901 ibuf, isize * sizeof(int));
1902 }
1903
1904 #endif
1905 }
1906
1907 void
1908 accessLogRotate(void)
1909 {
1910 customlog *log;
1911 #if FORW_VIA_DB
1912
1913 fvdbClear();
1914 #endif
1915
1916 for (log = Config.Log.accesslogs; log; log = log->next) {
1917 if (log->logfile) {
1918 logfileRotate(log->logfile);
1919 }
1920 }
1921
1922 #if HEADERS_LOG
1923
1924 logfileRotate(headerslog);
1925
1926 #endif
1927 }
1928
1929 void
1930 accessLogClose(void)
1931 {
1932 customlog *log;
1933
1934 for (log = Config.Log.accesslogs; log; log = log->next) {
1935 if (log->logfile) {
1936 logfileClose(log->logfile);
1937 log->logfile = NULL;
1938 }
1939 }
1940
1941 #if HEADERS_LOG
1942
1943 logfileClose(headerslog);
1944
1945 headerslog = NULL;
1946
1947 #endif
1948 }
1949
1950 HierarchyLogEntry::HierarchyLogEntry() :
1951 code(HIER_NONE),
1952 cd_lookup(LOOKUP_NONE),
1953 n_choices(0),
1954 n_ichoices(0),
1955 peer_reply_status(HTTP_STATUS_NONE),
1956 peer_response_time(-1),
1957 total_response_time(-1)
1958 {
1959 memset(host, '\0', SQUIDHOSTNAMELEN);
1960 memset(cd_host, '\0', SQUIDHOSTNAMELEN);
1961
1962 peer_select_start.tv_sec =0;
1963 peer_select_start.tv_usec =0;
1964
1965 store_complete_stop.tv_sec =0;
1966 store_complete_stop.tv_usec =0;
1967
1968 peer_http_request_sent.tv_sec = 0;
1969 peer_http_request_sent.tv_usec = 0;
1970
1971 first_conn_start.tv_sec = 0;
1972 first_conn_start.tv_usec = 0;
1973 }
1974
1975 void
1976 hierarchyNote(HierarchyLogEntry * hl,
1977 hier_code code,
1978 const char *cache_peer)
1979 {
1980 assert(hl != NULL);
1981 hl->code = code;
1982 xstrncpy(hl->host, cache_peer, SQUIDHOSTNAMELEN);
1983 }
1984
1985 static void
1986 accessLogRegisterWithCacheManager(void)
1987 {
1988 #if FORW_VIA_DB
1989 fvdbRegisterWithCacheManager();
1990 #endif
1991 }
1992
1993 void
1994 accessLogInit(void)
1995 {
1996 customlog *log;
1997
1998 accessLogRegisterWithCacheManager();
1999
2000 assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
2001
2002 for (log = Config.Log.accesslogs; log; log = log->next) {
2003 if (log->type == CLF_NONE)
2004 continue;
2005
2006 log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1);
2007
2008 LogfileStatus = LOG_ENABLE;
2009
2010 #if USE_ADAPTATION || ICAP_CLIENT
2011 alLogformatHasAdaptToken = false;
2012 alLogformatHasIcapToken = false;
2013 for (logformat_token * curr_token = (log->logFormat?log->logFormat->format:NULL); curr_token; curr_token = curr_token->next)
2014 {
2015 #if USE_ADAPTATION
2016 if (curr_token->type == LTF_ADAPTATION_SUM_XACT_TIMES ||
2017 curr_token->type == LTF_ADAPTATION_ALL_XACT_TIMES) {
2018 alLogformatHasAdaptToken = true;
2019 }
2020 #endif
2021 #if ICAP_CLIENT
2022 if (curr_token->type == LFT_ICAP_LAST_MATCHED_HEADER ||
2023 curr_token->type == LFT_ICAP_LAST_MATCHED_HEADER_ELEM ||
2024 curr_token->type == LFT_ICAP_LAST_MATCHED_ALL_HEADERS)
2025 {
2026 alLogformatHasIcapToken = true;
2027 }
2028 #endif
2029 }
2030 #endif
2031 }
2032
2033 #if HEADERS_LOG
2034
2035 headerslog = logfileOpen("/usr/local/squid/logs/headers.log", 512);
2036
2037 assert(NULL != headerslog);
2038
2039 #endif
2040 #if MULTICAST_MISS_STREAM
2041
2042 if (Config.mcast_miss.addr.s_addr != no_addr.s_addr) {
2043 memset(&mcast_miss_to, '\0', sizeof(mcast_miss_to));
2044 mcast_miss_to.sin_family = AF_INET;
2045 mcast_miss_to.sin_port = htons(Config.mcast_miss.port);
2046 mcast_miss_to.sin_addr.s_addr = Config.mcast_miss.addr.s_addr;
2047 mcast_miss_fd = comm_open(SOCK_DGRAM,
2048 IPPROTO_UDP,
2049 Config.Addrs.udp_incoming,
2050 Config.mcast_miss.port,
2051 COMM_NONBLOCKING,
2052 "Multicast Miss Stream");
2053
2054 if (mcast_miss_fd < 0)
2055 fatal("Cannot open Multicast Miss Stream Socket");
2056
2057 debugs(46, 1, "Multicast Miss Stream Socket opened on FD " << mcast_miss_fd);
2058
2059 mcastSetTtl(mcast_miss_fd, Config.mcast_miss.ttl);
2060
2061 if (strlen(Config.mcast_miss.encode_key) < 16)
2062 fatal("mcast_encode_key is too short, must be 16 characters");
2063 }
2064
2065 #endif
2066 #if FORW_VIA_DB
2067
2068 fvdbInit();
2069
2070 #endif
2071 }
2072
2073 const char *
2074 accessLogTime(time_t t)
2075 {
2076
2077 struct tm *tm;
2078 static char buf[128];
2079 static time_t last_t = 0;
2080
2081 if (t != last_t) {
2082 tm = localtime(&t);
2083 strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
2084 last_t = t;
2085 }
2086
2087 return buf;
2088 }
2089
2090
2091 #if FORW_VIA_DB
2092
2093 static void
2094 fvdbInit(void)
2095 {
2096 via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2097 forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2098 }
2099
2100 static void
2101 fvdbRegisterWithCacheManager(void)
2102 {
2103 CacheManager *manager=CacheManager::GetInstance();
2104 manager->registerAction("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
2105 manager->registerAction("forw_headers", "X-Forwarded-For Request Headers",
2106 fvdbDumpForw, 0, 1);
2107 }
2108
2109 static void
2110 fvdbCount(hash_table * hash, const char *key)
2111 {
2112 fvdb_entry *fv;
2113
2114 if (NULL == hash)
2115 return;
2116
2117 fv = (fvdb_entry *)hash_lookup(hash, key);
2118
2119 if (NULL == fv) {
2120 fv = static_cast <fvdb_entry *>(xcalloc(1, sizeof(fvdb_entry)));
2121 fv->hash.key = xstrdup(key);
2122 hash_join(hash, &fv->hash);
2123 }
2124
2125 fv->n++;
2126 }
2127
2128 void
2129 fvdbCountVia(const char *key)
2130 {
2131 fvdbCount(via_table, key);
2132 }
2133
2134 void
2135 fvdbCountForw(const char *key)
2136 {
2137 fvdbCount(forw_table, key);
2138 }
2139
2140 static void
2141 fvdbDumpTable(StoreEntry * e, hash_table * hash)
2142 {
2143 hash_link *h;
2144 fvdb_entry *fv;
2145
2146 if (hash == NULL)
2147 return;
2148
2149 hash_first(hash);
2150
2151 while ((h = hash_next(hash))) {
2152 fv = (fvdb_entry *) h;
2153 storeAppendPrintf(e, "%9d %s\n", fv->n, hashKeyStr(&fv->hash));
2154 }
2155 }
2156
2157 static void
2158 fvdbDumpVia(StoreEntry * e)
2159 {
2160 fvdbDumpTable(e, via_table);
2161 }
2162
2163 static void
2164 fvdbDumpForw(StoreEntry * e)
2165 {
2166 fvdbDumpTable(e, forw_table);
2167 }
2168
2169 static
2170 void
2171 fvdbFreeEntry(void *data)
2172 {
2173 fvdb_entry *fv = static_cast <fvdb_entry *>(data);
2174 xfree(fv->hash.key);
2175 xfree(fv);
2176 }
2177
2178 static void
2179 fvdbClear(void)
2180 {
2181 hashFreeItems(via_table, fvdbFreeEntry);
2182 hashFreeMemory(via_table);
2183 via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2184 hashFreeItems(forw_table, fvdbFreeEntry);
2185 hashFreeMemory(forw_table);
2186 forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2187 }
2188
2189 #endif
2190
2191 #if MULTICAST_MISS_STREAM
2192 /*
2193 * From http://www.io.com/~paulhart/game/algorithms/tea.html
2194 *
2195 * size of 'ibuf' must be a multiple of 2.
2196 * size of 'key' must be 4.
2197 * 'ibuf' is modified in place, encrypted data is written in
2198 * network byte order.
2199 */
2200 static void
2201 mcast_encode(unsigned int *ibuf, size_t isize, const unsigned int *key)
2202 {
2203 unsigned int y;
2204 unsigned int z;
2205 unsigned int sum;
2206 const unsigned int delta = 0x9e3779b9;
2207 unsigned int n = 32;
2208 const unsigned int k0 = htonl(key[0]);
2209 const unsigned int k1 = htonl(key[1]);
2210 const unsigned int k2 = htonl(key[2]);
2211 const unsigned int k3 = htonl(key[3]);
2212 int i;
2213
2214 for (i = 0; i < isize; i += 2) {
2215 y = htonl(ibuf[i]);
2216 z = htonl(ibuf[i + 1]);
2217 sum = 0;
2218
2219 for (n = 32; n; n--) {
2220 sum += delta;
2221 y += (z << 4) + (k0 ^ z) + (sum ^ (z >> 5)) + k1;
2222 z += (y << 4) + (k2 ^ y) + (sum ^ (y >> 5)) + k3;
2223 }
2224
2225 ibuf[i] = htonl(y);
2226 ibuf[i + 1] = htonl(z);
2227 }
2228 }
2229
2230 #endif
2231
2232 #if HEADERS_LOG
2233 void
2234 headersLog(int cs, int pq, const HttpRequestMethod& method, void *data)
2235 {
2236 HttpReply *rep;
2237 HttpRequest *req;
2238 unsigned short magic = 0;
2239 unsigned char M = (unsigned char) m;
2240 unsigned short S;
2241 char *hmask;
2242 int ccmask = 0;
2243
2244 if (0 == pq) {
2245 /* reply */
2246 rep = data;
2247 req = NULL;
2248 magic = 0x0050;
2249 hmask = rep->header.mask;
2250
2251 if (rep->cache_control)
2252 ccmask = rep->cache_control->mask;
2253 } else {
2254 /* request */
2255 req = data;
2256 rep = NULL;
2257 magic = 0x0051;
2258 hmask = req->header.mask;
2259
2260 if (req->cache_control)
2261 ccmask = req->cache_control->mask;
2262 }
2263
2264 if (0 == cs) {
2265 /* client */
2266 magic |= 0x4300;
2267 } else {
2268 /* server */
2269 magic |= 0x5300;
2270 }
2271
2272 magic = htons(magic);
2273 ccmask = htonl(ccmask);
2274
2275 if (0 == pq)
2276 S = (unsigned short) rep->sline.status;
2277 else
2278 S = (unsigned short) HTTP_STATUS_NONE;
2279
2280 logfileWrite(headerslog, &magic, sizeof(magic));
2281
2282 logfileWrite(headerslog, &M, sizeof(M));
2283
2284 logfileWrite(headerslog, &S, sizeof(S));
2285
2286 logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask));
2287
2288 logfileWrite(headerslog, &ccmask, sizeof(int));
2289
2290 logfileFlush(headerslog);
2291 }
2292
2293 #endif
2294
2295 void
2296 accessLogFreeMemory(AccessLogEntry * aLogEntry)
2297 {
2298 safe_free(aLogEntry->headers.request);
2299
2300 #if ICAP_CLIENT
2301 safe_free(aLogEntry->headers.icap);
2302 #endif
2303
2304 safe_free(aLogEntry->headers.reply);
2305 safe_free(aLogEntry->cache.authuser);
2306
2307 HTTPMSGUNLOCK(aLogEntry->reply);
2308 HTTPMSGUNLOCK(aLogEntry->request);
2309 #if ICAP_CLIENT
2310 HTTPMSGUNLOCK(aLogEntry->icap.reply);
2311 HTTPMSGUNLOCK(aLogEntry->icap.request);
2312 #endif
2313 }
2314
2315 int
2316 logTypeIsATcpHit(log_type code)
2317 {
2318 /* this should be a bitmap for better optimization */
2319
2320 if (code == LOG_TCP_HIT)
2321 return 1;
2322
2323 if (code == LOG_TCP_IMS_HIT)
2324 return 1;
2325
2326 if (code == LOG_TCP_REFRESH_FAIL)
2327 return 1;
2328
2329 if (code == LOG_TCP_REFRESH_UNMODIFIED)
2330 return 1;
2331
2332 if (code == LOG_TCP_NEGATIVE_HIT)
2333 return 1;
2334
2335 if (code == LOG_TCP_MEM_HIT)
2336 return 1;
2337
2338 if (code == LOG_TCP_OFFLINE_HIT)
2339 return 1;
2340
2341 return 0;
2342 }
2343