]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Initial support for "values with spaces" in ACL directives.
authorAlex Rousskov <rousskov@measurement-factory.com>
Sat, 23 Mar 2013 02:07:38 +0000 (20:07 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Sat, 23 Mar 2013 02:07:38 +0000 (20:07 -0600)
Needs more work to support escape sequences, macros, and include files, but
can be disabled using "configuration_includes_quoted_values off" in squid.conf.

Needs better documentation.

src/ConfigParser.cc
src/ConfigParser.h
src/acl/Acl.cc
src/acl/Acl.h
src/acl/Data.h
src/cache_cf.cc
src/cf.data.pre

index ceac61590aedc9f9a8886192456c451aaab8672a..dfe393542cdf47593d92a3170fd910259984f720 100644 (file)
@@ -41,6 +41,9 @@
 char *ConfigParser::lastToken = NULL;
 std::queue<std::string> ConfigParser::undo;
 
+
+int ConfigParser::RecognizeQuotedValues = true;
+
 void
 ConfigParser::destruct()
 {
@@ -63,6 +66,18 @@ ConfigParser::strtokFilePutBack(const char *tok)
     undo.push(tok);
 }
 
+char *
+xstrtok(char *str, const char *delimiters)
+{   
+    assert(!str); // we are parsing the configuration file
+    // no support unless enabled in the configuration and
+    // no support for other delimiters (they may need to be eradicated!)
+    return (ConfigParser::RecognizeQuotedValues &&
+            strcmp(delimiters, " \t\n\r") == 0) ?
+        ConfigParser::NextToken() : ::strtok(str, delimiters);
+}
+
+
 char *
 ConfigParser::strtokFile(void)
 {
@@ -77,9 +92,13 @@ ConfigParser::strtokFile(void)
         strncpy(undoToken, undo.front().c_str(), sizeof(undoToken));
         undoToken[sizeof(undoToken) - 1] = '\0';
         undo.pop();
-        return undoToken;
+        return lastToken = undoToken;
     }
 
+    // XXX: add file:name support to the quoted string-aware parser
+    if (RecognizeQuotedValues)
+        return lastToken = ConfigParser::NextToken();
+
     lastToken = NULL;
     do {
 
@@ -142,29 +161,62 @@ ConfigParser::strtokFile(void)
     return lastToken = t;
 }
 
+/// returns token after stripping any comments
+/// must be called in non-quoted context only
+char *
+ConfigParser::StripComment(char *token)
+{
+    if (!token)
+        return NULL;
+
+    // we are outside the quoted string context
+    // assume that anything starting with a '#' is a comment
+    if (char *comment = strchr(token, '#')) {
+        *comment = '\0'; // remove the comment from this token
+        (void)strtok(NULL, ""); // remove the comment from the current line
+        if (!*token)
+            return NULL; // token was a comment
+    }
+
+    return token;
+}
+
 void
 ConfigParser::ParseQuotedString(char **var, bool *wasQuoted)
 {
-    String sVar;
-    ParseQuotedString(&sVar, wasQuoted);
-    *var = xstrdup(sVar.termedBuf());
+    if (const char *phrase = NextElement(wasQuoted))
+        *var = xstrdup(phrase);
+    else
+        self_destruct();
 }
 
 void
 ConfigParser::ParseQuotedString(String *var, bool *wasQuoted)
 {
+    if (const char *phrase = NextElement(wasQuoted))
+        var->reset(phrase);
+    else
+        self_destruct();
+}
+
+char *
+ConfigParser::NextElement(bool *wasQuoted)
+{
+    if (wasQuoted)
+        *wasQuoted = false;
+
     // Get all of the remaining string
     char *token = strtok(NULL, "");
     if (token == NULL)
-        self_destruct();
+        return NULL;
 
-    if (*token != '"') {
-        token = strtok(token, w_space);
-        var->reset(token);
-        if (wasQuoted)
-            *wasQuoted = false;
-        return;
-    } else if (wasQuoted)
+    // skip leading whitespace (may skip the entire token that way)
+    while (xisspace(*token)) ++token;
+
+    if (*token != '"')
+        return StripComment(strtok(token, w_space));
+
+    if (wasQuoted)
         *wasQuoted = true;
 
     char  *s = token + 1;
@@ -178,15 +230,27 @@ ConfigParser::ParseQuotedString(String *var, bool *wasQuoted)
     }
 
     if (*s != '"') {
-        debugs(3, DBG_CRITICAL, "ParseQuotedString: missing '\"' at the end of quoted string" );
+        debugs(3, DBG_CRITICAL, "missing '\"' at the end of quoted string" );
         self_destruct();
     }
     strtok(s-1, "\""); /*Reset the strtok to point after the "  */
     *s = '\0';
 
-    var->reset(token+1);
+    return (token+1);
 }
 
+char *
+ConfigParser::NextToken()
+{
+    return NextElement(NULL);
+    // TODO: support file:name syntax to auto-include files, but think how
+    // admins will be able to disable that interpretation w/o disabling
+    // macros and other special value processing. The "file:" prefix or
+    // any similar key construct would probably have to go outside the
+    // optionally quoted string for that to work: file:"name with $macros".
+}
+
+
 const char *
 ConfigParser::QuoteString(String &var)
 {
index c5807d8f5fafced57eaf19cef350488f06964659..8564c34dd0f98b7153a39683b553aaf3fcbb247a 100644 (file)
@@ -82,6 +82,22 @@ public:
     static char * strtokFile();
     static void strtokFileUndo();
     static void strtokFilePutBack(const char *);
+
+    /**
+      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();
+
+    /// configuration_includes_quoted_values in squid.conf
+    static int RecognizeQuotedValues;
+
+protected:
+    static char *NextElement(bool *wasQuoted);
+    static char *StripComment(char *token);
+
 private:
     static char *lastToken;
     static std::queue<std::string> undo;
@@ -89,4 +105,9 @@ private:
 
 int parseConfigFile(const char *file_name);
 
+/// XXX: Used for temporary hacks to allow old code to handle quoted values
+/// without replacing every strtok() call.
+extern char *xstrtok(char *str, const char *delimiters);
+
+
 #endif /* SQUID_CONFIGPARSER_H */
index 2eeef57fab252947d184e738bf353b902f68aebb..f550cdac7d46344f7d96a7510dc4225a1191fb55 100644 (file)
@@ -431,6 +431,14 @@ acl_access::operator delete (void *address)
     cbdataFree(t);
 }
 
+/// XXX: Temporary hack to allow old ACL code to handle quoted values without
+/// replacing every strtok() call.
+char *
+ACL::strtok(char *str, const char *delimiters)
+{
+    return xstrtok(str, delimiters);
+}
+
 ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
 
 ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
index e7ae5af6f372641b0b49db1a4cc92e40bc205aa0..168293ba5b739d2fb3538eb121d86987927ec769 100644 (file)
@@ -151,6 +151,9 @@ public:
         typedef Vector<Prototype const*>::const_iterator const_iterator;
         void registerMe();
     };
+
+protected:
+    static char *strtok(char *str, const char *delimiters);
 };
 
 /// \ingroup ACLAPI
index 1ea9e061e37aeefc994c01117e4e91f48ab7c43d..342a15b3a20075ae084e272bbc0d66d26564104f 100644 (file)
@@ -33,6 +33,8 @@
 #define SQUID_ACLDATA_H
 
 class wordlist;
+extern char *xstrtok(char *str, const char *delimiters);
+
 
 /// \ingroup ACLAPI
 template <class M>
@@ -50,6 +52,11 @@ public:
     virtual void prepareForUse() {}
 
     virtual bool empty() const =0;
+
+
+    /// XXX: Temporary hack to allow old ACL code to handle quoted values without
+    /// replacing every strtok() call.
+    char *strtok(char *str, const char *dels) { return xstrtok(str, dels); }
 };
 
 #endif /* SQUID_ACLDATA_H */
index da7e93d6b2a20a50d01c937bdbbb93b5367807f4..fcd2701efc8e0b96a2730a25115681e2f959da91 100644 (file)
@@ -1302,6 +1302,7 @@ dump_acl(StoreEntry * entry, const char *name, ACL * ae)
 
         while (v != NULL) {
             debugs(3, 3, "dump_acl: " << name << " " << ae->name << " " << v->key);
+            // XXX: use something like ConfigParser::QuoteString() here
             storeAppendPrintf(entry, "%s ", v->key);
             v = v->next;
         }
index e38603b1b52ff5124d474471261db876ff2160f8..7d642a3aa706c3f56c7550e75937b0975e0bdc8e 100644 (file)
@@ -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.
+
+       XXX: Document escaping and macro substitution rules inside quoted
+       strings.
+
+       XXX: Support single-quoted strings that prevent macro substitution.
+
+
   Conditional configuration
 
        If-statements can be used to make configuration directives
@@ -8142,6 +8155,17 @@ 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" as a single
+       configuration directive parameter. The quotes are stripped before the
+       parameter value is interpreted or used. XXX: Give more details.
+DOC_END
+
 NAME: memory_pools
 COMMENT: on|off
 TYPE: onoff