aboutsummaryrefslogtreecommitdiff
path: root/src/lib/encoding
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-04-05 15:29:37 -0400
committerNick Mathewson <nickm@torproject.org>2019-04-25 14:13:03 -0400
commit73df91bbb55498b05faae16b49ab49545fdffa8f (patch)
treef924a1baaef554e381d50d8fe92529dd5bee0896 /src/lib/encoding
parent01b07c548b93bcc58adac612a02c69dcb4b63b28 (diff)
downloadtor-73df91bbb55498b05faae16b49ab49545fdffa8f.tar.gz
tor-73df91bbb55498b05faae16b49ab49545fdffa8f.zip
kvline: handle empty alues as well as empty keys
The two options are mutually exclusive, since otherwise an entry like "Foo" would be ambiguous. We want to have the ability to treat entries like this as keys, though, since some controller commands interpret them as flags.
Diffstat (limited to 'src/lib/encoding')
-rw-r--r--src/lib/encoding/kvline.c48
-rw-r--r--src/lib/encoding/kvline.h1
2 files changed, 42 insertions, 7 deletions
diff --git a/src/lib/encoding/kvline.c b/src/lib/encoding/kvline.c
index 307adc3f12..806f9d3db0 100644
--- a/src/lib/encoding/kvline.c
+++ b/src/lib/encoding/kvline.c
@@ -54,6 +54,15 @@ line_has_no_key(const config_line_t *line)
}
/**
+ * Return true iff the value in <b>line</b> is not set.
+ **/
+static bool
+line_has_no_val(const config_line_t *line)
+{
+ return line->value == NULL || strlen(line->value) == 0;
+}
+
+/**
* Return true iff the all the lines in <b>line</b> can be encoded
* using <b>flags</b>.
**/
@@ -98,6 +107,10 @@ kvline_can_encode_lines(const config_line_t *line, unsigned flags)
* If KV_OMIT_KEYS is set in <b>flags</b>, then pairs with empty keys are
* allowed, and are encoded as 'Value'. Otherwise, such pairs are not
* allowed.
+ *
+ * If KV_OMIT_VALS is set in <b>flags</b>, then an empty value is
+ * encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with
+ * KV_OMIT_KEYS.
*/
char *
kvline_encode(const config_line_t *line,
@@ -106,6 +119,9 @@ kvline_encode(const config_line_t *line,
if (!kvline_can_encode_lines(line, flags))
return NULL;
+ tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
+ (KV_OMIT_KEYS|KV_OMIT_VALS));
+
smartlist_t *elements = smartlist_new();
for (; line; line = line->next) {
@@ -126,7 +142,10 @@ kvline_encode(const config_line_t *line,
}
}
- if (esc) {
+ if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) {
+ eq = "";
+ v = "";
+ } else if (esc) {
tmp = esc_for_log(line->value);
v = tmp;
} else {
@@ -155,13 +174,21 @@ kvline_encode(const config_line_t *line,
*
* If KV_OMIT_KEYS is set in <b>flags</b>, then values without keys are
* allowed. Otherwise, such values are not allowed.
+ *
+ * If KV_OMIT_VALS is set in <b>flags</b>, then keys without values are
+ * allowed. Otherwise, such keys are not allowed. Mutually exclusive with
+ * KV_OMIT_KEYS.
*/
config_line_t *
kvline_parse(const char *line, unsigned flags)
{
+ tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
+ (KV_OMIT_KEYS|KV_OMIT_VALS));
+
const char *cp = line, *cplast = NULL;
- bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
- bool quoted = (flags & KV_QUOTED) != 0;
+ const bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
+ const bool omit_vals = (flags & KV_OMIT_VALS) != 0;
+ const bool quoted = (flags & KV_QUOTED) != 0;
config_line_t *result = NULL;
config_line_t **next_line = &result;
@@ -171,27 +198,33 @@ kvline_parse(const char *line, unsigned flags)
while (*cp) {
key = val = NULL;
+ /* skip all spaces */
{
size_t idx = strspn(cp, " \t\r\v\n");
cp += idx;
}
if (BUG(cp == cplast)) {
- /* If we didn't parse anything, this code is broken. */
+ /* If we didn't parse anything since the last loop, this code is
+ * broken. */
goto err; // LCOV_EXCL_LINE
}
cplast = cp;
if (! *cp)
break; /* End of string; we're done. */
- /* Possible formats are K=V, K="V", V, and "V", depending on flags. */
+ /* Possible formats are K=V, K="V", K, V, and "V", depending on flags. */
- /* Find the key. */
+ /* Find where the key ends */
if (*cp != '\"') {
size_t idx = strcspn(cp, " \t\r\v\n=");
if (cp[idx] == '=') {
key = tor_memdup_nulterm(cp, idx);
cp += idx + 1;
+ } else if (omit_vals) {
+ key = tor_memdup_nulterm(cp, idx);
+ cp += idx;
+ goto commit;
} else {
if (!omit_keys)
goto err;
@@ -214,6 +247,7 @@ kvline_parse(const char *line, unsigned flags)
cp += idx;
}
+ commit:
if (key && strlen(key) == 0) {
/* We don't allow empty keys. */
goto err;
@@ -221,7 +255,7 @@ kvline_parse(const char *line, unsigned flags)
*next_line = tor_malloc_zero(sizeof(config_line_t));
(*next_line)->key = key ? key : tor_strdup("");
- (*next_line)->value = val;
+ (*next_line)->value = val ? val : tor_strdup("");
next_line = &(*next_line)->next;
key = val = NULL;
}
diff --git a/src/lib/encoding/kvline.h b/src/lib/encoding/kvline.h
index 4eed30a223..6740f81d54 100644
--- a/src/lib/encoding/kvline.h
+++ b/src/lib/encoding/kvline.h
@@ -17,6 +17,7 @@ struct config_line_t;
#define KV_QUOTED (1u<<0)
#define KV_OMIT_KEYS (1u<<1)
+#define KV_OMIT_VALS (1u<<2)
struct config_line_t *kvline_parse(const char *line, unsigned flags);
char *kvline_encode(const struct config_line_t *line, unsigned flags);