[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r13021: Allow config values in quotes to contain special characters, (in tor/trunk: . doc src/common src/or)



Author: nickm
Date: 2008-01-02 01:59:15 -0500 (Wed, 02 Jan 2008)
New Revision: 13021

Modified:
   tor/trunk/
   tor/trunk/ChangeLog
   tor/trunk/doc/tor.1.in
   tor/trunk/src/common/util.c
   tor/trunk/src/or/test.c
Log:
 r15787@tombo:  nickm | 2008-01-02 01:59:07 -0500
 Allow config values in quotes to contain special characters, with full C escape syntax.  With tests.  Addresses bug 557.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r15787] on d9e39d38-0f13-419c-a857-e10a0ce2aa0c

Modified: tor/trunk/ChangeLog
===================================================================
--- tor/trunk/ChangeLog	2008-01-02 06:59:12 UTC (rev 13020)
+++ tor/trunk/ChangeLog	2008-01-02 06:59:15 UTC (rev 13021)
@@ -6,6 +6,11 @@
       implementation also avoids realloc();realloc(); patterns that
       can contribute to memory fragmentation.
 
+  o Minor features:
+    - Configuration files now accept C-style strings as values.  This
+      helps encode characters not allowed in the current configuration
+      file format, such as newline or #.  Addresses bug 557.
+
   o Minor performance improvements:
     - Reference-count and share copies of address policy entries; only
       5% of them were actually distinct.

Modified: tor/trunk/doc/tor.1.in
===================================================================
--- tor/trunk/doc/tor.1.in	2008-01-02 06:59:12 UTC (rev 13020)
+++ tor/trunk/doc/tor.1.in	2008-01-02 06:59:15 UTC (rev 13021)
@@ -53,8 +53,9 @@
 .LP
 .TP
 Other options can be specified either on the command-line (\fI--option
-value\fR), or in the configuration file (\fIoption value\fR).
-Options are case-insensitive.
+value\fR), or in the configuration file (\fIoption value\fR or
+\fIoption "value"\fR).  Options are case-insensitive.  C-style escaped
+characters are allowed inside quoted values.
 .LP
 .TP
 \fBBandwidthRate \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP

Modified: tor/trunk/src/common/util.c
===================================================================
--- tor/trunk/src/common/util.c	2008-01-02 06:59:12 UTC (rev 13020)
+++ tor/trunk/src/common/util.c	2008-01-02 06:59:15 UTC (rev 13021)
@@ -1924,6 +1924,95 @@
   return string;
 }
 
+#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7')
+
+/* DOCDOC */
+static const char *
+unescape_string(const char *s, char **result, size_t *size_out)
+{
+  const char *cp;
+  char *out;
+  tor_assert(s[0] == '\"');
+  cp = s+1;
+  while (1) {
+    switch (*cp) {
+      case '\0':
+      case '\n':
+        return NULL;
+      case '\"':
+        goto end_of_loop;
+      case '\\':
+        if ((cp[1] == 'x' || cp[1] == 'X')
+            && TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])) {
+          cp += 4;
+        } else if (TOR_ISODIGIT(cp[1])) {
+          cp += 2;
+          if (TOR_ISODIGIT(*cp)) ++cp;
+          if (TOR_ISODIGIT(*cp)) ++cp;
+        } else if (cp[1]) {
+          cp += 2;
+        } else {
+          return NULL;
+        }
+        break;
+      default:
+        ++cp;
+        break;
+    }
+  }
+ end_of_loop:
+  out = *result = tor_malloc(cp-s + 1);
+  cp = s+1;
+  while (1) {
+    switch (*cp)
+      {
+      case '\"':
+        *out = '\0';
+        if (size_out) *size_out = out - *result;
+        return cp+1;
+      case '\0':
+        tor_fragile_assert();
+        tor_free(*result);
+        return NULL;
+      case '\\':
+        switch (cp[1])
+          {
+          case 'n': *out++ = '\n'; cp += 2; break;
+          case 'r': *out++ = '\r'; cp += 2; break;
+          case 't': *out++ = '\t'; cp += 2; break;
+          case 'x': case 'X':
+            *out++ = ((hex_decode_digit(cp[2])<<4) +
+                      hex_decode_digit(cp[3]));
+            cp += 4;
+            break;
+          case '0': case '1': case '2': case '3': case '4': case '5':
+          case '6': case '7':
+            {
+              int n = cp[1]-'0';
+              cp += 2;
+              if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
+              if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
+              if (n > 255) { tor_free(*result); return NULL; }
+              *out++ = (char)n;
+            }
+            break;
+          case '\'':
+          case '\"':
+          case '\\':
+          case '\?':
+            *out++ = cp[1];
+            cp += 2;
+            break;
+          default:
+            tor_free(*result); return NULL;
+          }
+        break;
+      default:
+        *out++ = *cp++;
+      }
+  }
+}
+
 /** Given a string containing part of a configuration file or similar format,
  * advance past comments and whitespace and try to parse a single line.  If we
  * parse a line successfully, set *<b>key_out</b> to a new string holding the
@@ -1965,33 +2054,40 @@
     ++line;
   *key_out = tor_strndup(key, line-key);
 
-  /* Skip until the value, writing nuls so key will be nul-terminated */
+  /* Skip until the value. */
   while (*line == ' ' || *line == '\t')
     ++line;
 
   val = line;
 
   /* Find the end of the line. */
-  while (*line && *line != '\n' && *line != '#')
-    ++line;
-  if (*line == '\n') {
-    cp = line++;
+  if (*line == '\"') {
+    line = unescape_string(line, value_out, NULL);
+    while (*line == ' ' || *line == '\t')
+      ++line;
+    if (*line && *line != '#' && *line != '\n')
+      return NULL;
   } else {
-    cp = line;
+    while (*line && *line != '\n' && *line != '#')
+      ++line;
+    if (*line == '\n') {
+      cp = line++;
+    } else {
+      cp = line;
+    }
+    while (cp>val && TOR_ISSPACE(*(cp-1)))
+      --cp;
+
+    tor_assert(cp >= val);
+    *value_out = tor_strndup(val, cp-val);
   }
-  while (cp>val && TOR_ISSPACE(*(cp-1)))
-    --cp;
 
-  tor_assert(cp >= val);
-  *value_out = tor_strndup(val, cp-val);
-
   if (*line == '#') {
     do {
       ++line;
     } while (*line && *line != '\n');
-    if (*line == '\n')
-      ++line;
   }
+  while(TOR_ISSPACE(*line)) ++line;
 
   return line;
 }

Modified: tor/trunk/src/or/test.c
===================================================================
--- tor/trunk/src/or/test.c	2008-01-02 06:59:12 UTC (rev 13020)
+++ tor/trunk/src/or/test.c	2008-01-02 06:59:15 UTC (rev 13021)
@@ -826,14 +826,17 @@
   strlcpy(buf, "k v\n" " key    value with spaces   \n" "keykey val\n"
           "k2\n"
           "k3 \n" "\n" "   \n" "#comment\n"
-          "k4#a\n" "k5#abc\n" "k6 val #with comment\n", sizeof(buf));
+          "k4#a\n" "k5#abc\n" "k6 val #with comment\n"
+          "kseven   \"a quoted 'string\"\n"
+          "k8 \"a \\x71uoted\\n\\\"str\\\\ing\\t\\001\\01\\1\\\"\"\n"
+          , sizeof(buf));
   str = buf;
 
   str = parse_config_line_from_str(str, &k, &v);
   test_streq(k, "k");
   test_streq(v, "v");
   tor_free(k); tor_free(v);
-  test_assert(!strcmpstart(str, " key    value with"));
+  test_assert(!strcmpstart(str, "key    value with"));
 
   str = parse_config_line_from_str(str, &k, &v);
   test_streq(k, "key");
@@ -857,7 +860,7 @@
   test_streq(k, "k3");
   test_streq(v, "");
   tor_free(k); tor_free(v);
-  test_assert(!strcmpstart(str, "\n   \n"));
+  test_assert(!strcmpstart(str, "#comment"));
 
   str = parse_config_line_from_str(str, &k, &v);
   test_streq(k, "k4");
@@ -875,6 +878,18 @@
   test_streq(k, "k6");
   test_streq(v, "val");
   tor_free(k); tor_free(v);
+  test_assert(!strcmpstart(str, "kseven"));
+
+  str = parse_config_line_from_str(str, &k, &v);
+  test_streq(k, "kseven");
+  test_streq(v, "a quoted 'string");
+  tor_free(k); tor_free(v);
+  test_assert(!strcmpstart(str, "k8 "));
+
+  str = parse_config_line_from_str(str, &k, &v);
+  test_streq(k, "k8");
+  test_streq(v, "a quoted\n\"str\\ing\t\x01\x01\x01\"");
+  tor_free(k); tor_free(v);
   test_streq(str, "");
 
   /* Test for strcmpstart and strcmpend. */