Token.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 "proxyp/Elements.h"
15 #include "sbuf/Stream.h"
16 #include "SquidConfig.h"
17 #include "Store.h"
18 
19 // Due to token overlaps between 1 and 2 letter tokens (Bug 3310)
20 // We split the token table into sets determined by the token length
21 namespace Format
22 {
23 
26 
30 
34 
39 
41 
43 
44  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
45 };
46 
49 
54  /*TokenTableEntry( "lA", LFT_LOCAL_NAME ), */
55 
59 
66 
70 
73 
76  /*TokenTableEntry( "ur", LFT_USER_REALM ), */
77  /*TokenTableEntry( "us", LFT_USER_SCHEME ), */
80 
84  /*TokenTableEntry( "Ht", LFT_HTTP_STATUS ), */
86 
89 
91 
98  /*TokenTableEntry(">rq", LFT_CLIENT_REQ_QUERY),*/
100 
102  TokenTableEntry("ru", LFT_REQUEST_URI), /* doesn't include the query-string */
104  /* TokenTableEntry( "rq", LFT_REQUEST_QUERY ), * / / * the query-string, INCLUDING the leading ? */
107 
114  /*TokenTableEntry("<rq", LFT_SERVER_REQ_QUERY),*/
116 
119  /*TokenTableEntry( ">sb", LFT_REQUEST_SIZE_BODY ), */
120  /*TokenTableEntry( ">sB", LFT_REQUEST_SIZE_BODY_NO_TE ), */
121 
122  TokenTableEntry("<st", LFT_ADAPTED_REPLY_SIZE_TOTAL), // XXX: adapted should be code: <sta
125  TokenTableEntry("<sh", LFT_ADAPTED_REPLY_SIZE_HEADERS ), // XXX: adapted should be code: <sha
126  /*TokenTableEntry( "<sb", LFT_REPLY_SIZE_BODY ), */
127  /*TokenTableEntry( "<sB", LFT_REPLY_SIZE_BODY_NO_TE ), */
128 
129  TokenTableEntry("st", LFT_CLIENT_IO_SIZE_TOTAL), // XXX: total from client should be stC ??
130  /*TokenTableEntry("stP", LFT_SERVER_IO_SIZE_TOTAL),*/
131 
132  TokenTableEntry("et", LFT_TAG),
135 
136  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
137 };
138 
146  TokenTableEntry(">handshake", LFT_CLIENT_HANDSHAKE),
147  TokenTableEntry("err_code", LFT_SQUID_ERROR ),
148  TokenTableEntry("err_detail", LFT_SQUID_ERROR_DETAIL ),
149  TokenTableEntry("note", LFT_NOTE ),
150  TokenTableEntry("credentials", LFT_CREDENTIALS),
151  TokenTableEntry("master_xaction", LFT_MASTER_XACTION),
152  /*
153  * Legacy external_acl_type format tokens
154  */
158  TokenTableEntry("EXT_LOG", LFT_EXT_LOG),
159  TokenTableEntry("EXT_TAG", LFT_TAG),
160  TokenTableEntry("EXT_USER", LFT_USER_EXTERNAL),
171  TokenTableEntry("SRCPORT", LFT_CLIENT_PORT),
172  TokenTableEntry("SRC", LFT_CLIENT_IP_ADDRESS), // keep after longer SRC* tokens
173  TokenTableEntry("TAG", LFT_TAG),
175 #if USE_OPENSSL
178 #endif
179  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
180 };
181 
184 };
185 
186 #if USE_ADAPTATION
191  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
192 };
193 #endif
194 
195 #if ICAP_CLIENT
196 static TokenTableEntry TokenTableIcap[] = {
199  TokenTableEntry("<last_h", LFT_ADAPTATION_LAST_HEADER), // deprecated
200 
202  TokenTableEntry("<service_name", LFT_ICAP_SERV_NAME),
208 
211 
216 
217  TokenTableEntry(NULL, LFT_NONE) /* this must be last */
218 };
219 #endif
220 
221 #if USE_OPENSSL
222 // TLS/SSL (tls:: or ssl::) tokens
224  TokenTableEntry("bump_mode", LFT_SSL_BUMP_MODE),
225  TokenTableEntry(">cert_subject", LFT_SSL_USER_CERT_SUBJECT),
226  TokenTableEntry(">cert_issuer", LFT_SSL_USER_CERT_ISSUER),
232  TokenTableEntry(">negotiated_version", LFT_TLS_CLIENT_NEGOTIATED_VERSION),
233  TokenTableEntry("<negotiated_version", LFT_TLS_SERVER_NEGOTIATED_VERSION),
234  TokenTableEntry(">negotiated_cipher", LFT_TLS_CLIENT_NEGOTIATED_CIPHER),
235  TokenTableEntry("<negotiated_cipher", LFT_TLS_SERVER_NEGOTIATED_CIPHER),
236  TokenTableEntry(">received_hello_version", LFT_TLS_CLIENT_RECEIVED_HELLO_VERSION),
237  TokenTableEntry("<received_hello_version", LFT_TLS_SERVER_RECEIVED_HELLO_VERSION),
238  TokenTableEntry(">received_supported_version", LFT_TLS_CLIENT_SUPPORTED_VERSION),
239  TokenTableEntry("<received_supported_version", LFT_TLS_SERVER_SUPPORTED_VERSION),
241 };
242 #endif
243 } // namespace Format
244 
246 void
248 {
249  // TODO standard log tokens
250 
251 #if USE_ADAPTATION
253 #endif
254 #if ICAP_CLIENT
256 #endif
257 #if USE_OPENSSL
260 #endif
262 }
263 
266 const char *
268 {
269  for (TokenTableEntry const *lte = table; lte->configTag != NULL; ++lte) {
270  debugs(46, 8, HERE << "compare tokens '" << lte->configTag << "' with '" << cur << "'");
271  if (strncmp(lte->configTag, cur, strlen(lte->configTag)) == 0) {
272  type = lte->tokenType;
273  label = lte->configTag;
274  debugs(46, 7, HERE << "Found token '" << label << "'");
275  return cur + strlen(lte->configTag);
276  }
277  }
278  return cur;
279 }
280 
281 /* parses a single token. Returns the token length in characters,
282  * and fills in the lt item with the token information.
283  * def is for sure null-terminated
284  */
285 int
286 Format::Token::parse(const char *def, Quoting *quoting)
287 {
288  const char *cur = def;
289 
290  int l;
291 
292  l = strcspn(cur, "%");
293 
294  if (l > 0) {
295  char *cp;
296  /* it's a string for sure, until \0 or the next % */
297  cp = (char *)xmalloc(l + 1);
298  xstrncpy(cp, cur, l + 1);
299  type = LFT_STRING;
300  data.string = cp;
301 
302  while (l > 0) {
303  switch (*cur) {
304 
305  case '"':
306 
307  if (*quoting == LOG_QUOTE_NONE)
308  *quoting = LOG_QUOTE_QUOTES;
309  else if (*quoting == LOG_QUOTE_QUOTES)
310  *quoting = LOG_QUOTE_NONE;
311 
312  break;
313 
314  case '[':
315  if (*quoting == LOG_QUOTE_NONE)
316  *quoting = LOG_QUOTE_MIMEBLOB;
317 
318  break;
319 
320  case ']':
321  if (*quoting == LOG_QUOTE_MIMEBLOB)
322  *quoting = LOG_QUOTE_NONE;
323 
324  break;
325  }
326 
327  ++cur;
328  --l;
329  }
330 
331  } else if (*cur) {
332 
333  ++cur;
334 
335  // select quoting style for his particular token
336  switch (*cur) {
337 
338  case '"':
340  ++cur;
341  break;
342 
343  case '\'':
345  ++cur;
346  break;
347 
348  case '[':
350  ++cur;
351  break;
352 
353  case '#':
355  ++cur;
356  break;
357 
358  case '/':
360  ++cur;
361  break;
362 
363  default:
364  quote = *quoting;
365  break;
366  }
367 
368  if (*cur == '-') {
369  left = true;
370  ++cur;
371  }
372 
373  if (*cur == '0') {
374  zero = true;
375  ++cur;
376  }
377 
378  char *endp;
379  if (xisdigit(*cur)) {
380  widthMin = strtol(cur, &endp, 10);
381  cur = endp;
382  }
383 
384  if (*cur == '.' && xisdigit(*(++cur))) {
385  widthMax = strtol(cur, &endp, 10);
386  cur = endp;
387  }
388 
389  // when {arg} field is before the token (old logformat syntax)
390  if (*cur == '{') {
391  char *cp;
392  ++cur;
393  l = strcspn(cur, "}");
394  cp = (char *)xmalloc(l + 1);
395  xstrncpy(cp, cur, l + 1);
396  data.string = cp;
397  cur += l;
398 
399  if (*cur == '}')
400  ++cur;
401  }
402 
403  type = LFT_NONE;
404 
405  // Scan each registered token namespace
406  debugs(46, 9, "check for token in " << TheConfig.tokens.size() << " namespaces.");
407  for (const auto &itr : TheConfig.tokens) {
408  debugs(46, 7, "check for possible " << itr.prefix << ":: token");
409  const size_t len = itr.prefix.length();
410  if (itr.prefix.cmp(cur, len) == 0 && cur[len] == ':' && cur[len+1] == ':') {
411  debugs(46, 5, "check for " << itr.prefix << ":: token in '" << cur << "'");
412  const char *old = cur;
413  cur = scanForToken(itr.tokenSet, cur+len+2);
414  if (old != cur) // found
415  break;
416  else // reset to start of namespace
417  cur = cur - len - 2;
418  }
419  }
420 
421  if (type == LFT_NONE) {
422  // For upward compatibility, assume "http::" prefix as default prefix
423  // for all log access formatting codes, except those starting with a
424  // "%" or a known namespace. (ie "icap::", "adapt::")
425  if (strncmp(cur,"http::", 6) == 0 && *(cur+6) != '%' )
426  cur += 6;
427 
428  // NP: scan the sets of tokens in decreasing size to guarantee no
429  // mistakes made with overlapping names. (Bug 3310)
430 
431  // Scan for various long tokens
432  debugs(46, 5, HERE << "scan for possible Misc token");
433  cur = scanForToken(TokenTableMisc, cur);
434  // scan for 2-char tokens
435  if (type == LFT_NONE) {
436  debugs(46, 5, HERE << "scan for possible 2C token");
437  cur = scanForToken(TokenTable2C, cur);
438  }
439  // finally scan for 1-char tokens.
440  if (type == LFT_NONE) {
441  debugs(46, 5, HERE << "scan for possible 1C token");
442  cur = scanForToken(TokenTable1C, cur);
443  }
444  }
445 
446  if (type == LFT_NONE)
447  throw TexcHere(ToSBuf("Unsupported %code: '", def, "'"));
448 
449  // when {arg} field is after the token (old external_acl_type token syntax)
450  // but accept only if there was none before the token
451  if (*cur == '{' && !data.string) {
452  char *cp;
453  ++cur;
454  l = strcspn(cur, "}");
455  cp = (char *)xmalloc(l + 1);
456  xstrncpy(cp, cur, l + 1);
457  data.string = cp;
458  cur += l;
459 
460  if (*cur == '}')
461  ++cur;
462  }
463 
464  if (*cur == ' ') {
465  space = true;
466  ++cur;
467  }
468  }
469 
470  switch (type) {
471 
472 #if USE_ADAPTATION
474 #endif
475 
476 #if ICAP_CLIENT
477  case LFT_ICAP_REQ_HEADER:
478 
479  case LFT_ICAP_REP_HEADER:
480 #endif
481 
483 
484  case LFT_REQUEST_HEADER:
485 
486  case LFT_REPLY_HEADER:
487 
488  case LFT_NOTE:
489 
491 
492  if (data.string) {
493  char *header = data.string;
494  const auto initialType = type;
495 
496  const auto pseudoHeader = header[0] == ':';
497  char *cp = strchr(pseudoHeader ? header+1 : header, ':');
498 
499  if (cp) {
500  *cp = '\0';
501  ++cp;
502 
503  if (*cp == ',' || *cp == ';' || *cp == ':') {
504  data.header.separator = *cp;
505  ++cp;
506  } else {
507  data.header.separator = ',';
508  }
509 
510  data.header.element = cp;
511 
512  switch (type) {
513  case LFT_REQUEST_HEADER:
515  break;
516 
519  break;
520 
521  case LFT_REPLY_HEADER:
523  break;
524 #if USE_ADAPTATION
527  break;
528 #endif
529 #if ICAP_CLIENT
530  case LFT_ICAP_REQ_HEADER:
532  break;
533  case LFT_ICAP_REP_HEADER:
535  break;
536 #endif
539  break;
540  default:
541  break;
542  }
543  }
544 
545  if (!*header)
546  throw TexcHere(ToSBuf("Can't parse configuration token: '", def, "': missing header name"));
547 
548  if (initialType == LFT_PROXY_PROTOCOL_RECEIVED_HEADER)
549  data.headerId = ProxyProtocol::FieldNameToFieldType(SBuf(header));
550  else if (pseudoHeader)
551  throw TexcHere(ToSBuf("Pseudo headers are not supported in this context; got: '", def, "'"));
552 
553  data.header.header = header;
554  } else {
555  switch (type) {
556  case LFT_REQUEST_HEADER:
558  break;
559 
562  break;
563 
564  case LFT_REPLY_HEADER:
566  break;
567 #if USE_ADAPTATION
570  break;
571 #endif
572 #if ICAP_CLIENT
573  case LFT_ICAP_REQ_HEADER:
575  break;
576  case LFT_ICAP_REP_HEADER:
578  break;
579 #endif
582  break;
583  default:
584  break;
585  }
587  }
588 
589  break;
590 
591  case LFT_CLIENT_FQDN:
592  Config.onoff.log_fqdn = 1;
593  break;
594 
598  case LFT_DNS_WAIT_TIME:
599 #if ICAP_CLIENT
601  case LFT_ICAP_IO_TIME:
602  case LFT_ICAP_TOTAL_TIME:
603 #endif
604  case LFT_TIME_START:
605  case LFT_TIME_SUBSECOND:
606  divisor = 1000;
607 
608  if (widthMax > 0) {
609  divisor = 1000000;
610 
611  for (int i = widthMax; i > 0; --i)
612  divisor /= 10;
613 
614  if (!divisor)
615  divisor = 1;
616  }
617  break;
618 
620  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"Hs\" formatting code is deprecated. Use the \">Hs\" instead.");
622  break;
623 
625  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"oa\" formatting code is deprecated. Use the \"<la\" instead.");
627  break;
628 
630  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"rp\" formatting code is deprecated. Use the \">rp\" instead.");
632  break;
633 
635  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \">v\" formatting code is deprecated. Use the \">rv\" instead.");
637  break;
638 
639 #if !USE_SQUID_EUI
640  case LFT_CLIENT_EUI:
641  debugs(46, DBG_CRITICAL, "WARNING: The \">eui\" formatting code requires EUI features which are disabled in this Squid.");
642  break;
643 #endif
644 
645 #if USE_OPENSSL
650  break;
651 #endif
652 
654  debugs(46, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: The \"rG\" formatting code is deprecated. Use \"note{urlgroup}\" instead.");
655  type = LFT_NOTE;
656  data.header.header = xstrdup("urlgroup");
657  break;
658 
659  default:
660  break;
661  }
662 
663  return (cur - def);
664 }
665 
667  label(NULL),
668  widthMin(-1),
669  widthMax(-1),
671  left(false),
672  space(false),
673  zero(false),
674  divisor(1),
675  next(NULL)
676 {
677  data.string = NULL;
678  data.header.header = NULL;
679  data.header.element = NULL;
680  data.header.separator = ',';
682 }
683 
685 {
686  label = NULL; // drop reference to global static.
687  safe_free(data.string);
688  while (next) {
689  Token *tokens = next;
690  next = next->next;
691  tokens->next = NULL;
692  delete tokens;
693  }
694 }
695 
const char * scanForToken(TokenTableEntry const table[], const char *cur)
Definition: Token.cc:267
int type
Definition: errorpage.cc:152
Definition: SBuf.h:86
Token * next
Definition: Token.h:71
static TokenTableEntry TokenTable2C[]
2-char tokens
Definition: Token.cc:48
int i
Definition: membanger.c:49
#define xstrdup
static TokenTableEntry TokenTable1C[]
1-char tokens.
Definition: Token.cc:25
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:124
#define safe_free(x)
Definition: xalloc.h:73
int parse(const char *def, enum Quoting *quote)
Definition: Token.cc:286
Two::FieldType FieldNameToFieldType(const SBuf &nameOrId)
Definition: Elements.cc:102
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:197
Quoting
Quoting style for a format output.
Definition: ByteCode.h:257
static TokenTableEntry TokenTableAdapt[]
Definition: Token.cc:187
void const char HLPCB void * data
Definition: stub_helper.cc:16
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
#define DBG_IMPORTANT
Definition: Debug.h:46
static TokenTableEntry TokenTableProxyProtocol[]
Definition: Token.cc:182
static TokenTableEntry TokenTableMisc[]
Miscellaneous >2 byte tokens.
Definition: Token.cc:140
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:223
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:157
struct SquidConfig::@112 onoff
const char * label
Definition: Token.h:51
#define xmalloc
static void Init()
Initialize the format token registrations.
Definition: Token.cc:247
#define xisdigit(x)
Definition: xis.h:20
const char * quote
Definition: html_quote.c:21
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:55
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:344
#define false
Definition: GnuRegex.c:233

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors