2 #include "format/Config.h"
3 #include "format/Token.h"
4 #include "format/TokenTableEntry.h"
6 #include "SquidConfig.h"
9 const char *Format::log_tags
[] = {
13 "TCP_REFRESH_UNMODIFIED",
14 "TCP_REFRESH_FAIL", // same tag logged for LOG_TCP_REFRESH_FAIL_OLD and
15 "TCP_REFRESH_FAIL", // LOG_TCP_REFRESH_FAIL_ERR for backward-compatibility
16 "TCP_REFRESH_MODIFIED",
17 "TCP_CLIENT_REFRESH_MISS",
35 // Due to token overlaps between 1 and 2 letter tokens (Bug 3310)
36 // We split the token table into sets determined by the token length
41 static TokenTableEntry TokenTable1C
[] = {
43 {">a", LFT_CLIENT_IP_ADDRESS
},
44 {">p", LFT_CLIENT_PORT
},
45 {">A", LFT_CLIENT_FQDN
},
47 {"<a", LFT_SERVER_IP_ADDRESS
},
48 {"<p", LFT_SERVER_PORT
},
49 {"<A", LFT_SERVER_FQDN_OR_PEER_NAME
},
51 {">h", LFT_REQUEST_HEADER
},
52 {">h", LFT_REQUEST_ALL_HEADERS
},
53 {"<h", LFT_REPLY_HEADER
},
54 {"<h", LFT_REPLY_ALL_HEADERS
},
56 {">v", LFT_REQUEST_VERSION_OLD_2X
},
60 {NULL
, LFT_NONE
} /* this must be last */
64 static TokenTableEntry TokenTable2C
[] = {
66 {">la", LFT_CLIENT_LOCAL_IP
},
67 {"la", LFT_LOCAL_LISTENING_IP
},
68 {">lp", LFT_CLIENT_LOCAL_PORT
},
69 {"lp", LFT_LOCAL_LISTENING_PORT
},
70 /*{ "lA", LFT_LOCAL_NAME }, */
72 {"<la", LFT_SERVER_LOCAL_IP
},
73 {"oa", LFT_SERVER_LOCAL_IP_OLD_27
},
74 {"<lp", LFT_SERVER_LOCAL_PORT
},
75 /* {"ot", LFT_PEER_OUTGOING_TOS}, */
77 {"ts", LFT_TIME_SECONDS_SINCE_EPOCH
},
78 {"tu", LFT_TIME_SUBSECOND
},
79 {"tl", LFT_TIME_LOCALTIME
},
81 {"tr", LFT_TIME_TO_HANDLE_REQUEST
},
83 {"<pt", LFT_PEER_RESPONSE_TIME
},
84 {"<tt", LFT_TOTAL_SERVER_SIDE_RESPONSE_TIME
},
85 {"dt", LFT_DNS_WAIT_TIME
},
87 {">ha", LFT_ADAPTED_REQUEST_HEADER
},
88 {">ha", LFT_ADAPTED_REQUEST_ALL_HEADERS
},
90 {"un", LFT_USER_NAME
},
91 {"ul", LFT_USER_LOGIN
},
92 /*{ "ur", LFT_USER_REALM }, */
93 /*{ "us", LFT_USER_SCHEME }, */
94 {"ui", LFT_USER_IDENT
},
95 {"ue", LFT_USER_EXTERNAL
},
97 {"Hs", LFT_HTTP_SENT_STATUS_CODE_OLD_30
},
98 {">Hs", LFT_HTTP_SENT_STATUS_CODE
},
99 {"<Hs", LFT_HTTP_RECEIVED_STATUS_CODE
},
100 /*{ "Ht", LFT_HTTP_STATUS }, */
101 {"<bs", LFT_HTTP_BODY_BYTES_READ
},
103 {"Ss", LFT_SQUID_STATUS
},
104 {"Sh", LFT_SQUID_HIERARCHY
},
106 {"mt", LFT_MIME_TYPE
},
108 {">rm", LFT_CLIENT_REQ_METHOD
},
109 {">ru", LFT_CLIENT_REQ_URI
},
110 {">rp", LFT_CLIENT_REQ_URLPATH
},
111 /*{">rq", LFT_CLIENT_REQ_QUERY},*/
112 {">rv", LFT_CLIENT_REQ_VERSION
},
114 {"rm", LFT_REQUEST_METHOD
},
115 {"ru", LFT_REQUEST_URI
}, /* doesn't include the query-string */
116 {"rp", LFT_REQUEST_URLPATH_OLD_31
},
117 /* { "rq", LFT_REQUEST_QUERY }, * / / * the query-string, INCLUDING the leading ? */
118 {"rv", LFT_REQUEST_VERSION
},
120 {"<rm", LFT_SERVER_REQ_METHOD
},
121 {"<ru", LFT_SERVER_REQ_URI
},
122 {"<rp", LFT_SERVER_REQ_URLPATH
},
123 /*{"<rq", LFT_SERVER_REQ_QUERY},*/
124 {"<rv", LFT_SERVER_REQ_VERSION
},
126 {">st", LFT_REQUEST_SIZE_TOTAL
},
127 /*{ ">sl", LFT_REQUEST_SIZE_LINE }, * / / * the request line "GET ... " */
128 {">sh", LFT_REQUEST_SIZE_HEADERS
},
129 /*{ ">sb", LFT_REQUEST_SIZE_BODY }, */
130 /*{ ">sB", LFT_REQUEST_SIZE_BODY_NO_TE }, */
132 {"<st", LFT_REPLY_SIZE_TOTAL
},
133 {"<sH", LFT_REPLY_HIGHOFFSET
},
134 {"<sS", LFT_REPLY_OBJECTSIZE
},
135 /*{ "<sl", LFT_REPLY_SIZE_LINE }, * / / * the reply line (protocol, code, text) */
136 {"<sh", LFT_REPLY_SIZE_HEADERS
},
137 /*{ "<sb", LFT_REPLY_SIZE_BODY }, */
138 /*{ "<sB", LFT_REPLY_SIZE_BODY_NO_TE }, */
141 {"st", LFT_IO_SIZE_TOTAL
},
143 {"sn", LFT_SEQUENCE_NUMBER
},
145 {NULL
, LFT_NONE
} /* this must be last */
148 /// Miscellaneous >2 byte tokens
149 static TokenTableEntry TokenTableMisc
[] = {
150 {">eui", LFT_CLIENT_EUI
},
151 {"err_code", LFT_SQUID_ERROR
},
152 {"err_detail", LFT_SQUID_ERROR_DETAIL
},
154 {NULL
, LFT_NONE
} /* this must be last */
158 static TokenTableEntry TokenTableAdapt
[] = {
159 {"all_trs", LFT_ADAPTATION_ALL_XACT_TIMES
},
160 {"sum_trs", LFT_ADAPTATION_SUM_XACT_TIMES
},
161 {"<last_h", LFT_ADAPTATION_LAST_HEADER
},
162 {NULL
, LFT_NONE
} /* this must be last */
167 /// ICAP (icap::) tokens
168 static TokenTableEntry TokenTableIcap
[] = {
169 {"tt", LFT_ICAP_TOTAL_TIME
},
170 {"<last_h", LFT_ADAPTATION_LAST_HEADER
}, // deprecated
172 {"<A", LFT_ICAP_ADDR
},
173 {"<service_name", LFT_ICAP_SERV_NAME
},
174 {"ru", LFT_ICAP_REQUEST_URI
},
175 {"rm", LFT_ICAP_REQUEST_METHOD
},
176 {">st", LFT_ICAP_BYTES_SENT
},
177 {"<st", LFT_ICAP_BYTES_READ
},
178 {"<bs", LFT_ICAP_BODY_BYTES_READ
},
180 {">h", LFT_ICAP_REQ_HEADER
},
181 {"<h", LFT_ICAP_REP_HEADER
},
183 {"tr", LFT_ICAP_TR_RESPONSE_TIME
},
184 {"tio", LFT_ICAP_IO_TIME
},
185 {"to", LFT_ICAP_OUTCOME
},
186 {"Hs", LFT_ICAP_STATUS_CODE
},
188 {NULL
, LFT_NONE
} /* this must be last */
193 // SSL (ssl::) tokens
194 static TokenTableEntry TokenTableSsl
[] = {
195 {"bump_mode", LFT_SSL_BUMP_MODE
},
196 {">cert_subject", LFT_SSL_USER_CERT_SUBJECT
},
197 {">cert_issuer", LFT_SSL_USER_CERT_ISSUER
},
201 } // namespace Format
203 /// Register all components custom format tokens
205 Format::Token::Init()
207 // TODO standard log tokens
208 // TODO external ACL fmt tokens
211 TheConfig
.registerTokens(String("adapt"),::Format::TokenTableAdapt
);
214 TheConfig
.registerTokens(String("icap"),::Format::TokenTableIcap
);
217 TheConfig
.registerTokens(String("ssl"),::Format::TokenTableSsl
);
221 /// Scans a token table to see if the next token exists there
222 /// returns a pointer to next unparsed byte and updates type member if found
224 Format::Token::scanForToken(TokenTableEntry
const table
[], const char *cur
)
226 for (TokenTableEntry
const *lte
= table
; lte
->configTag
!= NULL
; ++lte
) {
227 debugs(46, 8, HERE
<< "compare tokens '" << lte
->configTag
<< "' with '" << cur
<< "'");
228 if (strncmp(lte
->configTag
, cur
, strlen(lte
->configTag
)) == 0) {
229 type
= lte
->tokenType
;
230 label
= lte
->configTag
;
231 debugs(46, 7, HERE
<< "Found token '" << label
<< "'");
232 return cur
+ strlen(lte
->configTag
);
238 /* parses a single token. Returns the token length in characters,
239 * and fills in the lt item with the token information.
240 * def is for sure null-terminated
243 Format::Token::parse(const char *def
, Quoting
*quoting
)
245 const char *cur
= def
;
249 l
= strcspn(cur
, "%");
253 /* it's a string for sure, until \0 or the next % */
254 cp
= (char *)xmalloc(l
+ 1);
255 xstrncpy(cp
, cur
, l
+ 1);
264 if (*quoting
== LOG_QUOTE_NONE
)
265 *quoting
= LOG_QUOTE_QUOTES
;
266 else if (*quoting
== LOG_QUOTE_QUOTES
)
267 *quoting
= LOG_QUOTE_NONE
;
272 if (*quoting
== LOG_QUOTE_NONE
)
273 *quoting
= LOG_QUOTE_MIMEBLOB
;
278 if (*quoting
== LOG_QUOTE_MIMEBLOB
)
279 *quoting
= LOG_QUOTE_NONE
;
296 // select quoting style for his particular token
300 quote
= LOG_QUOTE_QUOTES
;
305 quote
= LOG_QUOTE_RAW
;
310 quote
= LOG_QUOTE_MIMEBLOB
;
315 quote
= LOG_QUOTE_URL
;
335 if (xisdigit(*cur
)) {
336 widthMin
= strtol(cur
, &endp
, 10);
340 if (*cur
== '.' && xisdigit(*(++cur
))) {
341 widthMax
= strtol(cur
, &endp
, 10);
348 l
= strcspn(cur
, "}");
349 cp
= (char *)xmalloc(l
+ 1);
350 xstrncpy(cp
, cur
, l
+ 1);
360 // Scan each registered token namespace
361 debugs(46, 9, HERE
<< "check for token in " << TheConfig
.tokens
.size() << " namespaces.");
362 for (std::list
<TokenNamespace
>::const_iterator itr
= TheConfig
.tokens
.begin(); itr
!= TheConfig
.tokens
.end(); ++itr
) {
363 debugs(46, 7, HERE
<< "check for possible " << itr
->prefix
<< ":: token");
364 const size_t len
= itr
->prefix
.size();
365 if (itr
->prefix
.cmp(cur
, len
) == 0 && cur
[len
] == ':' && cur
[len
+1] == ':') {
366 debugs(46, 5, HERE
<< "check for " << itr
->prefix
<< ":: token in '" << cur
<< "'");
367 const char *old
= cur
;
368 cur
= scanForToken(itr
->tokenSet
, cur
+len
+2);
369 if (old
!= cur
) // found
371 else // reset to start of namespace
376 if (type
== LFT_NONE
) {
377 // For upward compatibility, assume "http::" prefix as default prefix
378 // for all log access formatting codes, except those starting with a
379 // "%" or a known namespace. (ie "icap::", "adapt::")
380 if (strncmp(cur
,"http::", 6) == 0 && *(cur
+6) != '%' )
383 // NP: scan the sets of tokens in decreasing size to guarantee no
384 // mistakes made with overlapping names. (Bug 3310)
386 // Scan for various long tokens
387 debugs(46, 5, HERE
<< "scan for possible Misc token");
388 cur
= scanForToken(TokenTableMisc
, cur
);
389 // scan for 2-char tokens
390 if (type
== LFT_NONE
) {
391 debugs(46, 5, HERE
<< "scan for possible 2C token");
392 cur
= scanForToken(TokenTable2C
, cur
);
394 // finally scan for 1-char tokens.
395 if (type
== LFT_NONE
) {
396 debugs(46, 5, HERE
<< "scan for possible 1C token");
397 cur
= scanForToken(TokenTable1C
, cur
);
401 if (type
== LFT_NONE
) {
402 fatalf("Can't parse configuration token: '%s'\n", def
);
415 case LFT_ADAPTATION_LAST_HEADER
:
419 case LFT_ICAP_REQ_HEADER
:
421 case LFT_ICAP_REP_HEADER
:
424 case LFT_ADAPTED_REQUEST_HEADER
:
426 case LFT_REQUEST_HEADER
:
428 case LFT_REPLY_HEADER
:
431 char *header
= data
.string
;
432 char *cp
= strchr(header
, ':');
438 if (*cp
== ',' || *cp
== ';' || *cp
== ':') {
439 data
.header
.separator
= *cp
;
442 data
.header
.separator
= ',';
445 data
.header
.element
= cp
;
448 case LFT_REQUEST_HEADER
:
449 type
= LFT_REQUEST_HEADER_ELEM
;
452 case LFT_ADAPTED_REQUEST_HEADER
:
453 type
= LFT_ADAPTED_REQUEST_HEADER_ELEM
;
456 case LFT_REPLY_HEADER
:
457 type
= LFT_REPLY_HEADER_ELEM
;
460 case LFT_ADAPTATION_LAST_HEADER
:
461 type
= LFT_ADAPTATION_LAST_HEADER_ELEM
;
465 case LFT_ICAP_REQ_HEADER
:
466 type
= LFT_ICAP_REQ_HEADER_ELEM
;
468 case LFT_ICAP_REP_HEADER
:
469 type
= LFT_ICAP_REP_HEADER_ELEM
;
477 data
.header
.header
= header
;
480 case LFT_REQUEST_HEADER
:
481 type
= LFT_REQUEST_ALL_HEADERS
;
484 case LFT_ADAPTED_REQUEST_HEADER
:
485 type
= LFT_ADAPTED_REQUEST_ALL_HEADERS
;
488 case LFT_REPLY_HEADER
:
489 type
= LFT_REPLY_ALL_HEADERS
;
492 case LFT_ADAPTATION_LAST_HEADER
:
493 type
= LFT_ADAPTATION_LAST_ALL_HEADERS
;
497 case LFT_ICAP_REQ_HEADER
:
498 type
= LFT_ICAP_REQ_ALL_HEADERS
;
500 case LFT_ICAP_REP_HEADER
:
501 type
= LFT_ICAP_REP_ALL_HEADERS
;
507 Config
.onoff
.log_mime_hdrs
= 1;
512 case LFT_CLIENT_FQDN
:
513 Config
.onoff
.log_fqdn
= 1;
516 case LFT_TIME_SUBSECOND
:
523 for (i
= widthMax
; i
> 1; --i
)
531 case LFT_HTTP_SENT_STATUS_CODE_OLD_30
:
532 debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT
), "WARNING: The \"Hs\" formatting code is deprecated. Use the \">Hs\" instead.");
533 type
= LFT_HTTP_SENT_STATUS_CODE
;
536 case LFT_SERVER_LOCAL_IP_OLD_27
:
537 debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT
), "WARNING: The \"oa\" formatting code is deprecated. Use the \"<la\" instead.");
538 type
= LFT_SERVER_LOCAL_IP
;
541 case LFT_REQUEST_URLPATH_OLD_31
:
542 debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT
), "WARNING: The \"rp\" formatting code is deprecated. Use the \">rp\" instead.");
543 type
= LFT_CLIENT_REQ_URLPATH
;
546 case LFT_REQUEST_VERSION_OLD_2X
:
547 debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT
), "WARNING: The \">v\" formatting code is deprecated. Use the \">rv\" instead.");
548 type
= LFT_REQUEST_VERSION
;
553 debugs(46, DBG_CRITICAL
, "WARNING: The \">eui\" formatting code requires EUI features which are disabled in this Squid.");
564 Format::Token::~Token()
566 label
= NULL
; // drop reference to global static.
567 safe_free(data
.string
);
569 Token
*tokens
= next
;