summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2020-02-26 10:10:27 -0500
committerNick Mathewson <nickm@torproject.org>2020-03-05 10:13:50 -0500
commit9dc946ba67a5d457ce00bf2853f624c3c7c344aa (patch)
tree9eb8b13ccf0d6a77505f783add1dc2e03a76dd5f /src
parentba8d71d9c37dcce213a0386e96731de5ba7d80fa (diff)
downloadtor-9dc946ba67a5d457ce00bf2853f624c3c7c344aa.tar.gz
tor-9dc946ba67a5d457ce00bf2853f624c3c7c344aa.zip
Add a config_lines_partition() function to help with LINELIST_V.
This function works a little bit like strsep(), to get a chunk of configuration lines with a given header. We can use this to make hidden service config easier to parse.
Diffstat (limited to 'src')
-rw-r--r--src/lib/encoding/confline.c29
-rw-r--r--src/lib/encoding/confline.h1
-rw-r--r--src/test/test_util.c51
3 files changed, 81 insertions, 0 deletions
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c
index ff8bacba3c..eb1a4e30f0 100644
--- a/src/lib/encoding/confline.c
+++ b/src/lib/encoding/confline.c
@@ -253,6 +253,35 @@ config_lines_dup_and_filter(const config_line_t *inp,
return result;
}
+/**
+ * Given a linelist <b>inp</b> beginning with the key <b>header</b>, find the
+ * next line with that key, and remove that instance and all following lines
+ * from the list. Return the lines that were removed. Operate
+ * case-insensitively.
+ *
+ * For example, if the header is "H", and <b>inp</b> contains "H, A, B, H, C,
+ * H, D", this function will alter <b>inp</b> to contain only "H, A, B", and
+ * return the elements "H, C, H, D" as a separate list.
+ **/
+config_line_t *
+config_lines_partition(config_line_t *inp, const char *header)
+{
+ if (BUG(inp == NULL))
+ return NULL;
+ if (BUG(strcasecmp(inp->key, header)))
+ return NULL;
+
+ /* Advance ptr until it points to the link to the next segment of this
+ list. */
+ config_line_t **ptr = &inp->next;
+ while (*ptr && strcasecmp((*ptr)->key, header)) {
+ ptr = &(*ptr)->next;
+ }
+ config_line_t *remainder = *ptr;
+ *ptr = NULL;
+ return remainder;
+}
+
/** Return true iff a and b contain identical keys and values in identical
* order. */
int
diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h
index cd343e0e99..ce0d6c6e17 100644
--- a/src/lib/encoding/confline.h
+++ b/src/lib/encoding/confline.h
@@ -50,6 +50,7 @@ const config_line_t *config_line_find(const config_line_t *lines,
const char *key);
const config_line_t *config_line_find_case(const config_line_t *lines,
const char *key);
+config_line_t *config_lines_partition(config_line_t *inp, const char *header);
int config_lines_eq(const config_line_t *a, const config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);
void config_free_lines_(config_line_t *front);
diff --git a/src/test/test_util.c b/src/test/test_util.c
index fecd279096..234ae06745 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1850,6 +1850,56 @@ test_util_config_line_crlf(void *arg)
tor_free(k); tor_free(v);
}
+static void
+test_util_config_line_partition(void *arg)
+{
+ (void)arg;
+ config_line_t *lines = NULL, *orig, *rest = NULL;
+
+ config_line_append(&lines, "Header", "X");
+ config_line_append(&lines, "Item", "Y");
+ config_line_append(&lines, "Thing", "Z");
+
+ config_line_append(&lines, "HEADER", "X2");
+
+ config_line_append(&lines, "header", "X3");
+ config_line_append(&lines, "Item3", "Foob");
+
+ /* set up h2 and h3 to point to the places where we hope the headers will
+ be. */
+ config_line_t *h2 = lines->next->next->next;
+ config_line_t *h3 = h2->next;
+ tt_str_op(h2->key, OP_EQ, "HEADER");
+ tt_str_op(h3->key, OP_EQ, "header");
+
+ orig = lines;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, h2);
+ tt_str_op(lines->next->key, OP_EQ, "Item");
+ tt_str_op(lines->next->next->key, OP_EQ, "Thing");
+ tt_ptr_op(lines->next->next->next, OP_EQ, NULL);
+ config_free_lines(lines);
+
+ orig = lines = rest;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, h3);
+ tt_ptr_op(lines->next, OP_EQ, NULL);
+ config_free_lines(lines);
+
+ orig = lines = rest;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, NULL);
+ tt_str_op(lines->next->key, OP_EQ, "Item3");
+ tt_ptr_op(lines->next->next, OP_EQ, NULL);
+
+ done:
+ config_free_lines(lines);
+ config_free_lines(rest);
+}
+
#ifndef DISABLE_PWDB_TESTS
static void
test_util_expand_filename(void *arg)
@@ -6379,6 +6429,7 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(config_line_comment_character),
UTIL_LEGACY(config_line_escaped_content),
UTIL_LEGACY(config_line_crlf),
+ UTIL_TEST(config_line_partition, 0),
UTIL_TEST_PWDB(expand_filename, 0),
UTIL_LEGACY(escape_string_socks),
UTIL_LEGACY(string_is_key_value),