From: Christos Tsantilas Date: Sun, 21 Jul 2013 19:24:35 +0000 (+0300) Subject: Quoted values in squid.conf X-Git-Tag: SQUID_3_4_0_1~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2eceb328ef857482d29d0b170856bf6213015c1c;p=thirdparty%2Fsquid.git Quoted values in squid.conf This patch : - adds support for quoted values in the entire squid.conf - warn about or prohibit values that can no longer be interpreted as either quoted strings or simple tokens - support parameters("/path/to/file.name") syntax to load external configuration files - Checks if macros allowed in "double quoted" values. - replaces the strtok() calls with calls to the new ConfigParser::NextToken() - modify strtokFile to use new ConfigParser::NextToken() - Add the new configuration_includes_quoted_values configuration option, to control the squid parser behaviour. If set to on Squid will recognize each "quoted string" after a configuration directive as a single parameter This is a Measurement Factory project --- diff --git a/src/ConfigParser.cc b/src/ConfigParser.cc index 453ca76f6f..a4e3ffcb86 100644 --- a/src/ConfigParser.cc +++ b/src/ConfigParser.cc @@ -38,68 +38,98 @@ #include "fatal.h" #include "globals.h" -char *ConfigParser::lastToken = NULL; -std::queue ConfigParser::undo; +int ConfigParser::RecognizeQuotedValues = true; +std::stack ConfigParser::CfgFiles; +ConfigParser::TokenType ConfigParser::LastTokenType = ConfigParser::SimpleToken; +char *ConfigParser::LastToken = NULL; +char *ConfigParser::CfgLine = NULL; +char *ConfigParser::CfgPos = NULL; +std::queue ConfigParser::Undo_; +bool ConfigParser::AllowMacros_ = false; void ConfigParser::destruct() { shutting_down = 1; - fatalf("Bungled %s line %d: %s", - cfg_filename, config_lineno, config_input_line); + if (!CfgFiles.empty()) { + std::ostringstream message; + CfgFile *f = CfgFiles.top(); + message << "Bungled " << f->filePath << " line " << f->lineNo << + ": " << f->currentLine << std::endl; + CfgFiles.pop(); + delete f; + while (!CfgFiles.empty()) { + f = CfgFiles.top(); + message << " included from " << f->filePath << " line " << + f->lineNo << ": " << f->currentLine << std::endl; + CfgFiles.pop(); + delete f; + } + message << " included from " << cfg_filename << " line " << + config_lineno << ": " << config_input_line << std::endl; + std::string msg = message.str(); + fatalf("%s", msg.c_str()); + } else + fatalf("Bungled %s line %d: %s", + cfg_filename, config_lineno, config_input_line); } void -ConfigParser::strtokFileUndo() +ConfigParser::TokenUndo() { - assert(lastToken); - undo.push(lastToken); + assert(LastToken); + Undo_.push(LastToken); } void -ConfigParser::strtokFilePutBack(const char *tok) +ConfigParser::TokenPutBack(const char *tok) { assert(tok); - undo.push(tok); + Undo_.push(tok); } char * -ConfigParser::strtokFile(void) +ConfigParser::Undo() { + LOCAL_ARRAY(char, undoToken, CONFIG_LINE_LIMIT); + if (!Undo_.empty()) { + strncpy(undoToken, Undo_.front().c_str(), sizeof(undoToken)); + undoToken[sizeof(undoToken) - 1] = '\0'; + Undo_.pop(); + return undoToken; + } + return NULL; +} + +char * +ConfigParser::strtokFile() +{ + if (RecognizeQuotedValues) + return ConfigParser::NextToken(); + static int fromFile = 0; static FILE *wordFile = NULL; - LOCAL_ARRAY(char, undoToken, CONFIG_LINE_LIMIT); - char *t, *fn; + char *t; LOCAL_ARRAY(char, buf, CONFIG_LINE_LIMIT); - if (!undo.empty()) { - strncpy(undoToken, undo.front().c_str(), sizeof(undoToken)); - undoToken[sizeof(undoToken) - 1] = '\0'; - undo.pop(); - return undoToken; - } + if ((LastToken = ConfigParser::Undo())) + return LastToken; - lastToken = NULL; do { if (!fromFile) { - t = (strtok(NULL, w_space)); - - if (!t || *t == '#') { + ConfigParser::TokenType tokenType; + t = ConfigParser::NextElement(tokenType, true); + if (!t) { return NULL; - } else if (*t == '\"' || *t == '\'') { + } else if (tokenType == ConfigParser::QuotedToken) { /* quote found, start reading from file */ - fn = ++t; - - while (*t && *t != '\"' && *t != '\'') - ++t; + debugs(3, 8,"Quoted token found : " << t); - *t = '\0'; - - if ((wordFile = fopen(fn, "r")) == NULL) { - debugs(28, DBG_CRITICAL, "strtokFile: " << fn << " not found"); - return (NULL); + if ((wordFile = fopen(t, "r")) == NULL) { + debugs(3, DBG_CRITICAL, "Can not open file " << t << " for reading"); + return false; } #if _SQUID_WINDOWS_ @@ -108,7 +138,7 @@ ConfigParser::strtokFile(void) fromFile = 1; } else { - return lastToken = t; + return LastToken = t; } } @@ -139,52 +169,182 @@ ConfigParser::strtokFile(void) /* skip blank lines */ } while ( *t == '#' || !*t ); - return lastToken = t; -} - -void -ConfigParser::ParseQuotedString(char **var, bool *wasQuoted) -{ - String sVar; - ParseQuotedString(&sVar, wasQuoted); - *var = xstrdup(sVar.termedBuf()); + return LastToken = t; } -void -ConfigParser::ParseQuotedString(String *var, bool *wasQuoted) +char * +ConfigParser::UnQuote(char *token, char **end) { - // Get all of the remaining string - char *token = strtok(NULL, ""); - if (token == NULL) - self_destruct(); - - if (*token != '"') { - token = strtok(token, w_space); - var->reset(token); - if (wasQuoted) - *wasQuoted = false; - return; - } else if (wasQuoted) - *wasQuoted = true; - + char quoteChar = *token; + assert(quoteChar == '"' || quoteChar == '\''); char *s = token + 1; /* scan until the end of the quoted string, unescaping " and \ */ - while (*s && *s != '"') { - if (*s == '\\') { + while (*s && *s != quoteChar) { + if (*s == '\\' && isalnum(*( s + 1))) { + debugs(3, DBG_CRITICAL, "Unsupported escape sequence: " << s); + self_destruct(); + } else if (*s == '$' && quoteChar == '"') { + debugs(3, DBG_CRITICAL, "Unsupported cfg macro: " << s); + self_destruct(); + } else if (*s == '%' && quoteChar == '"' && (!AllowMacros_ )) { + debugs(3, DBG_CRITICAL, "Macros are not supported here: " << s); + self_destruct(); + } else if (*s == '\\') { const char * next = s+1; // may point to 0 memmove(s, next, strlen(next) + 1); } ++s; } - if (*s != '"') { - debugs(3, DBG_CRITICAL, "ParseQuotedString: missing '\"' at the end of quoted string" ); + if (*s != quoteChar) { + debugs(3, DBG_CRITICAL, "missing '" << quoteChar << "' at the end of quoted string: " << (s-1)); self_destruct(); } - strtok(s-1, "\""); /*Reset the strtok to point after the " */ - *s = '\0'; + *end = s; + return (token+1); +} + +void +ConfigParser::SetCfgLine(char *line) +{ + CfgLine = line; + CfgPos = line; +} + +char * +ConfigParser::TokenParse(char * &nextToken, ConfigParser::TokenType &type, bool legacy) +{ + if (!nextToken || *nextToken == '\0') + return NULL; + type = ConfigParser::SimpleToken; + nextToken += strspn(nextToken, w_space); + if (*nextToken == '"' || *nextToken == '\'') { + type = ConfigParser::QuotedToken; + char *token = UnQuote(nextToken, &nextToken); + *nextToken = '\0'; + ++nextToken; + return token; + } + + char *token = nextToken; + if (char *t = strchr(nextToken, '#')) + *t = '\0'; + const char *sep; + if (legacy) + sep = w_space; + else + sep = w_space "("; + nextToken += strcspn(nextToken, sep); + + if (!legacy && *nextToken == '(') + type = ConfigParser::FunctionNameToken; + else + type = ConfigParser::SimpleToken; + + if (*nextToken != '\0') { + *nextToken = '\0'; + ++nextToken; + } + + if (*token == '\0') + return NULL; + + return token; +} + +char * +ConfigParser::NextElement(ConfigParser::TokenType &type, bool legacy) +{ + char *token = TokenParse(CfgPos, type, legacy); + return token; +} + +char * +ConfigParser::NextToken() +{ + if ((LastToken = ConfigParser::Undo())) + return LastToken; + + char *token = NULL; + do { + while (token == NULL && !CfgFiles.empty()) { + ConfigParser::CfgFile *wordfile = CfgFiles.top(); + token = wordfile->parse(LastTokenType); + if (!token) { + assert(!wordfile->isOpen()); + CfgFiles.pop(); + delete wordfile; + } + } + + if (!token) + token = NextElement(LastTokenType); - var->reset(token+1); + if (token && LastTokenType == ConfigParser::FunctionNameToken && strcmp("parameters", token) == 0) { + char *path = NextToken(); + if (LastTokenType != ConfigParser::QuotedToken) { + debugs(3, DBG_CRITICAL, "Quoted filename missing: " << token); + self_destruct(); + return NULL; + } + + // The next token in current cfg file line must be a ")" + char *end = NextToken(); + if (LastTokenType != ConfigParser::SimpleToken || strcmp(end, ")") != 0) { + debugs(3, DBG_CRITICAL, "missing ')' after " << token << "(\"" << path << "\""); + self_destruct(); + return NULL; + } + + if (CfgFiles.size() > 16) { + debugs(3, DBG_CRITICAL, "WARNING: can't open %s for reading parameters: includes are nested too deeply (>16)!\n" << path); + self_destruct(); + return NULL; + } + + ConfigParser::CfgFile *wordfile = new ConfigParser::CfgFile(); + if (!path || !wordfile->startParse(path)) { + debugs(3, DBG_CRITICAL, "Error opening config file: " << token); + delete wordfile; + self_destruct(); + return NULL; + } + CfgFiles.push(wordfile); + token = NULL; + } else if (token && LastTokenType == ConfigParser::FunctionNameToken) { + debugs(3, DBG_CRITICAL, "Unknown cfg function: " << token); + self_destruct(); + return NULL; + } + } while (token == NULL && !CfgFiles.empty()); + + return (LastToken = token); +} + +char * +ConfigParser::NextQuotedOrToEol() +{ + char *token; + + if ((token = CfgPos) == NULL) { + debugs(3, DBG_CRITICAL, "token is missing"); + self_destruct(); + return NULL; + } + token += strspn(token, w_space); + + if (*token == '\"' || *token == '\'') { + //TODO: eat the spaces at the end and check if it is untill the end of file. + char *end; + token = UnQuote(token, &end); + *end = '\0'; + CfgPos = end + 1; + LastTokenType = ConfigParser::QuotedToken; + } else + LastTokenType = ConfigParser::SimpleToken; + + CfgPos = NULL; + return (LastToken = token); } const char * @@ -210,3 +370,66 @@ ConfigParser::QuoteString(const String &var) quotedStr.append('"'); return quotedStr.termedBuf(); } + +bool +ConfigParser::CfgFile::startParse(char *path) +{ + assert(wordFile == NULL); + if ((wordFile = fopen(path, "r")) == NULL) { + debugs(3, DBG_CRITICAL, "file :" << path << " not found"); + return false; + } + +#if _SQUID_WINDOWS_ + setmode(fileno(wordFile), O_TEXT); +#endif + + filePath = path; + return getFileLine(); +} + +bool +ConfigParser::CfgFile::getFileLine() +{ + // Else get the next line + if (fgets(parseBuffer, CONFIG_LINE_LIMIT, wordFile) == NULL) { + /* stop reading from file */ + fclose(wordFile); + wordFile = NULL; + parseBuffer[0] = '\0'; + return false; + } + parsePos = parseBuffer; + currentLine = parseBuffer; + lineNo++; + return true; +} + +char * +ConfigParser::CfgFile::parse(ConfigParser::TokenType &type) +{ + if (!wordFile) + return NULL; + + if (!*parseBuffer) + return NULL; + + char *token; + while (!(token = nextElement(type))) { + if (!getFileLine()) + return NULL; + } + return token; +} + +char * +ConfigParser::CfgFile::nextElement(ConfigParser::TokenType &type) +{ + return TokenParse(parsePos, type); +} + +ConfigParser::CfgFile::~CfgFile() +{ + if (wordFile) + fclose(wordFile); +} diff --git a/src/ConfigParser.h b/src/ConfigParser.h index f313a5a6c2..1175bdce97 100644 --- a/src/ConfigParser.h +++ b/src/ConfigParser.h @@ -36,6 +36,7 @@ #include "SquidString.h" #include +#include #if HAVE_STRING #include #endif @@ -65,26 +66,143 @@ class ConfigParser { public: + /** + * Parsed tokens type: simple tokens, quoted tokens or function + * like parameters. + */ + enum TokenType {SimpleToken, QuotedToken, FunctionNameToken}; + void destruct(); static void ParseUShort(unsigned short *var); static void ParseBool(bool *var); - static void ParseString(char **var); - static void ParseString(String *var); - /// Parse an unquoted token (no spaces) or a "quoted string" that - /// may include spaces. In some contexts, quotes strings may also - /// include macros. Quoted strings may escape any character with - /// a backslash (\), which is currently only useful for inner - /// quotes. TODO: support quoted strings anywhere a token is accepted. - static void ParseQuotedString(char **var, bool *wasQuoted = NULL); - static void ParseQuotedString(String *var, bool *wasQuoted = NULL); static const char *QuoteString(const String &var); static void ParseWordList(wordlist **list); + + /** + * Backward compatibility wrapper for the ConfigParser::NextToken method. + * If the configuration_includes_quoted_values configuration parameter is + * set to 'off' this interprets the quoted tokens as filenames. + */ static char * strtokFile(); - static void strtokFileUndo(); - static void strtokFilePutBack(const char *); -private: - static char *lastToken; - static std::queue undo; + + /** + * Returns the body of the next element. The element is either a token or + * a quoted string with optional escape sequences and/or macros. The body + * of a quoted string element does not include quotes or escape sequences. + * Future code will want to see Elements and not just their bodies. + */ + static char *NextToken(); + + /// \return true if the last parsed token was quoted + static bool LastTokenWasQuoted() {return (LastTokenType == ConfigParser::QuotedToken);} + + /** + * \return the next quoted string or the raw string data until the end of line. + * This method allows %macros in unquoted strings to keep compatibility + * for the logformat option. + */ + static char *NextQuotedOrToEol(); + + /** + * Undo last NextToken call. The next call to NextToken() method will return + * again the last parsed element. + * Can not be called repeatedly to undo multiple NextToken calls. In this case + * the behaviour is undefined. + */ + static void TokenUndo(); + + /** + * The next NextToken call will return the token as next element + * It can be used repeatedly to add more than one tokens in a FIFO list. + */ + static void TokenPutBack(const char *token); + + /// Set the configuration file line to parse. + static void SetCfgLine(char *line); + + /// Allow %macros inside quoted strings + static void EnableMacros() {AllowMacros_ = true;} + + /// Do not allow %macros inside quoted strings + static void DisableMacros() {AllowMacros_ = false;} + + /// configuration_includes_quoted_values in squid.conf + static int RecognizeQuotedValues; + +protected: + /** + * Class used to store required information for the current + * configuration file. + */ + class CfgFile + { + public: + CfgFile(): wordFile(NULL), parsePos(NULL), lineNo(0) { parseBuffer[0] = '\0';} + ~CfgFile(); + /// True if the configuration file is open + bool isOpen() {return wordFile != NULL;} + + /** + * Open the file given by 'path' and initializes the CfgFile object + * to start parsing + */ + bool startParse(char *path); + + /** + * Do the next parsing step: + * reads the next line from file if required. + * \return the body of next element or a NULL pointer if there are no more token elements in the file. + * \param type will be filled with the ConfigParse::TokenType for any element found, or left unchanged if NULL is returned. + */ + char *parse(TokenType &type); + + private: + bool getFileLine(); ///< Read the next line from the file + /** + * Return the body of the next element. If the wasQuoted is given + * set to true if the element was quoted. + */ + char *nextElement(TokenType &type); + FILE *wordFile; ///< Pointer to the file. + char parseBuffer[CONFIG_LINE_LIMIT]; ///< Temporary buffer to store data to parse + char *parsePos; ///< The next element position in parseBuffer string + public: + std::string filePath; ///< The file path + std::string currentLine; ///< The current line to parse + int lineNo; ///< Current line number + }; + + /** + * Return the last TokenUndo() or TokenPutBack() queued element, or NULL + * if none exist + */ + static char *Undo(); + + /** + * Unquotes the token, which must be quoted. + * \param end if it is not NULL, it is set to the end of token. + */ + static char *UnQuote(char *token, char **end = NULL); + + /** + * Does the real tokens parsing job: Ignore comments, unquote an + * element if required. + * \return the next token, or NULL if there are no available tokens in the nextToken string. + * \param nextToken updated to point to the pos after parsed token. + * \param type The token type + * \param legacy If it is true function-like parameters are not allowed + */ + static char *TokenParse(char * &nextToken, TokenType &type, bool legacy = false); + + /// Wrapper method for TokenParse. + static char *NextElement(TokenType &type, bool legacy = false); + static std::stack CfgFiles; ///< The stack of open cfg files + static TokenType LastTokenType; ///< The type of last parsed element + static char *LastToken; ///< Points to the last parsed token + static char *CfgLine; ///< The current line to parse + static char *CfgPos; ///< Pointer to the next element in cfgLine string + static std::queue Undo_; ///< The list with TokenUndo() or TokenPutBack() queued elements + static bool AllowMacros_; }; int parseConfigFile(const char *file_name); diff --git a/src/HelperChildConfig.cc b/src/HelperChildConfig.cc index c82b9b5d85..ba46f04111 100644 --- a/src/HelperChildConfig.cc +++ b/src/HelperChildConfig.cc @@ -1,5 +1,6 @@ #include "squid.h" #include "cache_cf.h" +#include "ConfigParser.h" #include "Debug.h" #include "HelperChildConfig.h" #include "globals.h" @@ -44,7 +45,7 @@ HelperChildConfig::needNew() const void HelperChildConfig::parseConfig() { - char const *token = strtok(NULL, w_space); + char const *token = ConfigParser::NextToken(); if (!token) self_destruct(); @@ -58,7 +59,7 @@ HelperChildConfig::parseConfig() } /* Parse extension options */ - for (; (token = strtok(NULL, w_space)) ;) { + for (; (token = ConfigParser::NextToken()) ;) { if (strncmp(token, "startup=", 8) == 0) { n_startup = xatoui(token + 8); } else if (strncmp(token, "idle=", 5) == 0) { diff --git a/src/Notes.cc b/src/Notes.cc index 1258da77d8..3152910e76 100644 --- a/src/Notes.cc +++ b/src/Notes.cc @@ -92,9 +92,8 @@ Notes::add(const String ¬eKey) Note::Pointer Notes::parse(ConfigParser &parser) { - String key, value; - ConfigParser::ParseString(&key); - ConfigParser::ParseQuotedString(&value); + String key = ConfigParser::NextToken(); + String value = ConfigParser::NextToken(); Note::Pointer note = add(key); Note::Value::Pointer noteValue = note->addValue(value); diff --git a/src/Parsing.cc b/src/Parsing.cc index 2e9b75d0df..267ed67756 100644 --- a/src/Parsing.cc +++ b/src/Parsing.cc @@ -147,7 +147,7 @@ xatos(const char *token) int64_t GetInteger64(void) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (token == NULL) self_destruct(); @@ -162,7 +162,7 @@ GetInteger64(void) int GetInteger(void) { - char *token = ConfigParser::strtokFile(); + char *token = ConfigParser::NextToken(); int i; if (token == NULL) @@ -216,7 +216,7 @@ GetPercentage(void) unsigned short GetShort(void) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (token == NULL) self_destruct(); diff --git a/src/SwapDir.cc b/src/SwapDir.cc index efa3e0665a..2bb712ee9f 100644 --- a/src/SwapDir.cc +++ b/src/SwapDir.cc @@ -34,6 +34,7 @@ #include "cache_cf.h" #include "compat/strtoll.h" #include "ConfigOption.h" +#include "ConfigParser.h" #include "globals.h" #include "Parsing.h" #include "SquidConfig.h" @@ -276,7 +277,7 @@ SwapDir::parseOptions(int isaReconfig) ConfigOption *newOption = getOptionTree(); - while ((name = strtok(NULL, w_space)) != NULL) { + while ((name = ConfigParser::NextToken()) != NULL) { value = strchr(name, '='); if (value) { diff --git a/src/acl/Acl.cc b/src/acl/Acl.cc index b5e1c31fd3..839e8b0c80 100644 --- a/src/acl/Acl.cc +++ b/src/acl/Acl.cc @@ -73,10 +73,10 @@ ACLFlags::parseFlags() /*Regex code needs to parse -i file*/ if ( isSet(ACL_F_REGEX_CASE)) - ConfigParser::strtokFilePutBack("-i"); + ConfigParser::TokenPutBack("-i"); if (nextToken != NULL && strcmp(nextToken, "--") != 0 ) - ConfigParser::strtokFileUndo(); + ConfigParser::TokenUndo(); } const char * @@ -200,7 +200,7 @@ ACL::ParseAclLine(ConfigParser &parser, ACL ** head) /* snarf the ACL name */ - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL name."); parser.destruct(); return; @@ -217,7 +217,7 @@ ACL::ParseAclLine(ConfigParser &parser, ACL ** head) /* snarf the ACL type */ const char *theType; - if ((theType = strtok(NULL, w_space)) == NULL) { + if ((theType = ConfigParser::NextToken()) == NULL) { debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL type."); parser.destruct(); return; diff --git a/src/acl/Gadgets.cc b/src/acl/Gadgets.cc index d43f89f58c..8d3c0a5681 100644 --- a/src/acl/Gadgets.cc +++ b/src/acl/Gadgets.cc @@ -120,7 +120,7 @@ aclParseDenyInfoLine(AclDenyInfoList ** head) /* first expect a page name */ - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line); debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: missing 'error page' parameter."); return; @@ -133,7 +133,7 @@ aclParseDenyInfoLine(AclDenyInfoList ** head) /* next expect a list of ACL names */ Tail = &A->acl_list; - while ((t = strtok(NULL, w_space))) { + while ((t = ConfigParser::NextToken())) { L = (AclNameList *)memAllocate(MEM_ACL_NAME_LIST); xstrncpy(L->name, t, ACL_NAME_SZ-1); *Tail = L; @@ -157,7 +157,7 @@ void aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep) { /* first expect either 'allow' or 'deny' */ - const char *t = ConfigParser::strtokFile(); + const char *t = ConfigParser::NextToken(); if (!t) { debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line); diff --git a/src/adaptation/Config.cc b/src/adaptation/Config.cc index 2908a4101b..d84eabddee 100644 --- a/src/adaptation/Config.cc +++ b/src/adaptation/Config.cc @@ -264,8 +264,7 @@ Adaptation::Config::DumpServiceGroups(StoreEntry *entry, const char *name) void Adaptation::Config::ParseAccess(ConfigParser &parser) { - String groupId; - ConfigParser::ParseString(&groupId); + String groupId = ConfigParser::NextToken(); AccessRule *r; if (!(r=FindRuleByGroupId(groupId))) { r = new AccessRule(groupId); diff --git a/src/adaptation/ServiceConfig.cc b/src/adaptation/ServiceConfig.cc index cc73254dee..f6ecd79cf0 100644 --- a/src/adaptation/ServiceConfig.cc +++ b/src/adaptation/ServiceConfig.cc @@ -61,10 +61,8 @@ Adaptation::ServiceConfig::parseVectPoint(const char *service_configConfig) cons bool Adaptation::ServiceConfig::parse() { - String method_point; - - ConfigParser::ParseString(&key); - ConfigParser::ParseString(&method_point); + key = ConfigParser::NextToken(); + String method_point = ConfigParser::NextToken(); method = parseMethod(method_point.termedBuf()); point = parseVectPoint(method_point.termedBuf()); @@ -76,7 +74,7 @@ Adaptation::ServiceConfig::parse() bool onOverloadSet = false; std::set options; - while (char *option = strtok(NULL, w_space)) { + while (char *option = ConfigParser::NextToken()) { const char *name = option; const char *value = ""; if (strcmp(option, "0") == 0) { // backward compatibility diff --git a/src/adaptation/ServiceGroups.cc b/src/adaptation/ServiceGroups.cc index 4fee139d74..ad196bc1a9 100644 --- a/src/adaptation/ServiceGroups.cc +++ b/src/adaptation/ServiceGroups.cc @@ -23,7 +23,7 @@ Adaptation::ServiceGroup::~ServiceGroup() void Adaptation::ServiceGroup::parse() { - ConfigParser::ParseString(&id); + id = ConfigParser::NextToken(); wordlist *names = NULL; ConfigParser::ParseWordList(&names); diff --git a/src/cache_cf.cc b/src/cache_cf.cc index cd2233f62b..447f851563 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -1023,7 +1023,7 @@ parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec) if ((u = parseTimeUnits(units, allowMsec)) == 0) self_destruct(); - if ((token = strtok(NULL, w_space)) == NULL) + if ((token = ConfigParser::NextToken()) == NULL) self_destruct(); d = xatof(token); @@ -1032,7 +1032,7 @@ parseTimeLine(time_msec_t * tptr, const char *units, bool allowMsec) if (0 == d) (void) 0; - else if ((token = strtok(NULL, w_space)) == NULL) + else if ((token = ConfigParser::NextToken()) == NULL) debugs(3, DBG_CRITICAL, "WARNING: No units on '" << config_input_line << "', assuming " << d << " " << units ); @@ -1099,7 +1099,7 @@ parseBytesLine64(int64_t * bptr, const char *units) return; } - if ((token = strtok(NULL, w_space)) == NULL) { + if ((token = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -1115,7 +1115,7 @@ parseBytesLine64(int64_t * bptr, const char *units) if (0.0 == d) (void) 0; - else if ((token = strtok(NULL, w_space)) == NULL) + else if ((token = ConfigParser::NextToken()) == NULL) debugs(3, DBG_CRITICAL, "WARNING: No units on '" << config_input_line << "', assuming " << d << " " << units ); @@ -1146,7 +1146,7 @@ parseBytesLine(size_t * bptr, const char *units) return; } - if ((token = strtok(NULL, w_space)) == NULL) { + if ((token = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -1162,7 +1162,7 @@ parseBytesLine(size_t * bptr, const char *units) if (0.0 == d) (void) 0; - else if ((token = strtok(NULL, w_space)) == NULL) + else if ((token = ConfigParser::NextToken()) == NULL) debugs(3, DBG_CRITICAL, "WARNING: No units on '" << config_input_line << "', assuming " << d << " " << units ); @@ -1194,7 +1194,7 @@ parseBytesLineSigned(ssize_t * bptr, const char *units) return; } - if ((token = strtok(NULL, w_space)) == NULL) { + if ((token = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -1210,7 +1210,7 @@ parseBytesLineSigned(ssize_t * bptr, const char *units) if (0.0 == d) (void) 0; - else if ((token = strtok(NULL, w_space)) == NULL) + else if ((token = ConfigParser::NextToken()) == NULL) debugs(3, DBG_CRITICAL, "WARNING: No units on '" << config_input_line << "', assuming " << d << " " << units ); @@ -1367,7 +1367,7 @@ dump_address(StoreEntry * entry, const char *name, Ip::Address &addr) static void parse_address(Ip::Address *addr) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (!token) { self_destruct(); @@ -1475,7 +1475,7 @@ parse_acl_tos(acl_tos ** head) acl_tos *l; acl_tos **tail = head; /* sane name below */ unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */ - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (!token) { self_destruct(); @@ -1546,7 +1546,7 @@ parse_acl_nfmark(acl_nfmark ** head) acl_nfmark *l; acl_nfmark **tail = head; /* sane name below */ nfmark_t mark; - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (!token) { self_destruct(); @@ -1748,7 +1748,7 @@ parse_http_header_access(HeaderManglers **pm) { char *t = NULL; - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line); debugs(3, DBG_CRITICAL, "parse_http_header_access: missing header name."); return; @@ -1787,7 +1787,7 @@ parse_http_header_replace(HeaderManglers **pm) { char *t = NULL; - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line); debugs(3, DBG_CRITICAL, "parse_http_header_replace: missing header name."); return; @@ -1832,10 +1832,10 @@ parse_authparam(Auth::ConfigVector * config) char *type_str; char *param_str; - if ((type_str = strtok(NULL, w_space)) == NULL) + if ((type_str = ConfigParser::NextToken()) == NULL) self_destruct(); - if ((param_str = strtok(NULL, w_space)) == NULL) + if ((param_str = ConfigParser::NextToken()) == NULL) self_destruct(); /* find a configuration for the scheme in the currently parsed configs... */ @@ -1906,10 +1906,10 @@ parse_cachedir(SquidConfig::_cacheSwap * swap) int i; int fs; - if ((type_str = strtok(NULL, w_space)) == NULL) + if ((type_str = ConfigParser::NextToken()) == NULL) self_destruct(); - if ((path_str = strtok(NULL, w_space)) == NULL) + if ((path_str = ConfigParser::NextToken()) == NULL) self_destruct(); fs = find_fstype(type_str); @@ -2064,7 +2064,7 @@ GetService(const char *proto) { struct servent *port = NULL; /** Parses a port number or service name from the squid.conf */ - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (token == NULL) { self_destruct(); return 0; /* NEVER REACHED */ @@ -2112,14 +2112,14 @@ parse_peer(CachePeer ** head) p->basetime = 0; p->stats.logged_state = PEER_ALIVE; - if ((token = strtok(NULL, w_space)) == NULL) + if ((token = ConfigParser::NextToken()) == NULL) self_destruct(); p->host = xstrdup(token); p->name = xstrdup(token); - if ((token = strtok(NULL, w_space)) == NULL) + if ((token = ConfigParser::NextToken()) == NULL) self_destruct(); p->type = parseNeighborType(token); @@ -2137,7 +2137,7 @@ parse_peer(CachePeer ** head) p->icp.port = GetUdpService(); p->connection_auth = 2; /* auto */ - while ((token = strtok(NULL, w_space))) { + while ((token = ConfigParser::NextToken())) { if (!strcmp(token, "proxy-only")) { p->options.proxy_only = true; } else if (!strcmp(token, "no-query")) { @@ -2521,7 +2521,7 @@ parse_peer_access(void) char *host = NULL; CachePeer *p; - if (!(host = strtok(NULL, w_space))) + if (!(host = ConfigParser::NextToken())) self_destruct(); if ((p = peerFindByName(host)) == NULL) { @@ -2540,10 +2540,10 @@ parse_hostdomain(void) char *host = NULL; char *domain = NULL; - if (!(host = strtok(NULL, w_space))) + if (!(host = ConfigParser::NextToken())) self_destruct(); - while ((domain = strtok(NULL, list_sep))) { + while ((domain = ConfigParser::NextToken())) { CachePeerDomainList *l = NULL; CachePeerDomainList **L = NULL; CachePeer *p; @@ -2575,13 +2575,13 @@ parse_hostdomaintype(void) char *type = NULL; char *domain = NULL; - if (!(host = strtok(NULL, w_space))) + if (!(host = ConfigParser::NextToken())) self_destruct(); - if (!(type = strtok(NULL, w_space))) + if (!(type = ConfigParser::NextToken())) self_destruct(); - while ((domain = strtok(NULL, list_sep))) { + while ((domain = ConfigParser::NextToken())) { NeighborTypeDomainList *l = NULL; NeighborTypeDomainList **L = NULL; CachePeer *p; @@ -2629,7 +2629,7 @@ dump_onoff(StoreEntry * entry, const char *name, int var) void parse_onoff(int *var) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (token == NULL) self_destruct(); @@ -2670,7 +2670,7 @@ dump_tristate(StoreEntry * entry, const char *name, int var) static void parse_tristate(int *var) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (token == NULL) self_destruct(); @@ -2710,7 +2710,7 @@ parse_pipelinePrefetch(int *var) debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'."); *var = 0; } else { - ConfigParser::strtokFileUndo(); + ConfigParser::TokenUndo(); parse_int(var); } } @@ -2803,17 +2803,17 @@ parse_refreshpattern(RefreshPattern ** head) int errcode; int flags = REG_EXTENDED | REG_NOSUB; - if ((token = strtok(NULL, w_space)) == NULL) { + if ((token = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } if (strcmp(token, "-i") == 0) { flags |= REG_ICASE; - token = strtok(NULL, w_space); + token = ConfigParser::NextToken(); } else if (strcmp(token, "+i") == 0) { flags &= ~REG_ICASE; - token = strtok(NULL, w_space); + token = ConfigParser::NextToken(); } if (token == NULL) { @@ -2856,7 +2856,7 @@ parse_refreshpattern(RefreshPattern ** head) max = (time_t) (i * 60); /* convert minutes to seconds */ /* Options */ - while ((token = strtok(NULL, w_space)) != NULL) { + while ((token = ConfigParser::NextToken()) != NULL) { if (!strcmp(token, "refresh-ims")) { refresh_ims = 1; } else if (!strcmp(token, "store-stale")) { @@ -2987,7 +2987,7 @@ dump_string(StoreEntry * entry, const char *name, char *var) static void parse_string(char **var) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); safe_free(*var); if (token == NULL) @@ -2996,23 +2996,6 @@ parse_string(char **var) *var = xstrdup(token); } -void -ConfigParser::ParseString(char **var) -{ - parse_string(var); -} - -void -ConfigParser::ParseString(String *var) -{ - char *token = strtok(NULL, w_space); - - if (token == NULL) - self_destruct(); - - var->reset(token); -} - static void free_string(char **var) { @@ -3027,7 +3010,7 @@ parse_eol(char *volatile *var) return; } - unsigned char *token = (unsigned char *) strtok(NULL, null_string); + unsigned char *token = (unsigned char *) ConfigParser::NextQuotedOrToEol(); safe_free(*var); if (!token) { @@ -3261,9 +3244,7 @@ void parse_wordlist(wordlist ** list) { char *token; - char *t = strtok(NULL, ""); - - while ((token = strwordtok(NULL, &t))) + while ((token = ConfigParser::NextToken())) wordlistAdd(list, token); } @@ -3288,7 +3269,7 @@ check_null_acl_access(acl_access * a) static void parse_uri_whitespace(int *var) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (token == NULL) self_destruct(); @@ -3401,7 +3382,7 @@ free_memcachemode(SquidConfig * config) static void parse_memcachemode(SquidConfig * config) { - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (!token) self_destruct(); @@ -3471,7 +3452,7 @@ parse_IpAddress_list(Ip::Address_list ** head) Ip::Address_list *s; Ip::Address ipa; - while ((token = strtok(NULL, w_space))) { + while ((token = ConfigParser::NextToken())) { if (GetHostWithPort(token, &ipa)) { while (*head) @@ -3812,7 +3793,7 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName) return; } - char *token = strtok(NULL, w_space); + char *token = ConfigParser::NextToken(); if (!token) { self_destruct(); @@ -3823,7 +3804,7 @@ parsePortCfg(AnyP::PortCfg ** head, const char *optionName) parsePortSpecification(s, token); /* parse options ... */ - while ((token = strtok(NULL, w_space))) { + while ((token = ConfigParser::NextToken())) { parse_port_option(s, token); } @@ -4071,7 +4052,7 @@ parse_access_log(CustomLog ** logs) /* determine configuration style */ - const char *filename = strtok(NULL, w_space); + const char *filename = ConfigParser::NextToken(); if (!filename) { self_destruct(); return; @@ -4096,7 +4077,7 @@ parse_access_log(CustomLog ** logs) // if logformat name is not recognized, // put back the token; it must be an ACL name if (!setLogformat(cl, token, false)) - ConfigParser::strtokFileUndo(); + ConfigParser::TokenUndo(); } else { // style #4 do { if (strncasecmp(token, "on-error=", 9) == 0) { @@ -4115,7 +4096,7 @@ parse_access_log(CustomLog ** logs) setLogformat(cl, token+10, true); } else if (!strchr(token, '=')) { // put back the token; it must be an ACL name - ConfigParser::strtokFileUndo(); + ConfigParser::TokenUndo(); break; // done with name=value options, now to ACLs } else { debugs(3, DBG_CRITICAL, "Unknown access_log option " << token); @@ -4308,8 +4289,8 @@ parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap) if (!*cpuAffinityMap) *cpuAffinityMap = new CpuAffinityMap; - const char *const pToken = strtok(NULL, w_space); - const char *const cToken = strtok(NULL, w_space); + const char *const pToken = ConfigParser::NextToken(); + const char *const cToken = ConfigParser::NextToken(); Vector processes, cores; if (!parseNamedIntList(pToken, "process_numbers", processes)) { debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " << @@ -4441,7 +4422,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg) time_t m; cfg->service_failure_limit = GetInteger(); - if ((token = strtok(NULL, w_space)) == NULL) + if ((token = ConfigParser::NextToken()) == NULL) return; if (strcmp(token,"in") != 0) { @@ -4449,7 +4430,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg) self_destruct(); } - if ((token = strtok(NULL, w_space)) == NULL) { + if ((token = ConfigParser::NextToken()) == NULL) { self_destruct(); } @@ -4459,7 +4440,7 @@ static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg) if (0 == d) (void) 0; - else if ((token = strtok(NULL, w_space)) == NULL) { + else if ((token = ConfigParser::NextToken()) == NULL) { debugs(3, DBG_CRITICAL, "No time-units on '" << config_input_line << "'"); self_destruct(); } else if ((m = parseTimeUnits(token, false)) == 0) @@ -4489,7 +4470,7 @@ static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt) { char *al; sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt)); - if ((al = strtok(NULL, w_space)) == NULL) { + if ((al = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -4567,7 +4548,7 @@ static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign) { char *al; sslproxy_cert_sign *cs = (sslproxy_cert_sign *) xcalloc(1, sizeof(sslproxy_cert_sign)); - if ((al = strtok(NULL, w_space)) == NULL) { + if ((al = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -4659,7 +4640,7 @@ static void parse_sslproxy_ssl_bump(acl_access **ssl_bump) static BumpCfgStyle bumpCfgStyleLast = bcsNone; BumpCfgStyle bumpCfgStyleNow = bcsNone; char *bm; - if ((bm = strtok(NULL, w_space)) == NULL) { + if ((bm = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -4761,7 +4742,7 @@ static void parse_HeaderWithAclList(HeaderWithAclList **headers) if (!*headers) { *headers = new HeaderWithAclList; } - if ((fn = strtok(NULL, w_space)) == NULL) { + if ((fn = ConfigParser::NextToken()) == NULL) { self_destruct(); return; } @@ -4771,20 +4752,20 @@ static void parse_HeaderWithAclList(HeaderWithAclList **headers) if (hwa.fieldId == HDR_BAD_HDR) hwa.fieldId = HDR_OTHER; - String buf; - bool wasQuoted; - ConfigParser::ParseQuotedString(&buf, &wasQuoted); + Format::Format *nlf = new ::Format::Format("hdrWithAcl"); + ConfigParser::EnableMacros(); + String buf = ConfigParser::NextToken(); + ConfigParser::DisableMacros(); hwa.fieldValue = buf.termedBuf(); - hwa.quoted = wasQuoted; + hwa.quoted = ConfigParser::LastTokenWasQuoted(); if (hwa.quoted) { - Format::Format *nlf = new ::Format::Format("hdrWithAcl"); if (!nlf->parse(hwa.fieldValue.c_str())) { self_destruct(); return; } hwa.valueFormat = nlf; - } - + } else + delete nlf; aclParseAclList(LegacyParser, &hwa.aclList, (hwa.fieldName + ':' + hwa.fieldValue).c_str()); (*headers)->push_back(hwa); } diff --git a/src/cf.data.pre b/src/cf.data.pre index 23cbc881c9..b08964493e 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -65,6 +65,19 @@ COMMENT_START configuration files. + Values with spaces, quotes, and other special characters + + Squid supports directive parameters with spaces, quotes, and other + special characters. Surround such parameters with "double quotes". Use + the configuration_includes_quoted_values directive to enable or + disable that support. + + Squid supports reading configuration option parameters from external + files using the syntax: + parameters("/path/filename") + For example: + acl whitelist dstdomain parameters("/etc/squid/whitelist.txt") + Conditional configuration If-statements can be used to make configuration directives @@ -8448,6 +8461,19 @@ COMMENT_START ----------------------------------------------------------------------------- COMMENT_END +NAME: configuration_includes_quoted_values +COMMENT: on|off +TYPE: onoff +DEFAULT: on +LOC: ConfigParser::RecognizeQuotedValues +DOC_START + If set, Squid will recognize each "quoted string" after a configuration + directive as a single parameter. The quotes are stripped before the + parameter value is interpreted or used. + See "Values with spaces, quotes, and other special characters" + section for more details. +DOC_END + NAME: memory_pools COMMENT: on|off TYPE: onoff diff --git a/src/cf_gen.cc b/src/cf_gen.cc index 7d9e5591d1..246b3d9405 100644 --- a/src/cf_gen.cc +++ b/src/cf_gen.cc @@ -681,7 +681,8 @@ gen_parse(const EntryList &head, std::ostream &fout) "{\n" "\tchar\t*token;\n" "\tif ((token = strtok(buff, w_space)) == NULL) \n" - "\t\treturn 1;\t/* ignore empty lines */\n"; + "\t\treturn 1;\t/* ignore empty lines */\n" + "\tConfigParser::SetCfgLine(strtok(NULL, \"\"));\n"; for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) e->genParse(fout); diff --git a/src/external_acl.cc b/src/external_acl.cc index f4e04766f8..d8f85a1e96 100644 --- a/src/external_acl.cc +++ b/src/external_acl.cc @@ -44,6 +44,7 @@ #include "cache_cf.h" #include "client_side.h" #include "comm/Connection.h" +#include "ConfigParser.h" #include "ExternalACL.h" #include "ExternalACLEntry.h" #include "fde.h" @@ -330,14 +331,16 @@ parse_externalAclHelper(external_acl ** list) a->local_addr.setLocalhost(); a->quote = external_acl::QUOTE_METHOD_URL; - token = strtok(NULL, w_space); + token = ConfigParser::NextToken(); if (!token) self_destruct(); a->name = xstrdup(token); - token = strtok(NULL, w_space); + // Allow supported %macros inside quoted tokens + ConfigParser::EnableMacros(); + token = ConfigParser::NextToken(); /* Parse options */ while (token) { @@ -386,8 +389,9 @@ parse_externalAclHelper(external_acl ** list) break; } - token = strtok(NULL, w_space); + token = ConfigParser::NextToken(); } + ConfigParser::DisableMacros(); /* check that child startup value is sane. */ if (a->children.n_startup > a->children.n_max) @@ -503,7 +507,7 @@ parse_externalAclHelper(external_acl ** list) *p = format; p = &format->next; - token = strtok(NULL, w_space); + token = ConfigParser::NextToken(); } /* There must be at least one format token */ diff --git a/src/format/Config.cc b/src/format/Config.cc index 17c730933c..cb955a0bd8 100644 --- a/src/format/Config.cc +++ b/src/format/Config.cc @@ -1,4 +1,5 @@ #include "squid.h" +#include "ConfigParser.h" #include "cache_cf.h" #include "Debug.h" #include "format/Config.h" @@ -11,10 +12,10 @@ Format::FmtConfig::parseFormats() { char *name, *def; - if ((name = strtok(NULL, w_space)) == NULL) + if ((name = ConfigParser::NextToken()) == NULL) self_destruct(); - if ((def = strtok(NULL, "\r\n")) == NULL) { + if ((def = ConfigParser::NextQuotedOrToEol()) == NULL) { self_destruct(); return; } diff --git a/src/format/Format.h b/src/format/Format.h index a998327cad..4b4e6836f8 100644 --- a/src/format/Format.h +++ b/src/format/Format.h @@ -2,6 +2,7 @@ #define _SQUID_FORMAT_FORMAT_H #include "base/RefCount.h" +#include "ConfigParser.h" /* * Squid configuration allows users to define custom formats in * several components. @@ -29,7 +30,7 @@ class Format { public: Format(const char *name); - ~Format(); + virtual ~Format(); /* very inefficent parser, but who cares, this needs to be simple */ /* First off, let's tokenize, we'll optimize in a second pass. diff --git a/src/ip/QosConfig.cc b/src/ip/QosConfig.cc index 04c2acca2e..b300a4c20d 100644 --- a/src/ip/QosConfig.cc +++ b/src/ip/QosConfig.cc @@ -209,7 +209,7 @@ Ip::Qos::Config::parseConfigLine() self_destruct(); #endif - while ( (token = strtok(NULL, w_space)) ) { + while ( (token = ConfigParser::NextToken()) ) { // Work out TOS or mark. Default to TOS for backwards compatibility if (!(mark || tos)) { diff --git a/src/log/Config.cc b/src/log/Config.cc index fdac505793..bb0a872b75 100644 --- a/src/log/Config.cc +++ b/src/log/Config.cc @@ -1,5 +1,6 @@ #include "squid.h" #include "cache_cf.h" +#include "ConfigParser.h" #include "Debug.h" #include "log/Config.h" @@ -10,18 +11,20 @@ Log::LogConfig::parseFormats() { char *name, *def; - if ((name = strtok(NULL, w_space)) == NULL) + if ((name = ConfigParser::NextToken()) == NULL) self_destruct(); - if ((def = strtok(NULL, "\r\n")) == NULL) { + ::Format::Format *nlf = new ::Format::Format(name); + + ConfigParser::EnableMacros(); + if ((def = ConfigParser::NextQuotedOrToEol()) == NULL) { self_destruct(); return; } + ConfigParser::DisableMacros(); debugs(3, 2, "Log Format for '" << name << "' is '" << def << "'"); - ::Format::Format *nlf = new ::Format::Format(name); - if (!nlf->parse(def)) { self_destruct(); return; diff --git a/src/tests/stub_cache_cf.cc b/src/tests/stub_cache_cf.cc index 9bc906a2a9..8621747134 100644 --- a/src/tests/stub_cache_cf.cc +++ b/src/tests/stub_cache_cf.cc @@ -48,7 +48,6 @@ void requirePathnameExists(const char *name, const char *path) STUB_NOP void parse_time_t(time_t * var) STUB char * strtokFile(void) STUB_RETVAL(NULL) void ConfigParser::ParseUShort(unsigned short *var) STUB -void ConfigParser::ParseString(String*) STUB void dump_acl_access(StoreEntry * entry, const char *name, acl_access * head) STUB void dump_acl_list(StoreEntry*, ACLList*) STUB YesNoNone::operator void*() const { STUB_NOP; return NULL; } diff --git a/src/tests/testACLMaxUserIP.cc b/src/tests/testACLMaxUserIP.cc index db34cad0e3..c1e4fce924 100644 --- a/src/tests/testACLMaxUserIP.cc +++ b/src/tests/testACLMaxUserIP.cc @@ -6,6 +6,7 @@ #include "testACLMaxUserIP.h" #include "auth/AclMaxUserIp.h" +#include "ConfigParser.h" #if HAVE_STDEXCEPT #include @@ -29,9 +30,9 @@ void testACLMaxUserIP::testParseLine() { /* a config line to pass with a lead-in token to seed the parser. */ - char * line = xstrdup("token -s 1"); + char * line = xstrdup("-s 1"); /* seed the parser */ - strtok(line, w_space); + ConfigParser::SetCfgLine(line); ACLMaxUserIP anACL("max_user_ip"); anACL.parse(); /* we want a maximum of one, and strict to be true */ diff --git a/src/tests/testAuth.cc b/src/tests/testAuth.cc index f0fb6dd417..bb1cffc9ee 100644 --- a/src/tests/testAuth.cc +++ b/src/tests/testAuth.cc @@ -9,6 +9,7 @@ #include "auth/UserRequest.h" #include "auth/Scheme.h" #include "auth/Config.h" +#include "ConfigParser.h" #include "Mem.h" CPPUNIT_TEST_SUITE_REGISTRATION( testAuth ); @@ -92,6 +93,7 @@ setup_scheme(Auth::Config *scheme, char const **params, unsigned param_count) for (unsigned position=0; position < param_count; ++position) { char *param_str=xstrdup(params[position]); strtok(param_str, w_space); + ConfigParser::SetCfgLine(strtok(NULL, "")); scheme->parse(scheme, config.size(), param_str); } } diff --git a/src/tests/testConfigParser.cc b/src/tests/testConfigParser.cc index 2ac31e67d1..a7cd80dbcd 100644 --- a/src/tests/testConfigParser.cc +++ b/src/tests/testConfigParser.cc @@ -21,24 +21,15 @@ bool testConfigParser::doParseQuotedTest(const char *s, const char *expectInterp { char cfgline[2048]; char cfgparam[2048]; - snprintf(cfgline, 2048, "Config %s", s); - - // Points to the start of quoted string - const char *tmp = strchr(cfgline, ' '); - - if (tmp == NULL) { - fprintf(stderr, "Invalid config line: %s\n", s); - return false; - } + snprintf(cfgline, 2048, "%s", s); // Keep the initial value on cfgparam. The ConfigParser methods will write on cfgline - strncpy(cfgparam, tmp+1, sizeof(cfgparam)-1); + strncpy(cfgparam, cfgline, sizeof(cfgparam)-1); cfgparam[sizeof(cfgparam)-1] = '\0'; // Initialize parser to point to the start of quoted string - strtok(cfgline, w_space); - String unEscaped; - ConfigParser::ParseQuotedString(&unEscaped); + ConfigParser::SetCfgLine(cfgline); + String unEscaped = ConfigParser::NextToken(); const bool interpOk = (unEscaped.cmp(expectInterp) == 0); if (!interpOk) { diff --git a/src/tests/testCoss.cc b/src/tests/testCoss.cc index 72752186b8..ffec2b4c90 100644 --- a/src/tests/testCoss.cc +++ b/src/tests/testCoss.cc @@ -1,5 +1,6 @@ #define SQUID_UNIT_TEST 1 #include "squid.h" +#include "ConfigParser.h" #include "testCoss.h" #include "Store.h" #include "SwapDir.h" @@ -91,9 +92,9 @@ testCoss::testCossCreate() char *path=xstrdup(TESTDIR); - char *config_line=xstrdup("foo 100 max-size=102400 block-size=512 IOEngine=Blocking"); + char *config_line=xstrdup("100 max-size=102400 block-size=512 IOEngine=Blocking"); - strtok(config_line, w_space); + ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); @@ -155,9 +156,9 @@ testCoss::testCossSearch() char *path=xstrdup(TESTDIR); - char *config_line=xstrdup("foo 100 max-size=102400 block-size=512 IOEngine=Blocking"); + char *config_line=xstrdup("100 max-size=102400 block-size=512 IOEngine=Blocking"); - strtok(config_line, w_space); + ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); @@ -283,8 +284,8 @@ testCoss::testDefaultEngine() commonInit(); char *path=xstrdup(TESTDIR); - char *config_line=xstrdup("foo 100 max-size=102400 block-size=512"); - strtok(config_line, w_space); + char *config_line=xstrdup("100 max-size=102400 block-size=512"); + ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); safe_free(path); safe_free(config_line); diff --git a/src/tests/testRock.cc b/src/tests/testRock.cc index a15e3faf32..f1d7e3b1b3 100644 --- a/src/tests/testRock.cc +++ b/src/tests/testRock.cc @@ -1,6 +1,7 @@ #define SQUID_UNIT_TEST 1 #include "squid.h" +#include "ConfigParser.h" #include "DiskIO/DiskIOModule.h" #include "fs/rock/RockSwapDir.h" #include "globals.h" @@ -66,9 +67,9 @@ testRock::setUp() char *path=xstrdup(TESTDIR); - char *config_line=xstrdup("foo 10 max-size=16384"); + char *config_line=xstrdup("10 max-size=16384"); - strtok(config_line, w_space); + ConfigParser::SetCfgLine(config_line); store->parse(0, path); store_maxobjsize = 1024*1024*2; diff --git a/src/tests/testUfs.cc b/src/tests/testUfs.cc index 7e8563fc9a..92c89c6097 100644 --- a/src/tests/testUfs.cc +++ b/src/tests/testUfs.cc @@ -104,11 +104,11 @@ testUfs::testUfsSearch() char *path=xstrdup(TESTDIR); - char *config_line=xstrdup("foo 100 1 1"); + char *config_line=xstrdup("100 1 1"); visible_appname_string = xstrdup(PACKAGE "/" VERSION); - strtok(config_line, w_space); + ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); store_maxobjsize = 1024*1024*2; @@ -244,8 +244,8 @@ testUfs::testUfsDefaultEngine() mem_policy = createRemovalPolicy(Config.replPolicy); char *path=xstrdup(TESTDIR); - char *config_line=xstrdup("foo 100 1 1"); - strtok(config_line, w_space); + char *config_line=xstrdup("100 1 1"); + ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); safe_free(path); safe_free(config_line); diff --git a/src/wccp2.cc b/src/wccp2.cc index b2c695a3a9..c710bccc4d 100644 --- a/src/wccp2.cc +++ b/src/wccp2.cc @@ -39,6 +39,7 @@ #include "comm/Connection.h" #include "comm/Loops.h" #include "compat/strsep.h" +#include "ConfigParser.h" #include "event.h" #include "ip/Address.h" #include "md5.h" @@ -2013,7 +2014,7 @@ parse_wccp2_method(int *method) char *t; /* Snarf the method */ - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(80, DBG_CRITICAL, "wccp2_*_method: missing setting."); self_destruct(); } @@ -2060,7 +2061,7 @@ parse_wccp2_amethod(int *method) char *t; /* Snarf the method */ - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(80, DBG_CRITICAL, "wccp2_assignment_method: missing setting."); self_destruct(); } @@ -2116,7 +2117,7 @@ parse_wccp2_service(void *v) } /* Snarf the type */ - if ((t = strtok(NULL, w_space)) == NULL) { + if ((t = ConfigParser::NextToken()) == NULL) { debugs(80, DBG_CRITICAL, "wccp2ParseServiceInfo: missing service info type (standard|dynamic)"); self_destruct(); } @@ -2141,7 +2142,7 @@ parse_wccp2_service(void *v) memset(wccp_password, 0, sizeof(wccp_password)); /* Handle password, if any */ - if ((t = strtok(NULL, w_space)) != NULL) { + if ((t = ConfigParser::NextToken()) != NULL) { if (strncmp(t, "password=", 9) == 0) { security_type = WCCP2_MD5_SECURITY; strncpy(wccp_password, t + 9, WCCP2_PASSWORD_LEN); @@ -2317,7 +2318,7 @@ parse_wccp2_service_info(void *v) } /* Next: loop until we don't have any more tokens */ - while ((t = strtok(NULL, w_space)) != NULL) { + while ((t = ConfigParser::NextToken()) != NULL) { if (strncmp(t, "flags=", 6) == 0) { /* XXX eww, string pointer math */ flags = parse_wccp2_service_flags(t + 6);