]> git.ipfire.org Git - thirdparty/squid.git/blob - src/access_log.cc
SourceFormat: enforcement
[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 } else {
1014 outint = al->hier.peer_reply_status;
1015 doint = 1;
1016 }
1017 break;
1018 /* case LFT_HTTP_STATUS:
1019 * out = statusline->text;
1020 * quote = 1;
1021 * break;
1022 */
1023
1024 case LFT_SQUID_STATUS:
1025 out = log_tags[al->cache.code];
1026
1027 break;
1028
1029 /* case LFT_SQUID_ERROR: */
1030
1031 case LFT_SQUID_HIERARCHY:
1032 if (al->hier.ping.timedout)
1033 mb.append("TIMEOUT_", 8);
1034
1035 out = hier_code_str[al->hier.code];
1036
1037 break;
1038
1039 case LFT_MIME_TYPE:
1040 out = al->http.content_type;
1041
1042 break;
1043
1044 case LFT_REQUEST_METHOD:
1045 out = al->_private.method_str;
1046
1047 break;
1048
1049 case LFT_REQUEST_URI:
1050 out = al->url;
1051
1052 break;
1053
1054 case LFT_REQUEST_URLPATH:
1055 if (al->request) {
1056 out = al->request->urlpath.termedBuf();
1057 quote = 1;
1058 }
1059 break;
1060
1061 case LFT_REQUEST_VERSION:
1062 snprintf(tmp, sizeof(tmp), "%d.%d", (int) al->http.version.major, (int) al->http.version.minor);
1063 out = tmp;
1064 break;
1065
1066 case LFT_REQUEST_SIZE_TOTAL:
1067 outoff = al->cache.requestSize;
1068 dooff = 1;
1069 break;
1070
1071 /*case LFT_REQUEST_SIZE_LINE: */
1072 case LFT_REQUEST_SIZE_HEADERS:
1073 outoff = al->cache.requestHeadersSize;
1074 dooff =1;
1075 break;
1076 /*case LFT_REQUEST_SIZE_BODY: */
1077 /*case LFT_REQUEST_SIZE_BODY_NO_TE: */
1078
1079 case LFT_REPLY_SIZE_TOTAL:
1080 outoff = al->cache.replySize;
1081 dooff = 1;
1082 break;
1083
1084 case LFT_REPLY_HIGHOFFSET:
1085 outoff = al->cache.highOffset;
1086
1087 dooff = 1;
1088
1089 break;
1090
1091 case LFT_REPLY_OBJECTSIZE:
1092 outoff = al->cache.objectSize;
1093
1094 dooff = 1;
1095
1096 break;
1097
1098 /*case LFT_REPLY_SIZE_LINE: */
1099 case LFT_REPLY_SIZE_HEADERS:
1100 outint = al->cache.replyHeadersSize;
1101 doint = 1;
1102 /*case LFT_REPLY_SIZE_BODY: */
1103 /*case LFT_REPLY_SIZE_BODY_NO_TE: */
1104
1105 case LFT_TAG:
1106 if (al->request)
1107 out = al->request->tag.termedBuf();
1108
1109 quote = 1;
1110
1111 break;
1112
1113 case LFT_IO_SIZE_TOTAL:
1114 outint = al->cache.requestSize + al->cache.replySize;
1115 doint = 1;
1116 break;
1117
1118 case LFT_EXT_LOG:
1119 if (al->request)
1120 out = al->request->extacl_log.termedBuf();
1121
1122 quote = 1;
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 ? (int) fmt->width : 0, outoff);
1134 out = tmp;
1135
1136 } else if (doint) {
1137 snprintf(tmp, sizeof(tmp), "%0*ld", fmt->zero ? (int) fmt->width : 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 newout = log_quoted_string(out);
1154 newfree = 1;
1155 break;
1156
1157 case LOG_QUOTE_BRAKETS:
1158 newout = log_quote(out);
1159 newfree = 1;
1160 break;
1161
1162 case LOG_QUOTE_URL:
1163 newout = rfc1738_escape(out);
1164 break;
1165
1166 case LOG_QUOTE_RAW:
1167 break;
1168 }
1169
1170 if (newout) {
1171 if (dofree)
1172 safe_free(out);
1173
1174 out = newout;
1175
1176 dofree = newfree;
1177 }
1178 }
1179
1180 if (fmt->width) {
1181 if (fmt->left)
1182 mb.Printf("%-*s", (int) fmt->width, out);
1183 else
1184 mb.Printf("%*s", (int) fmt->width, out);
1185 } else
1186 mb.append(out, strlen(out));
1187 } else {
1188 mb.append("-", 1);
1189 }
1190
1191 if (fmt->space)
1192 mb.append(" ", 1);
1193
1194 sb.clean();
1195
1196 if (dofree)
1197 safe_free(out);
1198 }
1199
1200 logfilePrintf(logfile, "%s\n", mb.buf);
1201 }
1202
1203 /* parses a single token. Returns the token length in characters,
1204 * and fills in the lt item with the token information.
1205 * def is for sure null-terminated
1206 */
1207 static int
1208 accessLogGetNewLogFormatToken(logformat_token * lt, char *def, enum log_quote *quote)
1209 {
1210 char *cur = def;
1211
1212 struct logformat_token_table_entry *lte;
1213 int l;
1214
1215 memset(lt, 0, sizeof(*lt));
1216 l = strcspn(cur, "%");
1217
1218 if (l > 0) {
1219 char *cp;
1220 /* it's a string for sure, until \0 or the next % */
1221 cp = (char *)xmalloc(l + 1);
1222 xstrncpy(cp, cur, l + 1);
1223 lt->type = LFT_STRING;
1224 lt->data.string = cp;
1225
1226 while (l > 0) {
1227 switch (*cur) {
1228
1229 case '"':
1230
1231 if (*quote == LOG_QUOTE_NONE)
1232 *quote = LOG_QUOTE_QUOTES;
1233 else if (*quote == LOG_QUOTE_QUOTES)
1234 *quote = LOG_QUOTE_NONE;
1235
1236 break;
1237
1238 case '[':
1239 if (*quote == LOG_QUOTE_NONE)
1240 *quote = LOG_QUOTE_BRAKETS;
1241
1242 break;
1243
1244 case ']':
1245 if (*quote == LOG_QUOTE_BRAKETS)
1246 *quote = LOG_QUOTE_NONE;
1247
1248 break;
1249 }
1250
1251 cur++;
1252 l--;
1253 }
1254
1255 goto done;
1256 }
1257
1258 if (!*cur)
1259 goto done;
1260
1261 cur++;
1262
1263 switch (*cur) {
1264
1265 case '"':
1266 lt->quote = LOG_QUOTE_QUOTES;
1267 cur++;
1268 break;
1269
1270 case '\'':
1271 lt->quote = LOG_QUOTE_RAW;
1272 cur++;
1273 break;
1274
1275 case '[':
1276 lt->quote = LOG_QUOTE_BRAKETS;
1277 cur++;
1278 break;
1279
1280 case '#':
1281 lt->quote = LOG_QUOTE_URL;
1282 cur++;
1283 break;
1284
1285 default:
1286 lt->quote = *quote;
1287 break;
1288 }
1289
1290 if (*cur == '-') {
1291 lt->left = 1;
1292 cur++;
1293 }
1294
1295 if (*cur == '0') {
1296 lt->zero = 1;
1297 cur++;
1298 }
1299
1300 if (xisdigit(*cur))
1301 lt->width = strtol(cur, &cur, 10);
1302
1303 if (*cur == '.')
1304 lt->precision = strtol(cur + 1, &cur, 10);
1305
1306 if (*cur == '{') {
1307 char *cp;
1308 cur++;
1309 l = strcspn(cur, "}");
1310 cp = (char *)xmalloc(l + 1);
1311 xstrncpy(cp, cur, l + 1);
1312 lt->data.string = cp;
1313 cur += l;
1314
1315 if (*cur == '}')
1316 cur++;
1317 }
1318
1319 // For upward compatibility, assume "http::" prefix as default prefix
1320 // for all log access formating codes, except those starting
1321 // from "icap::", "adapt::" and "%"
1322 if (strncmp(cur,"http::", 6) == 0 &&
1323 strncmp(cur+6, "icap::", 6) != 0 &&
1324 strncmp(cur+6, "adapt::", 12) != 0 && *(cur+6) != '%' ) {
1325 cur += 6;
1326 }
1327
1328 lt->type = LFT_NONE;
1329
1330 for (lte = logformat_token_table; lte->config != NULL; lte++) {
1331 if (strncmp(lte->config, cur, strlen(lte->config)) == 0) {
1332 lt->type = lte->token_type;
1333 cur += strlen(lte->config);
1334 break;
1335 }
1336 }
1337
1338 if (lt->type == LFT_NONE) {
1339 fatalf("Can't parse configuration token: '%s'\n",
1340 def);
1341 }
1342
1343 if (*cur == ' ') {
1344 lt->space = 1;
1345 cur++;
1346 }
1347
1348 done:
1349
1350 switch (lt->type) {
1351
1352 #if ICAP_CLIENT
1353 case LFT_ICAP_LAST_MATCHED_HEADER:
1354
1355 case LFT_ICAP_REQ_HEADER:
1356
1357 case LFT_ICAP_REP_HEADER:
1358 #endif
1359
1360 case LFT_REQUEST_HEADER:
1361
1362 case LFT_REPLY_HEADER:
1363
1364 if (lt->data.string) {
1365 char *header = lt->data.string;
1366 char *cp = strchr(header, ':');
1367
1368 if (cp) {
1369 *cp++ = '\0';
1370
1371 if (*cp == ',' || *cp == ';' || *cp == ':')
1372 lt->data.header.separator = *cp++;
1373 else
1374 lt->data.header.separator = ',';
1375
1376 lt->data.header.element = cp;
1377
1378 switch (lt->type) {
1379 case LFT_REQUEST_HEADER:
1380 lt->type = LFT_REQUEST_HEADER_ELEM;
1381 break;
1382 case LFT_REPLY_HEADER:
1383 lt->type = LFT_REPLY_HEADER_ELEM;
1384 break;
1385 #if ICAP_CLIENT
1386 case LFT_ICAP_LAST_MATCHED_HEADER:
1387 lt->type = LFT_ICAP_LAST_MATCHED_HEADER_ELEM;
1388 break;
1389 case LFT_ICAP_REQ_HEADER:
1390 lt->type = LFT_ICAP_REQ_HEADER_ELEM;
1391 break;
1392 case LFT_ICAP_REP_HEADER:
1393 lt->type = LFT_ICAP_REP_HEADER_ELEM;
1394 break;
1395 #endif
1396 default:
1397 break;
1398 }
1399 }
1400
1401 lt->data.header.header = header;
1402 } else {
1403 switch (lt->type) {
1404 case LFT_REQUEST_HEADER:
1405 lt->type = LFT_REQUEST_ALL_HEADERS;
1406 break;
1407 case LFT_REPLY_HEADER:
1408 lt->type = LFT_REPLY_ALL_HEADERS;
1409 break;
1410 #if ICAP_CLIENT
1411 case LFT_ICAP_LAST_MATCHED_HEADER:
1412 lt->type = LFT_ICAP_LAST_MATCHED_ALL_HEADERS;
1413 break;
1414 case LFT_ICAP_REQ_HEADER:
1415 lt->type = LFT_ICAP_REQ_ALL_HEADERS;
1416 break;
1417 case LFT_ICAP_REP_HEADER:
1418 lt->type = LFT_ICAP_REP_ALL_HEADERS;
1419 break;
1420 #endif
1421 default:
1422 break;
1423 }
1424 Config.onoff.log_mime_hdrs = 1;
1425 }
1426
1427 break;
1428
1429 case LFT_CLIENT_FQDN:
1430 Config.onoff.log_fqdn = 1;
1431 break;
1432
1433 case LFT_TIME_SUBSECOND:
1434 lt->divisor = 1000;
1435
1436 if (lt->precision) {
1437 int i;
1438 lt->divisor = 1000000;
1439
1440 for (i = lt->precision; i > 1; i--)
1441 lt->divisor /= 10;
1442
1443 if (!lt->divisor)
1444 lt->divisor = 0;
1445 }
1446
1447 break;
1448
1449 case LFT_HTTP_SENT_STATUS_CODE_OLD_30:
1450 debugs(46, 0, "WARNING: the \"Hs\" formating code is deprecated use the \">Hs\" instead");
1451 lt->type = LFT_HTTP_SENT_STATUS_CODE;
1452 break;
1453 default:
1454 break;
1455 }
1456
1457 return (cur - def);
1458 }
1459
1460 int
1461 accessLogParseLogFormat(logformat_token ** fmt, char *def)
1462 {
1463 char *cur, *eos;
1464 logformat_token *new_lt, *last_lt;
1465 enum log_quote quote = LOG_QUOTE_NONE;
1466
1467 debugs(46, 2, "accessLogParseLogFormat: got definition '" << def << "'");
1468
1469 /* very inefficent parser, but who cares, this needs to be simple */
1470 /* First off, let's tokenize, we'll optimize in a second pass.
1471 * A token can either be a %-prefixed sequence (usually a dynamic
1472 * token but it can be an escaped sequence), or a string. */
1473 cur = def;
1474 eos = def + strlen(def);
1475 *fmt = new_lt = last_lt = (logformat_token *)xmalloc(sizeof(logformat_token));
1476 cur += accessLogGetNewLogFormatToken(new_lt, cur, &quote);
1477
1478 while (cur < eos) {
1479 new_lt = (logformat_token *)xmalloc(sizeof(logformat_token));
1480 last_lt->next = new_lt;
1481 last_lt = new_lt;
1482 cur += accessLogGetNewLogFormatToken(new_lt, cur, &quote);
1483 }
1484
1485 return 1;
1486 }
1487
1488 void
1489 accessLogDumpLogFormat(StoreEntry * entry, const char *name, logformat * definitions)
1490 {
1491 logformat_token *t;
1492 logformat *format;
1493
1494 struct logformat_token_table_entry *te;
1495 debugs(46, 0, "accessLogDumpLogFormat called");
1496
1497 for (format = definitions; format; format = format->next) {
1498 debugs(46, 0, "Dumping logformat definition for " << format->name);
1499 storeAppendPrintf(entry, "logformat %s ", format->name);
1500
1501 for (t = format->format; t; t = t->next) {
1502 if (t->type == LFT_STRING)
1503 storeAppendPrintf(entry, "%s", t->data.string);
1504 else {
1505 char argbuf[256];
1506 char *arg = NULL;
1507 logformat_bcode_t type = t->type;
1508
1509 switch (type) {
1510 /* special cases */
1511
1512 case LFT_STRING:
1513 break;
1514 #if ICAP_CLIENT
1515 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM:
1516 case LFT_ICAP_REQ_HEADER_ELEM:
1517 case LFT_ICAP_REP_HEADER_ELEM:
1518 #endif
1519 case LFT_REQUEST_HEADER_ELEM:
1520
1521 case LFT_REPLY_HEADER_ELEM:
1522
1523 if (t->data.header.separator != ',')
1524 snprintf(argbuf, sizeof(argbuf), "%s:%c%s", t->data.header.header, t->data.header.separator, t->data.header.element);
1525 else
1526 snprintf(argbuf, sizeof(argbuf), "%s:%s", t->data.header.header, t->data.header.element);
1527
1528 arg = argbuf;
1529
1530 switch (type) {
1531 case LFT_REQUEST_HEADER_ELEM:
1532 type = LFT_REQUEST_HEADER_ELEM;
1533 break;
1534 case LFT_REPLY_HEADER_ELEM:
1535 type = LFT_REPLY_HEADER_ELEM;
1536 break;
1537 #if ICAP_CLIENT
1538 case LFT_ICAP_LAST_MATCHED_HEADER_ELEM:
1539 type = LFT_ICAP_LAST_MATCHED_HEADER;
1540 break;
1541 case LFT_ICAP_REQ_HEADER_ELEM:
1542 type = LFT_ICAP_REQ_HEADER;
1543 break;
1544 case LFT_ICAP_REP_HEADER_ELEM:
1545 type = LFT_ICAP_REP_HEADER;
1546 break;
1547 #endif
1548 default:
1549 break;
1550 }
1551
1552 break;
1553
1554 case LFT_REQUEST_ALL_HEADERS:
1555
1556 case LFT_REPLY_ALL_HEADERS:
1557
1558 #if ICAP_CLIENT
1559 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS:
1560 case LFT_ICAP_REQ_ALL_HEADERS:
1561 case LFT_ICAP_REP_ALL_HEADERS:
1562 #endif
1563
1564 switch (type) {
1565 case LFT_REQUEST_ALL_HEADERS:
1566 type = LFT_REQUEST_HEADER;
1567 break;
1568 case LFT_REPLY_ALL_HEADERS:
1569 type = LFT_REPLY_HEADER;
1570 break;
1571 #if ICAP_CLIENT
1572 case LFT_ICAP_LAST_MATCHED_ALL_HEADERS:
1573 type = LFT_ICAP_LAST_MATCHED_HEADER;
1574 break;
1575 case LFT_ICAP_REQ_ALL_HEADERS:
1576 type = LFT_ICAP_REQ_HEADER;
1577 break;
1578 case LFT_ICAP_REP_ALL_HEADERS:
1579 type = LFT_ICAP_REP_HEADER;
1580 break;
1581 #endif
1582 default:
1583 break;
1584 }
1585
1586 break;
1587
1588 default:
1589 if (t->data.string)
1590 arg = t->data.string;
1591
1592 break;
1593 }
1594
1595 entry->append("%", 1);
1596
1597 switch (t->quote) {
1598
1599 case LOG_QUOTE_QUOTES:
1600 entry->append("\"", 1);
1601 break;
1602
1603 case LOG_QUOTE_BRAKETS:
1604 entry->append("[", 1);
1605 break;
1606
1607 case LOG_QUOTE_URL:
1608 entry->append("#", 1);
1609 break;
1610
1611 case LOG_QUOTE_RAW:
1612 entry->append("'", 1);
1613 break;
1614
1615 case LOG_QUOTE_NONE:
1616 break;
1617 }
1618
1619 if (t->left)
1620 entry->append("-", 1);
1621
1622 if (t->zero)
1623 entry->append("0", 1);
1624
1625 if (t->width)
1626 storeAppendPrintf(entry, "%d", (int) t->width);
1627
1628 if (t->precision)
1629 storeAppendPrintf(entry, ".%d", (int) t->precision);
1630
1631 if (arg)
1632 storeAppendPrintf(entry, "{%s}", arg);
1633
1634 for (te = logformat_token_table; te->config != NULL; te++) {
1635 if (te->token_type == type) {
1636 storeAppendPrintf(entry, "%s", te->config);
1637 break;
1638 }
1639 }
1640
1641 if (t->space)
1642 entry->append(" ", 1);
1643
1644 assert(te->config != NULL);
1645 }
1646 }
1647
1648 entry->append("\n", 1);
1649 }
1650
1651 }
1652
1653 void
1654 accessLogFreeLogFormat(logformat_token ** tokens)
1655 {
1656 while (*tokens) {
1657 logformat_token *token = *tokens;
1658 *tokens = token->next;
1659 safe_free(token->data.string);
1660 xfree(token);
1661 }
1662 }
1663
1664 static void
1665 accessLogSquid(AccessLogEntry * al, Logfile * logfile)
1666 {
1667 const char *client = NULL;
1668 const char *user = NULL;
1669 char buf[MAX_IPSTRLEN];
1670
1671 if (Config.onoff.log_fqdn) {
1672 client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
1673 }
1674
1675 if (client == NULL) {
1676 client = al->cache.caddr.NtoA(buf,MAX_IPSTRLEN);
1677 }
1678
1679 user = accessLogFormatName(al->cache.authuser);
1680
1681 if (!user)
1682 user = accessLogFormatName(al->cache.extuser);
1683
1684 #if USE_SSL
1685
1686 if (!user)
1687 user = accessLogFormatName(al->cache.ssluser);
1688
1689 #endif
1690
1691 if (!user)
1692 user = accessLogFormatName(al->cache.rfc931);
1693
1694 if (user && !*user)
1695 safe_free(user);
1696
1697 if (!Config.onoff.log_mime_hdrs) {
1698 logfilePrintf(logfile, "%9ld.%03d %6d %s %s/%03d %"PRId64" %s %s %s %s%s/%s %s\n",
1699 (long int) current_time.tv_sec,
1700 (int) current_time.tv_usec / 1000,
1701 al->cache.msec,
1702 client,
1703 log_tags[al->cache.code],
1704 al->http.code,
1705 al->cache.replySize,
1706 al->_private.method_str,
1707 al->url,
1708 user ? user : dash_str,
1709 al->hier.ping.timedout ? "TIMEOUT_" : "",
1710 hier_code_str[al->hier.code],
1711 al->hier.host,
1712 al->http.content_type);
1713 } else {
1714 char *ereq = log_quote(al->headers.request);
1715 char *erep = log_quote(al->headers.reply);
1716 logfilePrintf(logfile, "%9ld.%03d %6d %s %s/%03d %"PRId64" %s %s %s %s%s/%s %s [%s] [%s]\n",
1717 (long int) current_time.tv_sec,
1718 (int) current_time.tv_usec / 1000,
1719 al->cache.msec,
1720 client,
1721 log_tags[al->cache.code],
1722 al->http.code,
1723 al->cache.replySize,
1724 al->_private.method_str,
1725 al->url,
1726 user ? user : dash_str,
1727 al->hier.ping.timedout ? "TIMEOUT_" : "",
1728 hier_code_str[al->hier.code],
1729 al->hier.host,
1730 al->http.content_type,
1731 ereq,
1732 erep);
1733 safe_free(ereq);
1734 safe_free(erep);
1735 }
1736 safe_free(user);
1737 }
1738
1739 static void
1740 accessLogCommon(AccessLogEntry * al, Logfile * logfile)
1741 {
1742 const char *client = NULL;
1743 char *user1 = NULL, *user2 = NULL;
1744 char buf[MAX_IPSTRLEN];
1745
1746 if (Config.onoff.log_fqdn) {
1747 client = fqdncache_gethostbyaddr(al->cache.caddr, 0);
1748 }
1749
1750 if (client == NULL) {
1751 client = al->cache.caddr.NtoA(buf,MAX_IPSTRLEN);
1752 }
1753
1754 user1 = accessLogFormatName(al->cache.authuser);
1755
1756 user2 = accessLogFormatName(al->cache.rfc931);
1757
1758 logfilePrintf(logfile, "%s %s %s [%s] \"%s %s HTTP/%d.%d\" %d %"PRId64" %s:%s",
1759 client,
1760 user2 ? user2 : dash_str,
1761 user1 ? user1 : dash_str,
1762 mkhttpdlogtime(&squid_curtime),
1763 al->_private.method_str,
1764 al->url,
1765 al->http.version.major, al->http.version.minor,
1766 al->http.code,
1767 al->cache.replySize,
1768 log_tags[al->cache.code],
1769 hier_code_str[al->hier.code]);
1770
1771 safe_free(user1);
1772
1773 safe_free(user2);
1774
1775 if (Config.onoff.log_mime_hdrs) {
1776 char *ereq = log_quote(al->headers.request);
1777 char *erep = log_quote(al->headers.reply);
1778 logfilePrintf(logfile, " [%s] [%s]\n", ereq, erep);
1779 safe_free(ereq);
1780 safe_free(erep);
1781 } else {
1782 logfilePrintf(logfile, "\n");
1783 }
1784
1785 }
1786
1787 #if ICAP_CLIENT
1788 static void
1789 accessLogICAPSquid(AccessLogEntry * al, Logfile * logfile)
1790 {
1791 const char *client = NULL;
1792 const char *user = NULL;
1793 char tmp[MAX_IPSTRLEN], clientbuf[MAX_IPSTRLEN];
1794
1795 if (al->cache.caddr.IsAnyAddr()) { // ICAP OPTIONS xactions lack client
1796 client = "-";
1797 } else {
1798 if (Config.onoff.log_fqdn)
1799 client = fqdncache_gethostbyaddr(al->cache.caddr, FQDN_LOOKUP_IF_MISS);
1800 if (!client)
1801 client = al->cache.caddr.NtoA(clientbuf, MAX_IPSTRLEN);
1802 }
1803
1804 user = accessLogFormatName(al->cache.authuser);
1805
1806 if (!user)
1807 user = accessLogFormatName(al->cache.extuser);
1808
1809 #if USE_SSL
1810
1811 if (!user)
1812 user = accessLogFormatName(al->cache.ssluser);
1813
1814 #endif
1815
1816 if (!user)
1817 user = accessLogFormatName(al->cache.rfc931);
1818
1819 if (user && !*user)
1820 safe_free(user);
1821
1822 logfilePrintf(logfile, "%9ld.%03d %6d %s -/%03d %"PRId64" %s %s %s -/%s -\n",
1823 (long int) current_time.tv_sec,
1824 (int) current_time.tv_usec / 1000,
1825
1826 al->icap.trTime,
1827 client,
1828
1829 al->icap.resStatus,
1830 al->icap.bytesRead,
1831 Adaptation::Icap::ICAP::methodStr(al->icap.reqMethod),
1832 al->icap.reqUri.termedBuf(),
1833 user ? user : dash_str,
1834 al->icap.hostAddr.NtoA(tmp, MAX_IPSTRLEN));
1835 safe_free(user);
1836 }
1837 #endif
1838
1839 void
1840 accessLogLogTo(customlog* log, AccessLogEntry * al, ACLChecklist * checklist)
1841 {
1842
1843 if (al->url == NULL)
1844 al->url = dash_str;
1845
1846 if (!al->http.content_type || *al->http.content_type == '\0')
1847 al->http.content_type = dash_str;
1848
1849 if (al->icp.opcode)
1850 al->_private.method_str = icp_opcode_str[al->icp.opcode];
1851 else if (al->htcp.opcode)
1852 al->_private.method_str = al->htcp.opcode;
1853 else
1854 al->_private.method_str = RequestMethodStr(al->http.method);
1855
1856 if (al->hier.host[0] == '\0')
1857 xstrncpy(al->hier.host, dash_str, SQUIDHOSTNAMELEN);
1858
1859 for (; log; log = log->next) {
1860 if (checklist && log->aclList && !checklist->matchAclListFast(log->aclList))
1861 continue;
1862
1863 switch (log->type) {
1864
1865 case CLF_AUTO:
1866
1867 if (Config.onoff.common_log)
1868 accessLogCommon(al, log->logfile);
1869 else
1870 accessLogSquid(al, log->logfile);
1871
1872 break;
1873
1874 case CLF_SQUID:
1875 accessLogSquid(al, log->logfile);
1876
1877 break;
1878
1879 case CLF_COMMON:
1880 accessLogCommon(al, log->logfile);
1881
1882 break;
1883
1884 case CLF_CUSTOM:
1885 accessLogCustom(al, log);
1886
1887 break;
1888
1889 #if ICAP_CLIENT
1890 case CLF_ICAP_SQUID:
1891 accessLogICAPSquid(al, log->logfile);
1892
1893 break;
1894 #endif
1895
1896 case CLF_NONE:
1897 goto last;
1898
1899 default:
1900 fatalf("Unknown log format %d\n", log->type);
1901
1902 break;
1903 }
1904
1905 logfileFlush(log->logfile);
1906
1907 if (!checklist)
1908 break;
1909 }
1910
1911 last:
1912 (void)0; /* NULL statement for label */
1913 }
1914
1915 void
1916 accessLogLog(AccessLogEntry * al, ACLChecklist * checklist)
1917 {
1918 if (LogfileStatus != LOG_ENABLE)
1919 return;
1920
1921 accessLogLogTo(Config.Log.accesslogs, al, checklist);
1922 #if MULTICAST_MISS_STREAM
1923
1924 if (al->cache.code != LOG_TCP_MISS)
1925 (void) 0;
1926 else if (al->http.method != METHOD_GET)
1927 (void) 0;
1928 else if (mcast_miss_fd < 0)
1929 (void) 0;
1930 else {
1931 unsigned int ibuf[365];
1932 size_t isize;
1933 xstrncpy((char *) ibuf, al->url, 364 * sizeof(int));
1934 isize = ((strlen(al->url) + 8) / 8) * 2;
1935
1936 if (isize > 364)
1937 isize = 364;
1938
1939 mcast_encode((unsigned int *) ibuf, isize,
1940 (const unsigned int *) Config.mcast_miss.encode_key);
1941
1942 comm_udp_sendto(mcast_miss_fd,
1943 &mcast_miss_to, sizeof(mcast_miss_to),
1944 ibuf, isize * sizeof(int));
1945 }
1946
1947 #endif
1948 }
1949
1950 void
1951 accessLogRotate(void)
1952 {
1953 customlog *log;
1954 #if FORW_VIA_DB
1955
1956 fvdbClear();
1957 #endif
1958
1959 for (log = Config.Log.accesslogs; log; log = log->next) {
1960 if (log->logfile) {
1961 logfileRotate(log->logfile);
1962 }
1963 }
1964
1965 #if HEADERS_LOG
1966
1967 logfileRotate(headerslog);
1968
1969 #endif
1970 }
1971
1972 void
1973 accessLogClose(void)
1974 {
1975 customlog *log;
1976
1977 for (log = Config.Log.accesslogs; log; log = log->next) {
1978 if (log->logfile) {
1979 logfileClose(log->logfile);
1980 log->logfile = NULL;
1981 }
1982 }
1983
1984 #if HEADERS_LOG
1985
1986 logfileClose(headerslog);
1987
1988 headerslog = NULL;
1989
1990 #endif
1991 }
1992
1993 HierarchyLogEntry::HierarchyLogEntry() :
1994 code(HIER_NONE),
1995 cd_lookup(LOOKUP_NONE),
1996 n_choices(0),
1997 n_ichoices(0),
1998 peer_reply_status(HTTP_STATUS_NONE),
1999 peer_response_time(-1),
2000 total_response_time(-1)
2001 {
2002 memset(host, '\0', SQUIDHOSTNAMELEN);
2003 memset(cd_host, '\0', SQUIDHOSTNAMELEN);
2004
2005 peer_select_start.tv_sec =0;
2006 peer_select_start.tv_usec =0;
2007
2008 store_complete_stop.tv_sec =0;
2009 store_complete_stop.tv_usec =0;
2010
2011 peer_http_request_sent.tv_sec = 0;
2012 peer_http_request_sent.tv_usec = 0;
2013
2014 first_conn_start.tv_sec = 0;
2015 first_conn_start.tv_usec = 0;
2016 }
2017
2018 void
2019 hierarchyNote(HierarchyLogEntry * hl,
2020 hier_code code,
2021 const char *cache_peer)
2022 {
2023 assert(hl != NULL);
2024 hl->code = code;
2025 xstrncpy(hl->host, cache_peer, SQUIDHOSTNAMELEN);
2026 }
2027
2028 static void
2029 accessLogRegisterWithCacheManager(void)
2030 {
2031 #if FORW_VIA_DB
2032 fvdbRegisterWithCacheManager();
2033 #endif
2034 }
2035
2036 void
2037 accessLogInit(void)
2038 {
2039 customlog *log;
2040
2041 accessLogRegisterWithCacheManager();
2042
2043 assert(sizeof(log_tags) == (LOG_TYPE_MAX + 1) * sizeof(char *));
2044
2045 for (log = Config.Log.accesslogs; log; log = log->next) {
2046 if (log->type == CLF_NONE)
2047 continue;
2048
2049 log->logfile = logfileOpen(log->filename, MAX_URL << 1, 1);
2050
2051 LogfileStatus = LOG_ENABLE;
2052
2053 #if USE_ADAPTATION || ICAP_CLIENT
2054 alLogformatHasAdaptToken = false;
2055 alLogformatHasIcapToken = false;
2056 for (logformat_token * curr_token = (log->logFormat?log->logFormat->format:NULL); curr_token; curr_token = curr_token->next) {
2057 #if USE_ADAPTATION
2058 if (curr_token->type == LTF_ADAPTATION_SUM_XACT_TIMES ||
2059 curr_token->type == LTF_ADAPTATION_ALL_XACT_TIMES) {
2060 alLogformatHasAdaptToken = true;
2061 }
2062 #endif
2063 #if ICAP_CLIENT
2064 if (curr_token->type == LFT_ICAP_LAST_MATCHED_HEADER ||
2065 curr_token->type == LFT_ICAP_LAST_MATCHED_HEADER_ELEM ||
2066 curr_token->type == LFT_ICAP_LAST_MATCHED_ALL_HEADERS) {
2067 alLogformatHasIcapToken = true;
2068 }
2069 #endif
2070 }
2071 #endif
2072 }
2073
2074 #if HEADERS_LOG
2075
2076 headerslog = logfileOpen("/usr/local/squid/logs/headers.log", 512);
2077
2078 assert(NULL != headerslog);
2079
2080 #endif
2081 #if MULTICAST_MISS_STREAM
2082
2083 if (Config.mcast_miss.addr.s_addr != no_addr.s_addr) {
2084 memset(&mcast_miss_to, '\0', sizeof(mcast_miss_to));
2085 mcast_miss_to.sin_family = AF_INET;
2086 mcast_miss_to.sin_port = htons(Config.mcast_miss.port);
2087 mcast_miss_to.sin_addr.s_addr = Config.mcast_miss.addr.s_addr;
2088 mcast_miss_fd = comm_open(SOCK_DGRAM,
2089 IPPROTO_UDP,
2090 Config.Addrs.udp_incoming,
2091 Config.mcast_miss.port,
2092 COMM_NONBLOCKING,
2093 "Multicast Miss Stream");
2094
2095 if (mcast_miss_fd < 0)
2096 fatal("Cannot open Multicast Miss Stream Socket");
2097
2098 debugs(46, 1, "Multicast Miss Stream Socket opened on FD " << mcast_miss_fd);
2099
2100 mcastSetTtl(mcast_miss_fd, Config.mcast_miss.ttl);
2101
2102 if (strlen(Config.mcast_miss.encode_key) < 16)
2103 fatal("mcast_encode_key is too short, must be 16 characters");
2104 }
2105
2106 #endif
2107 #if FORW_VIA_DB
2108
2109 fvdbInit();
2110
2111 #endif
2112 }
2113
2114 const char *
2115 accessLogTime(time_t t)
2116 {
2117
2118 struct tm *tm;
2119 static char buf[128];
2120 static time_t last_t = 0;
2121
2122 if (t != last_t) {
2123 tm = localtime(&t);
2124 strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
2125 last_t = t;
2126 }
2127
2128 return buf;
2129 }
2130
2131
2132 #if FORW_VIA_DB
2133
2134 static void
2135 fvdbInit(void)
2136 {
2137 via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2138 forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2139 }
2140
2141 static void
2142 fvdbRegisterWithCacheManager(void)
2143 {
2144 CacheManager *manager=CacheManager::GetInstance();
2145 manager->registerAction("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
2146 manager->registerAction("forw_headers", "X-Forwarded-For Request Headers",
2147 fvdbDumpForw, 0, 1);
2148 }
2149
2150 static void
2151 fvdbCount(hash_table * hash, const char *key)
2152 {
2153 fvdb_entry *fv;
2154
2155 if (NULL == hash)
2156 return;
2157
2158 fv = (fvdb_entry *)hash_lookup(hash, key);
2159
2160 if (NULL == fv) {
2161 fv = static_cast <fvdb_entry *>(xcalloc(1, sizeof(fvdb_entry)));
2162 fv->hash.key = xstrdup(key);
2163 hash_join(hash, &fv->hash);
2164 }
2165
2166 fv->n++;
2167 }
2168
2169 void
2170 fvdbCountVia(const char *key)
2171 {
2172 fvdbCount(via_table, key);
2173 }
2174
2175 void
2176 fvdbCountForw(const char *key)
2177 {
2178 fvdbCount(forw_table, key);
2179 }
2180
2181 static void
2182 fvdbDumpTable(StoreEntry * e, hash_table * hash)
2183 {
2184 hash_link *h;
2185 fvdb_entry *fv;
2186
2187 if (hash == NULL)
2188 return;
2189
2190 hash_first(hash);
2191
2192 while ((h = hash_next(hash))) {
2193 fv = (fvdb_entry *) h;
2194 storeAppendPrintf(e, "%9d %s\n", fv->n, hashKeyStr(&fv->hash));
2195 }
2196 }
2197
2198 static void
2199 fvdbDumpVia(StoreEntry * e)
2200 {
2201 fvdbDumpTable(e, via_table);
2202 }
2203
2204 static void
2205 fvdbDumpForw(StoreEntry * e)
2206 {
2207 fvdbDumpTable(e, forw_table);
2208 }
2209
2210 static
2211 void
2212 fvdbFreeEntry(void *data)
2213 {
2214 fvdb_entry *fv = static_cast <fvdb_entry *>(data);
2215 xfree(fv->hash.key);
2216 xfree(fv);
2217 }
2218
2219 static void
2220 fvdbClear(void)
2221 {
2222 hashFreeItems(via_table, fvdbFreeEntry);
2223 hashFreeMemory(via_table);
2224 via_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2225 hashFreeItems(forw_table, fvdbFreeEntry);
2226 hashFreeMemory(forw_table);
2227 forw_table = hash_create((HASHCMP *) strcmp, 977, hash4);
2228 }
2229
2230 #endif
2231
2232 #if MULTICAST_MISS_STREAM
2233 /*
2234 * From http://www.io.com/~paulhart/game/algorithms/tea.html
2235 *
2236 * size of 'ibuf' must be a multiple of 2.
2237 * size of 'key' must be 4.
2238 * 'ibuf' is modified in place, encrypted data is written in
2239 * network byte order.
2240 */
2241 static void
2242 mcast_encode(unsigned int *ibuf, size_t isize, const unsigned int *key)
2243 {
2244 unsigned int y;
2245 unsigned int z;
2246 unsigned int sum;
2247 const unsigned int delta = 0x9e3779b9;
2248 unsigned int n = 32;
2249 const unsigned int k0 = htonl(key[0]);
2250 const unsigned int k1 = htonl(key[1]);
2251 const unsigned int k2 = htonl(key[2]);
2252 const unsigned int k3 = htonl(key[3]);
2253 int i;
2254
2255 for (i = 0; i < isize; i += 2) {
2256 y = htonl(ibuf[i]);
2257 z = htonl(ibuf[i + 1]);
2258 sum = 0;
2259
2260 for (n = 32; n; n--) {
2261 sum += delta;
2262 y += (z << 4) + (k0 ^ z) + (sum ^ (z >> 5)) + k1;
2263 z += (y << 4) + (k2 ^ y) + (sum ^ (y >> 5)) + k3;
2264 }
2265
2266 ibuf[i] = htonl(y);
2267 ibuf[i + 1] = htonl(z);
2268 }
2269 }
2270
2271 #endif
2272
2273 #if HEADERS_LOG
2274 void
2275 headersLog(int cs, int pq, const HttpRequestMethod& method, void *data)
2276 {
2277 HttpReply *rep;
2278 HttpRequest *req;
2279 unsigned short magic = 0;
2280 unsigned char M = (unsigned char) m;
2281 unsigned short S;
2282 char *hmask;
2283 int ccmask = 0;
2284
2285 if (0 == pq) {
2286 /* reply */
2287 rep = data;
2288 req = NULL;
2289 magic = 0x0050;
2290 hmask = rep->header.mask;
2291
2292 if (rep->cache_control)
2293 ccmask = rep->cache_control->mask;
2294 } else {
2295 /* request */
2296 req = data;
2297 rep = NULL;
2298 magic = 0x0051;
2299 hmask = req->header.mask;
2300
2301 if (req->cache_control)
2302 ccmask = req->cache_control->mask;
2303 }
2304
2305 if (0 == cs) {
2306 /* client */
2307 magic |= 0x4300;
2308 } else {
2309 /* server */
2310 magic |= 0x5300;
2311 }
2312
2313 magic = htons(magic);
2314 ccmask = htonl(ccmask);
2315
2316 if (0 == pq)
2317 S = (unsigned short) rep->sline.status;
2318 else
2319 S = (unsigned short) HTTP_STATUS_NONE;
2320
2321 logfileWrite(headerslog, &magic, sizeof(magic));
2322
2323 logfileWrite(headerslog, &M, sizeof(M));
2324
2325 logfileWrite(headerslog, &S, sizeof(S));
2326
2327 logfileWrite(headerslog, hmask, sizeof(HttpHeaderMask));
2328
2329 logfileWrite(headerslog, &ccmask, sizeof(int));
2330
2331 logfileFlush(headerslog);
2332 }
2333
2334 #endif
2335
2336 void
2337 accessLogFreeMemory(AccessLogEntry * aLogEntry)
2338 {
2339 safe_free(aLogEntry->headers.request);
2340
2341 #if ICAP_CLIENT
2342 safe_free(aLogEntry->headers.icap);
2343 #endif
2344
2345 safe_free(aLogEntry->headers.reply);
2346 safe_free(aLogEntry->cache.authuser);
2347
2348 HTTPMSGUNLOCK(aLogEntry->reply);
2349 HTTPMSGUNLOCK(aLogEntry->request);
2350 #if ICAP_CLIENT
2351 HTTPMSGUNLOCK(aLogEntry->icap.reply);
2352 HTTPMSGUNLOCK(aLogEntry->icap.request);
2353 #endif
2354 }
2355
2356 int
2357 logTypeIsATcpHit(log_type code)
2358 {
2359 /* this should be a bitmap for better optimization */
2360
2361 if (code == LOG_TCP_HIT)
2362 return 1;
2363
2364 if (code == LOG_TCP_IMS_HIT)
2365 return 1;
2366
2367 if (code == LOG_TCP_REFRESH_FAIL)
2368 return 1;
2369
2370 if (code == LOG_TCP_REFRESH_UNMODIFIED)
2371 return 1;
2372
2373 if (code == LOG_TCP_NEGATIVE_HIT)
2374 return 1;
2375
2376 if (code == LOG_TCP_MEM_HIT)
2377 return 1;
2378
2379 if (code == LOG_TCP_OFFLINE_HIT)
2380 return 1;
2381
2382 return 0;
2383 }
2384