[squid-dev] [PATCH] Support for regex with \-escaped characters

Amos Jeffries squid3 at treenet.co.nz
Tue Nov 18 00:56:07 UTC 2014


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Since we updated the squid.conf ConfigParser it is now possible to
handle regex patterns containing quoted-pair (\-escaped) characters
properly.

This patch adds support by detecting the '\' characters as token
delimiters, and explicitly skipping the following character regardless
of whether it is a SP or not.

For now the detection is only added during parsing of regex tokens or
files.

Amos
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)

iQEcBAEBAgAGBQJUapkkAAoJELJo5wb/XPRjnycIANHEE1JeAC/gnhzD2le7y9IO
yvY3zZu7LX8QixlBAj0wzO4u3ByDkS9jD3PrTXyX/tP2SKwk8D95F/IZPQbVBJG2
2LAU6Q6TW9a+7swTkxz+c5go0wZpZaIsMIwa3EvC/4oLajHX/mB3+mcCMGRMS70Y
q96xTfoeEflPOx9C7o/M56R4bWa7I1J+t5PnLqzq5KYbysmCLXeHJo7LgD+F/7lo
OIxeGFcbP4Oks3iK1K9M9vI7Nu1c10zQARg8X3iSQUoXs0l29OfFcp8p7MW3oIpo
PlW46IS0DkJOZhnxlsfRyZoJl3Zl0ocA6VK5yYHMqQlAS/iv9BuYiNWGHr+XSRQ=
=/qRU
-----END PGP SIGNATURE-----
-------------- next part --------------
=== modified file 'doc/release-notes/release-3.5.sgml'
--- doc/release-notes/release-3.5.sgml	2014-11-04 14:23:42 +0000
+++ doc/release-notes/release-3.5.sgml	2014-11-17 10:50:56 +0000
@@ -386,40 +386,45 @@
 	   slot/page size when small slot sizes are desired. The default and
 	   maximum slot size is 32KB.
 	<p>Removal of old rock cache dir followed by <em>squid -z</em> is required
 	   when upgrading from earlier versions of Squid.
 	<p><em>COSS</em> storage type is formally replaced by Rock storage type.
 	   COSS storage type and all COSS specific options are removed.
 
 	<tag>cache_peer</tag>
 	<p>New <em>standby=N</em> option to retain a set of N open and unused
 	   connections to the peer at virtually all times to reduce TCP handshake
 	   delays.
 	<p>These connections differ from HTTP persistent connections in that they
 	   have not been used for HTTP messaging (and may never be). They may be
 	   turned into persistent connections after their first use subject to the
 	   same keep-alive critera any HTTP connection is checked for.
 	<p>Squid-2 option <em>idle=</em> replaced by <em>standby=</em>.
 	<p>NOTE that standby connections are started earlier and available in
 	   more circumstances than squid-2 idle connections were. They are
 	   also spread over all IPs of the peer.
 
+	<tag>configuration_includes_quoted_values</tag>
+	<p>Regex expression values can not be parsed when this directive is
+	   configured to <em>ON</em>. Instead Squid now accepts regex \-escaped
+	   characters including escaped whitespace.
+
 	<tag>external_acl_type</tag>
 	<p>New format code <em>%ssl::>sni</em> to send SSL client SNI.
 	<p>New format code <em>%ssl::<cert_subject</em> to send SSL server certificate DN.
 	<p>New format code <em>%ssl::<cert_issuer</em> to send SSL server certificate issuer DN.
 	<p>New response kv-pair <em>clt_conn_tag=</em> to associates a given tag with the client TCP connection.
 
 	<tag>forward_max_tries</tag>
 	<p>Default value increased to <em>25 destinations</em> to allow better
 	   contact and IPv4 failover with domains using long lists of IPv6
 	   addresses.
 
 	<tag>ftp_epsv</tag>
 	<p>Converted into an Access List with allow/deny value driven by ACLs
 	   using Squid standard first line wins matching basis.
 	<p>The old values of <em>on</em> and <em>off</em> imply <em>allow all</em>
 	    and <em>deny all</em> respectively and are now deprecated.
 	   Do not combine use of on/off values with ACL configuration.
 
 	<tag>http_port</tag>
 	<p><em>protocol=</em> option altered to accept protocol version details.

=== modified file 'src/ConfigParser.cc'
--- src/ConfigParser.cc	2014-11-17 10:04:18 +0000
+++ src/ConfigParser.cc	2014-11-17 11:54:55 +0000
@@ -6,40 +6,41 @@
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #include "squid.h"
 #include "cache_cf.h"
 #include "ConfigParser.h"
 #include "Debug.h"
 #include "fatal.h"
 #include "globals.h"
 
 bool ConfigParser::RecognizeQuotedValues = true;
 bool ConfigParser::StrictMode = true;
 std::stack<ConfigParser::CfgFile *> ConfigParser::CfgFiles;
 ConfigParser::TokenType ConfigParser::LastTokenType = ConfigParser::SimpleToken;
 const char *ConfigParser::CfgLine = NULL;
 const char *ConfigParser::CfgPos = NULL;
 std::queue<char *> ConfigParser::CfgLineTokens_;
 std::queue<std::string> ConfigParser::Undo_;
 bool ConfigParser::AllowMacros_ = false;
 bool ConfigParser::ParseQuotedOrToEol_ = false;
+bool ConfigParser::RecognizeQuotedPair_ = false;
 bool ConfigParser::PreviewMode_ = false;
 
 static const char *SQUID_ERROR_TOKEN = "[invalid token]";
 
 void
 ConfigParser::destruct()
 {
     shutting_down = 1;
     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();
@@ -246,44 +247,53 @@
         return NULL;
     type = ConfigParser::SimpleToken;
     nextToken += strspn(nextToken, w_space);
 
     if (*nextToken == '#')
         return NULL;
 
     if (ConfigParser::RecognizeQuotedValues && (*nextToken == '"' || *nextToken == '\'')) {
         type = ConfigParser::QuotedToken;
         char *token = xstrdup(UnQuote(nextToken, &nextToken));
         CfgLineTokens_.push(token);
         return token;
     }
 
     const char *tokenStart = nextToken;
     const char *sep;
     if (ConfigParser::ParseQuotedOrToEol_)
         sep = "\n";
     else if (!ConfigParser::RecognizeQuotedValues || *nextToken == '(')
         sep = w_space;
+    else if (ConfigParser::RecognizeQuotedPair_)
+        sep = w_space "\\";
     else
         sep = w_space "(";
     nextToken += strcspn(nextToken, sep);
 
+    while (ConfigParser::RecognizeQuotedPair_ && *(nextToken-1) == '\\') {
+        if (*nextToken) { // do not permit \0 terminator to be escaped.
+            ++nextToken; // skip the quoted-pair (\-escaped) character
+            nextToken += strcspn(nextToken, sep);
+        }
+    }
+
     if (ConfigParser::RecognizeQuotedValues && *nextToken == '(') {
         if (strncmp(tokenStart, "parameters", nextToken - tokenStart) == 0)
             type = ConfigParser::FunctionParameters;
         else {
             if (PreviewMode_) {
                 char *err = xstrdup(SQUID_ERROR_TOKEN);
                 CfgLineTokens_.push(err);
                 return err;
             } else {
                 debugs(3, DBG_CRITICAL, "FATAL: Unknown cfg function: " << tokenStart);
                 self_destruct();
             }
         }
     } else
         type = ConfigParser::SimpleToken;
 
     char *token = NULL;
     if (nextToken - tokenStart) {
         if (ConfigParser::StrictMode && type == ConfigParser::SimpleToken) {
             bool tokenIsNumber = true;
@@ -415,53 +425,56 @@
     ParseQuotedOrToEol_ = false;
 
     // Assume end of current config line
     // Close all open configuration files for this config line
     while (!CfgFiles.empty()) {
         ConfigParser::CfgFile *wordfile = CfgFiles.top();
         CfgFiles.pop();
         delete wordfile;
     }
 
     return token;
 }
 
 char *
 ConfigParser::RegexStrtokFile()
 {
     if (ConfigParser::RecognizeQuotedValues) {
         debugs(3, DBG_CRITICAL, "FATAL: Can not read regex expression while configuration_includes_quoted_values is enabled");
         self_destruct();
     }
+    ConfigParser::RecognizeQuotedPair_ = true;
     char * token = strtokFile();
+    ConfigParser::RecognizeQuotedPair_ = false;
     return token;
 }
 
 char *
 ConfigParser::RegexPattern()
 {
     if (ConfigParser::RecognizeQuotedValues) {
         debugs(3, DBG_CRITICAL, "FATAL: Can not read regex expression while configuration_includes_quoted_values is enabled");
         self_destruct();
     }
-
+    ConfigParser::RecognizeQuotedPair_ = true;
     char * token = NextToken();
+    ConfigParser::RecognizeQuotedPair_ = false;
     return token;
 }
 
 char *
 ConfigParser::NextQuotedToken()
 {
     const bool saveRecognizeQuotedValues = ConfigParser::RecognizeQuotedValues;
     ConfigParser::RecognizeQuotedValues = true;
     char *token = NextToken();
     ConfigParser::RecognizeQuotedValues = saveRecognizeQuotedValues;
     return token;
 }
 
 const char *
 ConfigParser::QuoteString(const String &var)
 {
     static String quotedStr;
     const char *s = var.termedBuf();
     bool  needQuote = false;
 

=== modified file 'src/ConfigParser.h'
--- src/ConfigParser.h	2014-09-13 13:59:43 +0000
+++ src/ConfigParser.h	2014-11-17 11:55:07 +0000
@@ -184,26 +184,27 @@
 
     /**
      * 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
      */
     static char *TokenParse(const char * &nextToken, TokenType &type);
 
     /// Wrapper method for TokenParse.
     static char *NextElement(TokenType &type);
     static std::stack<CfgFile *> CfgFiles; ///< The stack of open cfg files
     static TokenType LastTokenType; ///< The type of last parsed element
     static const char *CfgLine; ///< The current line to parse
     static const char *CfgPos; ///< Pointer to the next element in cfgLine string
     static std::queue<char *> CfgLineTokens_; ///< Store the list of tokens for current configuration line
     static std::queue<std::string> Undo_; ///< The list with TokenPutBack() queued elements
     static bool AllowMacros_;
     static bool ParseQuotedOrToEol_; ///< The next tokens will be handled as quoted or to_eol token
+    static bool RecognizeQuotedPair_; ///< The next tokens may containing quoted-pair (\-escaped) characters
     static bool PreviewMode_; ///< The next token will not poped from cfg files, will just previewd.
 };
 
 int parseConfigFile(const char *file_name);
 
 #endif /* SQUID_CONFIGPARSER_H */

-------------- next part --------------
A non-text attachment was scrubbed...
Name: bug4135_regex_parse_mk1.patch.sig
Type: application/octet-stream
Size: 287 bytes
Desc: not available
URL: <http://lists.squid-cache.org/pipermail/squid-dev/attachments/20141118/f801e94f/attachment.obj>


More information about the squid-dev mailing list