mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 15:43:32 +01:00
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. svn:r13021
This commit is contained in:
parent
86f5180853
commit
58de695f90
@ -6,6 +6,11 @@ Changes in version 0.2.0.16-alpha - 2008-01-??
|
|||||||
implementation also avoids realloc();realloc(); patterns that
|
implementation also avoids realloc();realloc(); patterns that
|
||||||
can contribute to memory fragmentation.
|
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:
|
o Minor performance improvements:
|
||||||
- Reference-count and share copies of address policy entries; only
|
- Reference-count and share copies of address policy entries; only
|
||||||
5% of them were actually distinct.
|
5% of them were actually distinct.
|
||||||
|
@ -53,8 +53,9 @@ Display Tor version.
|
|||||||
.LP
|
.LP
|
||||||
.TP
|
.TP
|
||||||
Other options can be specified either on the command-line (\fI--option
|
Other options can be specified either on the command-line (\fI--option
|
||||||
value\fR), or in the configuration file (\fIoption value\fR).
|
value\fR), or in the configuration file (\fIoption value\fR or
|
||||||
Options are case-insensitive.
|
\fIoption "value"\fR). Options are case-insensitive. C-style escaped
|
||||||
|
characters are allowed inside quoted values.
|
||||||
.LP
|
.LP
|
||||||
.TP
|
.TP
|
||||||
\fBBandwidthRate \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
\fBBandwidthRate \fR\fIN\fR \fBbytes\fR|\fBKB\fR|\fBMB\fR|\fBGB\fR|\fBTB\fP
|
||||||
|
@ -1924,6 +1924,95 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out)
|
|||||||
return string;
|
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,
|
/** 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
|
* 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
|
* parse a line successfully, set *<b>key_out</b> to a new string holding the
|
||||||
@ -1965,13 +2054,20 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
|
|||||||
++line;
|
++line;
|
||||||
*key_out = tor_strndup(key, line-key);
|
*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')
|
while (*line == ' ' || *line == '\t')
|
||||||
++line;
|
++line;
|
||||||
|
|
||||||
val = line;
|
val = line;
|
||||||
|
|
||||||
/* Find the end of the line. */
|
/* Find the end of the line. */
|
||||||
|
if (*line == '\"') {
|
||||||
|
line = unescape_string(line, value_out, NULL);
|
||||||
|
while (*line == ' ' || *line == '\t')
|
||||||
|
++line;
|
||||||
|
if (*line && *line != '#' && *line != '\n')
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
while (*line && *line != '\n' && *line != '#')
|
while (*line && *line != '\n' && *line != '#')
|
||||||
++line;
|
++line;
|
||||||
if (*line == '\n') {
|
if (*line == '\n') {
|
||||||
@ -1984,14 +2080,14 @@ parse_config_line_from_str(const char *line, char **key_out, char **value_out)
|
|||||||
|
|
||||||
tor_assert(cp >= val);
|
tor_assert(cp >= val);
|
||||||
*value_out = tor_strndup(val, cp-val);
|
*value_out = tor_strndup(val, cp-val);
|
||||||
|
}
|
||||||
|
|
||||||
if (*line == '#') {
|
if (*line == '#') {
|
||||||
do {
|
do {
|
||||||
++line;
|
++line;
|
||||||
} while (*line && *line != '\n');
|
} while (*line && *line != '\n');
|
||||||
if (*line == '\n')
|
|
||||||
++line;
|
|
||||||
}
|
}
|
||||||
|
while(TOR_ISSPACE(*line)) ++line;
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
@ -826,14 +826,17 @@ test_util(void)
|
|||||||
strlcpy(buf, "k v\n" " key value with spaces \n" "keykey val\n"
|
strlcpy(buf, "k v\n" " key value with spaces \n" "keykey val\n"
|
||||||
"k2\n"
|
"k2\n"
|
||||||
"k3 \n" "\n" " \n" "#comment\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 = buf;
|
||||||
|
|
||||||
str = parse_config_line_from_str(str, &k, &v);
|
str = parse_config_line_from_str(str, &k, &v);
|
||||||
test_streq(k, "k");
|
test_streq(k, "k");
|
||||||
test_streq(v, "v");
|
test_streq(v, "v");
|
||||||
tor_free(k); tor_free(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);
|
str = parse_config_line_from_str(str, &k, &v);
|
||||||
test_streq(k, "key");
|
test_streq(k, "key");
|
||||||
@ -857,7 +860,7 @@ test_util(void)
|
|||||||
test_streq(k, "k3");
|
test_streq(k, "k3");
|
||||||
test_streq(v, "");
|
test_streq(v, "");
|
||||||
tor_free(k); tor_free(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);
|
str = parse_config_line_from_str(str, &k, &v);
|
||||||
test_streq(k, "k4");
|
test_streq(k, "k4");
|
||||||
@ -875,6 +878,18 @@ test_util(void)
|
|||||||
test_streq(k, "k6");
|
test_streq(k, "k6");
|
||||||
test_streq(v, "val");
|
test_streq(v, "val");
|
||||||
tor_free(k); tor_free(v);
|
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_streq(str, "");
|
||||||
|
|
||||||
/* Test for strcmpstart and strcmpend. */
|
/* Test for strcmpstart and strcmpend. */
|
||||||
|
Loading…
Reference in New Issue
Block a user