Token.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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(">handshake", LFT_CLIENT_HANDSHAKE),
145  TokenTableEntry("err_code", LFT_SQUID_ERROR ),
146  TokenTableEntry("err_detail", LFT_SQUID_ERROR_DETAIL ),
147  TokenTableEntry("note", LFT_NOTE ),
148  TokenTableEntry("credentials", LFT_CREDENTIALS),
149  /*
150  * Legacy external_acl_type format tokens
151  */
155  TokenTableEntry("EXT_LOG", LFT_EXT_LOG),
156  TokenTableEntry("EXT_TAG", LFT_TAG),
157  TokenTableEntry("EXT_USER", LFT_USER_EXTERNAL),
168  TokenTableEntry("SRCPORT", LFT_CLIENT_PORT),
169  TokenTableEntry("SRC", LFT_CLIENT_IP_ADDRESS), // keep after longer SRC* tokens
170  TokenTableEntry("TAG", LFT_TAG),
172 #if USE_OPENSSL
175 #endif
176  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
177 };
178 
179 #if USE_ADAPTATION
184  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
185 };
186 #endif
187 
188 #if ICAP_CLIENT
189 static TokenTableEntry TokenTableIcap[] = {
191  TokenTableEntry("tt", LFT_ICAP_TOTAL_TIME),
192  TokenTableEntry("<last_h", LFT_ADAPTATION_LAST_HEADER), // deprecated
193 
194  TokenTableEntry("<A", LFT_ICAP_ADDR),
195  TokenTableEntry("<service_name", LFT_ICAP_SERV_NAME),
196  TokenTableEntry("ru", LFT_ICAP_REQUEST_URI),
197  TokenTableEntry("rm", LFT_ICAP_REQUEST_METHOD),
198  TokenTableEntry(">st", LFT_ICAP_BYTES_SENT),
199  TokenTableEntry("<st", LFT_ICAP_BYTES_READ),
200  TokenTableEntry("<bs", LFT_ICAP_BODY_BYTES_READ),
201 
202  TokenTableEntry(">h", LFT_ICAP_REQ_HEADER),
203  TokenTableEntry("<h", LFT_ICAP_REP_HEADER),
204 
205  TokenTableEntry("tr", LFT_ICAP_TR_RESPONSE_TIME),
206  TokenTableEntry("tio", LFT_ICAP_IO_TIME),
207  TokenTableEntry("to", LFT_ICAP_OUTCOME),
208  TokenTableEntry("Hs", LFT_ICAP_STATUS_CODE),
209 
210  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
211 };
212 #endif
213 
214 #if USE_OPENSSL
215 // TLS/SSL (tls:: or ssl::) tokens
217  TokenTableEntry("bump_mode", LFT_SSL_BUMP_MODE),
218  TokenTableEntry(">cert_subject", LFT_SSL_USER_CERT_SUBJECT),
219  TokenTableEntry(">cert_issuer", LFT_SSL_USER_CERT_ISSUER),
224  TokenTableEntry(">negotiated_version", LFT_TLS_CLIENT_NEGOTIATED_VERSION),
225  TokenTableEntry("<negotiated_version", LFT_TLS_SERVER_NEGOTIATED_VERSION),
226  TokenTableEntry(">negotiated_cipher", LFT_TLS_CLIENT_NEGOTIATED_CIPHER),
227  TokenTableEntry("<negotiated_cipher", LFT_TLS_SERVER_NEGOTIATED_CIPHER),
228  TokenTableEntry(">received_hello_version", LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION),
229  TokenTableEntry("<received_hello_version", LFT_TLS_SERVER_RECEIVED_HELLO_VERSION),
230  TokenTableEntry(">received_supported_version", LFT_TLS_CLIENT_SUPPORTED_VERSION),
231  TokenTableEntry("<received_supported_version", LFT_TLS_SERVER_SUPPORTED_VERSION),
233 };
234 #endif
235 } // namespace Format
236 
238 void
240 {
241  // TODO standard log tokens
242 
243 #if USE_ADAPTATION
245 #endif
246 #if ICAP_CLIENT
248 #endif
249 #if USE_OPENSSL
252 #endif
253 }
254 
257 const char *
259 {
260  for (TokenTableEntry const *lte = table; lte->configTag != NULL; ++lte) {
261  debugs(46, 8, HERE << "compare tokens '" << lte->configTag << "' with '" << cur << "'");
262  if (strncmp(lte->configTag, cur, strlen(lte->configTag)) == 0) {
263  type = lte->tokenType;
264  label = lte->configTag;
265  debugs(46, 7, HERE << "Found token '" << label << "'");
266  return cur + strlen(lte->configTag);
267  }
268  }
269  return cur;
270 }
271 
272 /* parses a single token. Returns the token length in characters,
273  * and fills in the lt item with the token information.
274  * def is for sure null-terminated
275  */
276 int
277 Format::Token::parse(const char *def, Quoting *quoting)
278 {
279  const char *cur = def;
280 
281  int l;
282 
283  l = strcspn(cur, "%");
284 
285  if (l > 0) {
286  char *cp;
287  /* it's a string for sure, until \0 or the next % */
288  cp = (char *)xmalloc(l + 1);
289  xstrncpy(cp, cur, l + 1);
290  type = LFT_STRING;
291  data.string = cp;
292 
293  while (l > 0) {
294  switch (*cur) {
295 
296  case '"':
297 
298  if (*quoting == LOG_QUOTE_NONE)
299  *quoting = LOG_QUOTE_QUOTES;
300  else if (*quoting == LOG_QUOTE_QUOTES)
301  *quoting = LOG_QUOTE_NONE;
302 
303  break;
304 
305  case '[':
306  if (*quoting == LOG_QUOTE_NONE)
307  *quoting = LOG_QUOTE_MIMEBLOB;
308 
309  break;
310 
311  case ']':
312  if (*quoting == LOG_QUOTE_MIMEBLOB)
313  *quoting = LOG_QUOTE_NONE;
314 
315  break;
316  }
317 
318  ++cur;
319  --l;
320  }
321 
322  } else if (*cur) {
323 
324  ++cur;
325 
326  // select quoting style for his particular token
327  switch (*cur) {
328 
329  case '"':
331  ++cur;
332  break;
333 
334  case '\'':
336  ++cur;
337  break;
338 
339  case '[':
341  ++cur;
342  break;
343 
344  case '#':
346  ++cur;
347  break;
348 
349  case '/':
351  ++cur;
352  break;
353 
354  default:
355  quote = *quoting;
356  break;
357  }
358 
359  if (*cur == '-') {
360  left = true;
361  ++cur;
362  }
363 
364  if (*cur == '0') {
365  zero = true;
366  ++cur;
367  }
368 
369  char *endp;
370  if (xisdigit(*cur)) {
371  widthMin = strtol(cur, &endp, 10);
372  cur = endp;
373  }
374 
375  if (*cur == '.' && xisdigit(*(++cur))) {
376  widthMax = strtol(cur, &endp, 10);
377  cur = endp;
378  }
379 
380  // when {arg} field is before the token (old logformat syntax)
381  if (*cur == '{') {
382  char *cp;
383  ++cur;
384  l = strcspn(cur, "}");
385  cp = (char *)xmalloc(l + 1);
386  xstrncpy(cp, cur, l + 1);
387  data.string = cp;
388  cur += l;
389 
390  if (*cur == '}')
391  ++cur;
392  }
393 
394  type = LFT_NONE;
395 
396  // Scan each registered token namespace
397  debugs(46, 9, "check for token in " << TheConfig.tokens.size() << " namespaces.");
398  for (const auto &itr : TheConfig.tokens) {
399  debugs(46, 7, "check for possible " << itr.prefix << ":: token");
400  const size_t len = itr.prefix.length();
401  if (itr.prefix.cmp(cur, len) == 0 && cur[len] == ':' && cur[len+1] == ':') {
402  debugs(46, 5, "check for " << itr.prefix << ":: token in '" << cur << "'");
403  const char *old = cur;
404  cur = scanForToken(itr.tokenSet, cur+len+2);
405  if (old != cur) // found
406  break;
407  else // reset to start of namespace
408  cur = cur - len - 2;
409  }
410  }
411 
412  if (type == LFT_NONE) {
413  // For upward compatibility, assume "http::" prefix as default prefix
414  // for all log access formatting codes, except those starting with a
415  // "%" or a known namespace. (ie "icap::", "adapt::")
416  if (strncmp(cur,"http::", 6) == 0 && *(cur+6) != '%' )
417  cur += 6;
418 
419  // NP: scan the sets of tokens in decreasing size to guarantee no
420  // mistakes made with overlapping names. (Bug 3310)
421 
422  // Scan for various long tokens
423  debugs(46, 5, HERE << "scan for possible Misc token");
424  cur = scanForToken(TokenTableMisc, cur);
425  // scan for 2-char tokens
426  if (type == LFT_NONE) {
427  debugs(46, 5, HERE << "scan for possible 2C token");
428  cur = scanForToken(TokenTable2C, cur);
429  }
430  // finally scan for 1-char tokens.
431  if (type == LFT_NONE) {
432  debugs(46, 5, HERE << "scan for possible 1C token");
433  cur = scanForToken(TokenTable1C, cur);
434  }
435  }
436 
437  if (type == LFT_NONE) {
438  fatalf("Can't parse configuration token: '%s'\n", def);
439  }
440 
441  // when {arg} field is after the token (old external_acl_type token syntax)
442  // but accept only if there was none before the token
443  if (*cur == '{' && !data.string) {
444  char *cp;
445  ++cur;
446  l = strcspn(cur, "}");
447  cp = (char *)xmalloc(l + 1);
448  xstrncpy(cp, cur, l + 1);
449  data.string = cp;
450  cur += l;
451 
452  if (*cur == '}')
453  ++cur;
454  }
455 
456  if (*cur == ' ') {
457  space = true;
458  ++cur;
459  }
460  }
461 
462  switch (type) {
463 
464 #if USE_ADAPTATION
466 #endif
467 
468 #if ICAP_CLIENT
469  case LFT_ICAP_REQ_HEADER:
470 
471  case LFT_ICAP_REP_HEADER:
472 #endif
473 
475 
476  case LFT_REQUEST_HEADER:
477 
478  case LFT_REPLY_HEADER:
479 
480  case LFT_NOTE:
481 
482  if (data.string) {
483  char *header = data.string;
484  char *cp = strchr(header, ':');
485 
486  if (cp) {
487  *cp = '\0';
488  ++cp;
489 
490  if (*cp == ',' || *cp == ';' || *cp == ':') {
491  data.header.separator = *cp;
492  ++cp;
493  } else {
494  data.header.separator = ',';
495  }
496 
497  data.header.element = cp;
498 
499  switch (type) {
500  case LFT_REQUEST_HEADER:
502  break;
503 
506  break;
507 
508  case LFT_REPLY_HEADER:
510  break;
511 #if USE_ADAPTATION
514  break;
515 #endif
516 #if ICAP_CLIENT
517  case LFT_ICAP_REQ_HEADER:
519  break;
520  case LFT_ICAP_REP_HEADER:
522  break;
523 #endif
524  default:
525  break;
526  }
527  }
528 
529  data.header.header = header;
530  } else {
531  switch (type) {
532  case LFT_REQUEST_HEADER:
534  break;
535 
538  break;
539 
540  case LFT_REPLY_HEADER:
542  break;
543 #if USE_ADAPTATION
546  break;
547 #endif
548 #if ICAP_CLIENT
549  case LFT_ICAP_REQ_HEADER:
551  break;
552  case LFT_ICAP_REP_HEADER:
554  break;
555 #endif
556  default:
557  break;
558  }
560  }
561 
562  break;
563 
564  case LFT_CLIENT_FQDN:
565  Config.onoff.log_fqdn = 1;
566  break;
567 
571  case LFT_DNS_WAIT_TIME:
572 #if ICAP_CLIENT
574  case LFT_ICAP_IO_TIME:
575  case LFT_ICAP_TOTAL_TIME:
576 #endif
577  case LFT_TIME_START:
578  case LFT_TIME_SUBSECOND:
579  divisor = 1000;
580 
581  if (widthMax > 0) {
582  divisor = 1000000;
583 
584  for (int i = widthMax; i > 0; --i)
585  divisor /= 10;
586 
587  if (!divisor)
588  divisor = 1;
589  }
590  break;
591 
593  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"Hs\" formatting code is deprecated. Use the \">Hs\" instead.");
595  break;
596 
598  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"oa\" formatting code is deprecated. Use the \"<la\" instead.");
600  break;
601 
603  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"rp\" formatting code is deprecated. Use the \">rp\" instead.");
605  break;
606 
608  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \">v\" formatting code is deprecated. Use the \">rv\" instead.");
610  break;
611 
612 #if !USE_SQUID_EUI
613  case LFT_CLIENT_EUI:
614  debugs(46, DBG_CRITICAL, "WARNING: The \">eui\" formatting code requires EUI features which are disabled in this Squid.");
615  break;
616 #endif
617 
618 #if USE_OPENSSL
623  break;
624 #endif
625 
627  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"rG\" formatting code is deprecated. Use \"note{urlgroup}\" instead.");
628  type = LFT_NOTE;
629  data.header.header = xstrdup("urlgroup");
630  break;
631 
632  default:
633  break;
634  }
635 
636  return (cur - def);
637 }
638 
640  label(NULL),
641  widthMin(-1),
642  widthMax(-1),
644  left(false),
645  space(false),
646  zero(false),
647  divisor(1),
648  next(NULL)
649 {
650  data.string = NULL;
651  data.header.header = NULL;
652  data.header.element = NULL;
653  data.header.separator = ',';
654 }
655 
657 {
658  label = NULL; // drop reference to global static.
659  safe_free(data.string);
660  while (next) {
661  Token *tokens = next;
662  next = next->next;
663  tokens->next = NULL;
664  delete tokens;
665  }
666 }
667 
const char * scanForToken(TokenTableEntry const table[], const char *cur)
Definition: Token.cc:258
int type
Definition: errorpage.cc:78
Definition: SBuf.h:86
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:277
struct tok * next
Definition: parse.c:165
One entry in a table of format tokens.
#define DBG_CRITICAL
Definition: Debug.h:45
std::list< TokenNamespace > tokens
list of token namespaces registered
Definition: Config.h:64
#define DBG_PARSE_NOTE(x)
Definition: Debug.h:50
static TokenTableEntry TokenTableIcap[]
ICAP (icap::) tokens.
Definition: Token.cc:190
Quoting
Quoting style for a format output.
Definition: ByteCode.h:251
static TokenTableEntry TokenTableAdapt[]
Definition: Token.cc:180
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
void const char HLPCB void * data
Definition: stub_helper.cc:16
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define DBG_IMPORTANT
Definition: Debug.h:46
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:216
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
int log_mime_hdrs
Definition: SquidConfig.h:286
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
struct SquidConfig::@112 onoff
#define xmalloc
static void Init()
Initialize the format token registrations.
Definition: Token.cc:239
#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:345
#define false
Definition: GnuRegex.c:233

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors