Token.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #include "squid.h"
10 #include "format/Config.h"
11 #include "format/Token.h"
12 #include "format/TokenTableEntry.h"
13 #include "globals.h"
14 #include "SquidConfig.h"
15 #include "Store.h"
16 
17 // Due to token overlaps between 1 and 2 letter tokens (Bug 3310)
18 // We split the token table into sets determined by the token length
19 namespace Format
20 {
21 
24 
28 
32 
37 
39 
41 
42  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
43 };
44 
47 
52  /*TokenTableEntry( "lA", LFT_LOCAL_NAME ), */
53 
57 
64 
68 
71 
74  /*TokenTableEntry( "ur", LFT_USER_REALM ), */
75  /*TokenTableEntry( "us", LFT_USER_SCHEME ), */
78 
82  /*TokenTableEntry( "Ht", LFT_HTTP_STATUS ), */
84 
87 
89 
96  /*TokenTableEntry(">rq", LFT_CLIENT_REQ_QUERY),*/
98 
100  TokenTableEntry("ru", LFT_REQUEST_URI), /* doesn't include the query-string */
102  /* TokenTableEntry( "rq", LFT_REQUEST_QUERY ), * / / * the query-string, INCLUDING the leading ? */
105 
112  /*TokenTableEntry("<rq", LFT_SERVER_REQ_QUERY),*/
114 
117  /*TokenTableEntry( ">sb", LFT_REQUEST_SIZE_BODY ), */
118  /*TokenTableEntry( ">sB", LFT_REQUEST_SIZE_BODY_NO_TE ), */
119 
120  TokenTableEntry("<st", LFT_ADAPTED_REPLY_SIZE_TOTAL), // XXX: adapted should be code: <sta
123  TokenTableEntry("<sh", LFT_ADAPTED_REPLY_SIZE_HEADERS ), // XXX: adapted should be code: <sha
124  /*TokenTableEntry( "<sb", LFT_REPLY_SIZE_BODY ), */
125  /*TokenTableEntry( "<sB", LFT_REPLY_SIZE_BODY_NO_TE ), */
126 
127  TokenTableEntry("st", LFT_CLIENT_IO_SIZE_TOTAL), // XXX: total from client should be stC ??
128  /*TokenTableEntry("stP", LFT_SERVER_IO_SIZE_TOTAL),*/
129 
130  TokenTableEntry("et", LFT_TAG),
133 
134  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
135 };
136 
144  TokenTableEntry("err_code", LFT_SQUID_ERROR ),
145  TokenTableEntry("err_detail", LFT_SQUID_ERROR_DETAIL ),
146  TokenTableEntry("note", LFT_NOTE ),
147  TokenTableEntry("credentials", LFT_CREDENTIALS),
148  /*
149  * Legacy external_acl_type format tokens
150  */
154  TokenTableEntry("EXT_LOG", LFT_EXT_LOG),
155  TokenTableEntry("EXT_TAG", LFT_TAG),
156  TokenTableEntry("EXT_USER", LFT_USER_EXTERNAL),
167  TokenTableEntry("SRCPORT", LFT_CLIENT_PORT),
168  TokenTableEntry("SRC", LFT_CLIENT_IP_ADDRESS), // keep after longer SRC* tokens
169  TokenTableEntry("TAG", LFT_TAG),
171 #if USE_OPENSSL
174 #endif
175  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
176 };
177 
178 #if USE_ADAPTATION
183  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
184 };
185 #endif
186 
187 #if ICAP_CLIENT
188 static TokenTableEntry TokenTableIcap[] = {
190  TokenTableEntry("tt", LFT_ICAP_TOTAL_TIME),
191  TokenTableEntry("<last_h", LFT_ADAPTATION_LAST_HEADER), // deprecated
192 
193  TokenTableEntry("<A", LFT_ICAP_ADDR),
194  TokenTableEntry("<service_name", LFT_ICAP_SERV_NAME),
195  TokenTableEntry("ru", LFT_ICAP_REQUEST_URI),
196  TokenTableEntry("rm", LFT_ICAP_REQUEST_METHOD),
197  TokenTableEntry(">st", LFT_ICAP_BYTES_SENT),
198  TokenTableEntry("<st", LFT_ICAP_BYTES_READ),
199  TokenTableEntry("<bs", LFT_ICAP_BODY_BYTES_READ),
200 
201  TokenTableEntry(">h", LFT_ICAP_REQ_HEADER),
202  TokenTableEntry("<h", LFT_ICAP_REP_HEADER),
203 
204  TokenTableEntry("tr", LFT_ICAP_TR_RESPONSE_TIME),
205  TokenTableEntry("tio", LFT_ICAP_IO_TIME),
206  TokenTableEntry("to", LFT_ICAP_OUTCOME),
207  TokenTableEntry("Hs", LFT_ICAP_STATUS_CODE),
208 
209  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
210 };
211 #endif
212 
213 #if USE_OPENSSL
214 // TLS/SSL (tls:: or ssl::) tokens
216  TokenTableEntry("bump_mode", LFT_SSL_BUMP_MODE),
217  TokenTableEntry(">cert_subject", LFT_SSL_USER_CERT_SUBJECT),
218  TokenTableEntry(">cert_issuer", LFT_SSL_USER_CERT_ISSUER),
223  TokenTableEntry(">negotiated_version", LFT_TLS_CLIENT_NEGOTIATED_VERSION),
224  TokenTableEntry("<negotiated_version", LFT_TLS_SERVER_NEGOTIATED_VERSION),
225  TokenTableEntry(">negotiated_cipher", LFT_TLS_CLIENT_NEGOTIATED_CIPHER),
226  TokenTableEntry("<negotiated_cipher", LFT_TLS_SERVER_NEGOTIATED_CIPHER),
227  TokenTableEntry(">received_hello_version", LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION),
228  TokenTableEntry("<received_hello_version", LFT_TLS_SERVER_RECEIVED_HELLO_VERSION),
229  TokenTableEntry(">received_supported_version", LFT_TLS_CLIENT_SUPPORTED_VERSION),
230  TokenTableEntry("<received_supported_version", LFT_TLS_SERVER_SUPPORTED_VERSION),
232 };
233 #endif
234 } // namespace Format
235 
237 void
239 {
240  // TODO standard log tokens
241 
242 #if USE_ADAPTATION
244 #endif
245 #if ICAP_CLIENT
247 #endif
248 #if USE_OPENSSL
251 #endif
252 }
253 
256 const char *
258 {
259  for (TokenTableEntry const *lte = table; lte->configTag != NULL; ++lte) {
260  debugs(46, 8, HERE << "compare tokens '" << lte->configTag << "' with '" << cur << "'");
261  if (strncmp(lte->configTag, cur, strlen(lte->configTag)) == 0) {
262  type = lte->tokenType;
263  label = lte->configTag;
264  debugs(46, 7, HERE << "Found token '" << label << "'");
265  return cur + strlen(lte->configTag);
266  }
267  }
268  return cur;
269 }
270 
271 /* parses a single token. Returns the token length in characters,
272  * and fills in the lt item with the token information.
273  * def is for sure null-terminated
274  */
275 int
276 Format::Token::parse(const char *def, Quoting *quoting)
277 {
278  const char *cur = def;
279 
280  int l;
281 
282  l = strcspn(cur, "%");
283 
284  if (l > 0) {
285  char *cp;
286  /* it's a string for sure, until \0 or the next % */
287  cp = (char *)xmalloc(l + 1);
288  xstrncpy(cp, cur, l + 1);
289  type = LFT_STRING;
290  data.string = cp;
291 
292  while (l > 0) {
293  switch (*cur) {
294 
295  case '"':
296 
297  if (*quoting == LOG_QUOTE_NONE)
298  *quoting = LOG_QUOTE_QUOTES;
299  else if (*quoting == LOG_QUOTE_QUOTES)
300  *quoting = LOG_QUOTE_NONE;
301 
302  break;
303 
304  case '[':
305  if (*quoting == LOG_QUOTE_NONE)
306  *quoting = LOG_QUOTE_MIMEBLOB;
307 
308  break;
309 
310  case ']':
311  if (*quoting == LOG_QUOTE_MIMEBLOB)
312  *quoting = LOG_QUOTE_NONE;
313 
314  break;
315  }
316 
317  ++cur;
318  --l;
319  }
320 
321  } else if (*cur) {
322 
323  ++cur;
324 
325  // select quoting style for his particular token
326  switch (*cur) {
327 
328  case '"':
330  ++cur;
331  break;
332 
333  case '\'':
335  ++cur;
336  break;
337 
338  case '[':
340  ++cur;
341  break;
342 
343  case '#':
345  ++cur;
346  break;
347 
348  case '/':
350  ++cur;
351  break;
352 
353  default:
354  quote = *quoting;
355  break;
356  }
357 
358  if (*cur == '-') {
359  left = true;
360  ++cur;
361  }
362 
363  if (*cur == '0') {
364  zero = true;
365  ++cur;
366  }
367 
368  char *endp;
369  if (xisdigit(*cur)) {
370  widthMin = strtol(cur, &endp, 10);
371  cur = endp;
372  }
373 
374  if (*cur == '.' && xisdigit(*(++cur))) {
375  widthMax = strtol(cur, &endp, 10);
376  cur = endp;
377  }
378 
379  // when {arg} field is before the token (old logformat syntax)
380  if (*cur == '{') {
381  char *cp;
382  ++cur;
383  l = strcspn(cur, "}");
384  cp = (char *)xmalloc(l + 1);
385  xstrncpy(cp, cur, l + 1);
386  data.string = cp;
387  cur += l;
388 
389  if (*cur == '}')
390  ++cur;
391  }
392 
393  type = LFT_NONE;
394 
395  // Scan each registered token namespace
396  debugs(46, 9, "check for token in " << TheConfig.tokens.size() << " namespaces.");
397  for (const auto &itr : TheConfig.tokens) {
398  debugs(46, 7, "check for possible " << itr.prefix << ":: token");
399  const size_t len = itr.prefix.length();
400  if (itr.prefix.cmp(cur, len) == 0 && cur[len] == ':' && cur[len+1] == ':') {
401  debugs(46, 5, "check for " << itr.prefix << ":: token in '" << cur << "'");
402  const char *old = cur;
403  cur = scanForToken(itr.tokenSet, cur+len+2);
404  if (old != cur) // found
405  break;
406  else // reset to start of namespace
407  cur = cur - len - 2;
408  }
409  }
410 
411  if (type == LFT_NONE) {
412  // For upward compatibility, assume "http::" prefix as default prefix
413  // for all log access formatting codes, except those starting with a
414  // "%" or a known namespace. (ie "icap::", "adapt::")
415  if (strncmp(cur,"http::", 6) == 0 && *(cur+6) != '%' )
416  cur += 6;
417 
418  // NP: scan the sets of tokens in decreasing size to guarantee no
419  // mistakes made with overlapping names. (Bug 3310)
420 
421  // Scan for various long tokens
422  debugs(46, 5, HERE << "scan for possible Misc token");
423  cur = scanForToken(TokenTableMisc, cur);
424  // scan for 2-char tokens
425  if (type == LFT_NONE) {
426  debugs(46, 5, HERE << "scan for possible 2C token");
427  cur = scanForToken(TokenTable2C, cur);
428  }
429  // finally scan for 1-char tokens.
430  if (type == LFT_NONE) {
431  debugs(46, 5, HERE << "scan for possible 1C token");
432  cur = scanForToken(TokenTable1C, cur);
433  }
434  }
435 
436  if (type == LFT_NONE) {
437  fatalf("Can't parse configuration token: '%s'\n", def);
438  }
439 
440  // when {arg} field is after the token (old external_acl_type token syntax)
441  // but accept only if there was none before the token
442  if (*cur == '{' && !data.string) {
443  char *cp;
444  ++cur;
445  l = strcspn(cur, "}");
446  cp = (char *)xmalloc(l + 1);
447  xstrncpy(cp, cur, l + 1);
448  data.string = cp;
449  cur += l;
450 
451  if (*cur == '}')
452  ++cur;
453  }
454 
455  if (*cur == ' ') {
456  space = true;
457  ++cur;
458  }
459  }
460 
461  switch (type) {
462 
463 #if USE_ADAPTATION
465 #endif
466 
467 #if ICAP_CLIENT
468  case LFT_ICAP_REQ_HEADER:
469 
470  case LFT_ICAP_REP_HEADER:
471 #endif
472 
474 
475  case LFT_REQUEST_HEADER:
476 
477  case LFT_REPLY_HEADER:
478 
479  case LFT_NOTE:
480 
481  if (data.string) {
482  char *header = data.string;
483  char *cp = strchr(header, ':');
484 
485  if (cp) {
486  *cp = '\0';
487  ++cp;
488 
489  if (*cp == ',' || *cp == ';' || *cp == ':') {
490  data.header.separator = *cp;
491  ++cp;
492  } else {
493  data.header.separator = ',';
494  }
495 
496  data.header.element = cp;
497 
498  switch (type) {
499  case LFT_REQUEST_HEADER:
501  break;
502 
505  break;
506 
507  case LFT_REPLY_HEADER:
509  break;
510 #if USE_ADAPTATION
513  break;
514 #endif
515 #if ICAP_CLIENT
516  case LFT_ICAP_REQ_HEADER:
518  break;
519  case LFT_ICAP_REP_HEADER:
521  break;
522 #endif
523  default:
524  break;
525  }
526  }
527 
528  data.header.header = header;
529  } else {
530  switch (type) {
531  case LFT_REQUEST_HEADER:
533  break;
534 
537  break;
538 
539  case LFT_REPLY_HEADER:
541  break;
542 #if USE_ADAPTATION
545  break;
546 #endif
547 #if ICAP_CLIENT
548  case LFT_ICAP_REQ_HEADER:
550  break;
551  case LFT_ICAP_REP_HEADER:
553  break;
554 #endif
555  default:
556  break;
557  }
559  }
560 
561  break;
562 
563  case LFT_CLIENT_FQDN:
564  Config.onoff.log_fqdn = 1;
565  break;
566 
570  case LFT_DNS_WAIT_TIME:
571 #if ICAP_CLIENT
573  case LFT_ICAP_IO_TIME:
574  case LFT_ICAP_TOTAL_TIME:
575 #endif
576  case LFT_TIME_START:
577  case LFT_TIME_SUBSECOND:
578  divisor = 1000;
579 
580  if (widthMax > 0) {
581  divisor = 1000000;
582 
583  for (int i = widthMax; i > 0; --i)
584  divisor /= 10;
585 
586  if (!divisor)
587  divisor = 1;
588  }
589  break;
590 
592  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"Hs\" formatting code is deprecated. Use the \">Hs\" instead.");
594  break;
595 
597  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"oa\" formatting code is deprecated. Use the \"<la\" instead.");
599  break;
600 
602  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"rp\" formatting code is deprecated. Use the \">rp\" instead.");
604  break;
605 
607  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \">v\" formatting code is deprecated. Use the \">rv\" instead.");
609  break;
610 
611 #if !USE_SQUID_EUI
612  case LFT_CLIENT_EUI:
613  debugs(46, DBG_CRITICAL, "WARNING: The \">eui\" formatting code requires EUI features which are disabled in this Squid.");
614  break;
615 #endif
616 
617 #if USE_OPENSSL
622  break;
623 #endif
624 
626  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"rG\" formatting code is deprecated. Use \"note{urlgroup}\" instead.");
627  type = LFT_NOTE;
628  data.header.header = xstrdup("urlgroup");
629  break;
630 
631  default:
632  break;
633  }
634 
635  return (cur - def);
636 }
637 
639  label(NULL),
640  widthMin(-1),
641  widthMax(-1),
643  left(false),
644  space(false),
645  zero(false),
646  divisor(1),
647  next(NULL)
648 {
649  data.string = NULL;
650  data.header.header = NULL;
651  data.header.element = NULL;
652  data.header.separator = ',';
653 }
654 
656 {
657  label = NULL; // drop reference to global static.
658  safe_free(data.string);
659  while (next) {
660  Token *tokens = next;
661  next = next->next;
662  tokens->next = NULL;
663  delete tokens;
664  }
665 }
666 
const char * scanForToken(TokenTableEntry const table[], const char *cur)
Definition: Token.cc:257
int type
Definition: errorpage.cc:79
Definition: SBuf.h:87
Token * next
Definition: Token.h:67
static TokenTableEntry TokenTable2C[]
2-char tokens
Definition: Token.cc:46
int i
Definition: membanger.c:49
#define xstrdup
static TokenTableEntry TokenTable1C[]
1-char tokens.
Definition: Token.cc:23
#define safe_free(x)
Definition: xalloc.h:73
int parse(const char *def, enum Quoting *quote)
Definition: Token.cc:276
struct tok * next
Definition: parse.c:165
One entry in a table of format tokens.
#define DBG_CRITICAL
Definition: Debug.h:44
std::list< TokenNamespace > tokens
list of token namespaces registered
Definition: Config.h:64
#define DBG_PARSE_NOTE(x)
Definition: Debug.h:49
static TokenTableEntry TokenTableIcap[]
ICAP (icap::) tokens.
Definition: Token.cc:189
Quoting
Quoting style for a format output.
Definition: ByteCode.h:249
static TokenTableEntry TokenTableAdapt[]
Definition: Token.cc:179
void fatalf(const char *fmt,...)
Definition: fatal.cc:79
void const char HLPCB void * data
Definition: stub_helper.cc:16
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define DBG_IMPORTANT
Definition: Debug.h:45
static TokenTableEntry TokenTableMisc[]
Miscellaneous >2 byte tokens.
Definition: Token.cc:138
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
FmtConfig TheConfig
Definition: Config.cc:16
void registerTokens(const SBuf &nsName, TokenTableEntry const *tokenArray)
Definition: Config.cc:48
int cur
Definition: ModDevPoll.cc:76
static TokenTableEntry TokenTableSsl[]
Definition: Token.cc:215
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
int log_mime_hdrs
Definition: SquidConfig.h:282
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
struct SquidConfig::@112 onoff
#define xmalloc
static void Init()
Initialize the format token registrations.
Definition: Token.cc:238
#define xisdigit(x)
Definition: xis.h:20
const char * quote
Definition: html_quote.c:21
struct tok tokens[]
Definition: parse.c:168
struct Format::Token::@69 data
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
bool logTlsServerHelloDetails
Definition: SquidConfig.h:341
#define false
Definition: GnuRegex.c:233

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors