From: Amos Jeffries Date: Thu, 25 Aug 2011 12:32:02 +0000 (+1200) Subject: Bug 3310: regression: %config != NULL; te++) { - if (te->token_type == type) { - storeAppendPrintf(entry, "%s", te->config); - break; - } - } + storeAppendPrintf(entry, "%s", t->label); if (t->space) entry->append(" ", 1); diff --git a/src/format/Tokens.cc b/src/format/Tokens.cc index 59a04c001e..5e39d9c067 100644 --- a/src/format/Tokens.cc +++ b/src/format/Tokens.cc @@ -30,17 +30,36 @@ const char *Format::log_tags[] = { "LOG_TYPE_MAX" }; -struct Format::TokenTableEntry Format::TokenTable[] = { +// Due to token overlaps between 1 and 2 letter tokens (Bug 3310) +// We split the token table into sets determined by the token length +namespace Format { + +/// 1-char tokens. +static struct TokenTableEntry TokenTable1C[] = { {">a", LFT_CLIENT_IP_ADDRESS}, {">p", LFT_CLIENT_PORT}, {">A", LFT_CLIENT_FQDN}, - {">eui", LFT_CLIENT_EUI}, {"h", LFT_REQUEST_HEADER}, + {">h", LFT_REQUEST_ALL_HEADERS}, + {"v", LFT_REQUEST_VERSION_OLD_2X}, + + {"%", LFT_PERCENT}, + + {NULL, LFT_NONE} /* this must be last */ +}; + +/// 2-char tokens +static struct TokenTableEntry TokenTable2C[] = { + {">la", LFT_CLIENT_LOCAL_IP}, {"la", LFT_CLIENT_LOCAL_IP_OLD_31}, {">lp", LFT_CLIENT_LOCAL_PORT}, @@ -64,10 +83,6 @@ struct Format::TokenTableEntry Format::TokenTable[] = { {">ha", LFT_ADAPTED_REQUEST_HEADER}, {">ha", LFT_ADAPTED_REQUEST_ALL_HEADERS}, - {">h", LFT_REQUEST_HEADER}, - {">h", LFT_REQUEST_ALL_HEADERS}, - {"v", LFT_REQUEST_VERSION_OLD_2X}, {"rv", LFT_REQUEST_VERSION}, {"2 byte tokens +static struct TokenTableEntry TokenTableMisc[] = { + {">eui", LFT_CLIENT_EUI}, + { "err_code", LFT_SQUID_ERROR }, + { "err_detail", LFT_SQUID_ERROR_DETAIL }, {NULL, LFT_NONE} /* this must be last */ }; +} // namespace Format + +/// Scans a token table to see if the next token exists there +/// returns a pointer to next unparsed byte and updates type member if found +char * +Format::Token::scanForToken(const struct TokenTableEntry *table, char *cur) +{ + for (const struct TokenTableEntry *lte = table; lte->config != NULL; lte++) { + if (strncmp(lte->config, cur, strlen(lte->config)) == 0) { + type = lte->token_type; + label = lte->config; + debugs(46, 7, HERE << "Found token '" << label << "'"); + return cur + strlen(lte->config); + } + } + return cur; +} + /* parses a single token. Returns the token length in characters, * and fills in the lt item with the token information. * def is for sure null-terminated @@ -168,7 +213,6 @@ Format::Token::parse(char *def, Quoting *quoting) { char *cur = def; - struct TokenTableEntry *lte; int l; l = strcspn(cur, "%"); @@ -275,28 +319,52 @@ Format::Token::parse(char *def, Quoting *quoting) cur++; } - // For upward compatibility, assume "http::" prefix as default prefix - // for all log access formating codes, except those starting - // from "icap::", "adapt::" and "%" - if (strncmp(cur,"http::", 6) == 0 && - strncmp(cur+6, "icap::", 6) != 0 && - strncmp(cur+6, "adapt::", 12) != 0 && *(cur+6) != '%' ) { - cur += 6; - } - type = LFT_NONE; - for (lte = TokenTable; lte->config != NULL; lte++) { - if (strncmp(lte->config, cur, strlen(lte->config)) == 0) { - type = lte->token_type; - cur += strlen(lte->config); - break; + // Scan each token namespace + if (strncmp(cur, "icap::", 6) == 0) { +#if ICAP_CLIENT + cur += 6; + debugs(46, 5, HERE << "scan for icap:: token"); + cur = scanForToken(TokenTableIcap, cur); +#else + debugs(46, DBG_IMPORTANT, "ERROR: Format uses icap:: token. ICAP disabled!"); +#endif + } else if (strncmp(cur, "adapt::", 7) == 0) { +#if USE_ADAPTATION + cur += 7; + debugs(46, 5, HERE << "scan for adapt:: token"); + cur = scanForToken(TokenTableAdapt, cur); +#else + debugs(46, DBG_IMPORTANT, "ERROR: Format uses adapt:: token. Adaptation disabled!"); +#endif + } else { + // For upward compatibility, assume "http::" prefix as default prefix + // for all log access formating codes, except those starting with a + // "%" or a known namespace. (ie "icap::", "adapt::") + if (strncmp(cur,"http::", 6) == 0 && *(cur+6) != '%' ) + cur += 6; + + // NP: scan the sets of tokens in decreasing size to guarantee no + // mistakes made with overlapping names. (Bug 3310) + + // Scan for various long tokens + debugs(46, 5, HERE << "scan for possible Misc token"); + cur = scanForToken(TokenTableMisc, cur); + // scan for 2-char tokens + if (type == LFT_NONE) { + debugs(46, 5, HERE << "scan for possible 2C token"); + cur = scanForToken(TokenTable2C, cur); + } + // finally scan for 1-char tokens. + if (type == LFT_NONE) { + debugs(46, 5, HERE << "scan for possible 1C token"); + cur = scanForToken(TokenTable1C, cur); } } if (type == LFT_NONE) { - fatalf("Can't parse configuration token: '%s'\n", - def); + fatalf("Can't parse configuration token: '%s'\n", def); } if (*cur == ' ') { @@ -467,6 +535,7 @@ done: Format::Token::~Token() { + label = NULL; // drop reference to global static. safe_free(data.string); while (next) { Token *tokens = next; diff --git a/src/format/Tokens.h b/src/format/Tokens.h index d79552c8e4..a609718e5b 100644 --- a/src/format/Tokens.h +++ b/src/format/Tokens.h @@ -174,11 +174,18 @@ enum Quoting { LOG_QUOTE_RAW }; +struct TokenTableEntry { + const char *config; + ByteCode_t token_type; + int options; +}; + // XXX: inherit from linked list class Token { public: Token() : type(LFT_NONE), + label(NULL), width(0), precision(0), quote(LOG_QUOTE_NONE), @@ -197,6 +204,7 @@ public: int parse(char *def, enum Quoting *quote); ByteCode_t type; + const char *label; union { char *string; @@ -215,16 +223,12 @@ public: unsigned int zero:1; int divisor; Token *next; /* todo: move from linked list to array */ -}; -struct TokenTableEntry { - const char *config; - ByteCode_t token_type; - int options; +private: + char *scanForToken(const struct TokenTableEntry *table, char *cur); }; extern const char *log_tags[]; -extern struct TokenTableEntry TokenTable[]; } // namespace Format