[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. */