Browse Source

Refactor out the 'find string at start of any line' logic.

We do this in too many places throughout the code; it's time to start
clamping down.

Also, refactor Karsten's patch to use strchr-then-strndup, rather than
malloc-then-strlcpy-then-strchr-then-clear.
Nick Mathewson 15 years ago
parent
commit
235f1e1a96
4 changed files with 77 additions and 29 deletions
  1. 23 0
      src/common/util.c
  2. 2 0
      src/common/util.h
  3. 21 29
      src/or/geoip.c
  4. 31 0
      src/test/test_util.c

+ 23 - 0
src/common/util.c

@@ -682,6 +682,29 @@ find_whitespace_eos(const char *s, const char *eos)
   return s;
 }
 
+/** Return the the first occurrence of <b>needle</b> in <b>haystack</b> that
+ * occurs at the start of a line (that is, at the beginning of <b>haystack</b>
+ * or immediately after a newline).  Return NULL if no such string is found.
+ */
+const char *
+find_str_at_start_of_line(const char *haystack, const char *needle)
+{
+  size_t needle_len = strlen(needle);
+
+  do {
+    if (!strncmp(haystack, needle, needle_len))
+      return haystack;
+
+    haystack = strchr(haystack, '\n');
+    if (!haystack)
+      return NULL;
+    else
+      ++haystack;
+  } while (*haystack);
+
+  return NULL;
+}
+
 /** Return true iff the 'len' bytes at 'mem' are all zero. */
 int
 tor_mem_is_zero(const char *mem, size_t len)

+ 2 - 0
src/common/util.h

@@ -195,6 +195,8 @@ const char *eat_whitespace_no_nl(const char *s) ATTR_PURE;
 const char *eat_whitespace_eos_no_nl(const char *s, const char *eos) ATTR_PURE;
 const char *find_whitespace(const char *s) ATTR_PURE;
 const char *find_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
+const char *find_str_at_start_of_line(const char *haystack, const char *needle)
+  ATTR_PURE;
 int tor_mem_is_zero(const char *mem, size_t len) ATTR_PURE;
 int tor_digest_is_zero(const char *digest) ATTR_PURE;
 int tor_digest256_is_zero(const char *digest) ATTR_PURE;

+ 21 - 29
src/or/geoip.c

@@ -1099,11 +1099,10 @@ parse_bridge_stats_controller(const char *stats_str, time_t now)
 {
   char stats_end_str[ISO_TIME_LEN+1], stats_start_str[ISO_TIME_LEN+1],
        *controller_str, *eos, *eol, *summary;
-  const char *stats_end_first = "bridge-stats-end ",
-             *stats_end_middle = "\nbridge-stats-end ",
-             *ips_first = "bridge-ips",
-             *ips_middle = "\nbridge-ips",
-             *tmp;
+
+  const char *BRIDGE_STATS_END = "bridge-stats-end ";
+  const char *BRIDGE_IPS = "bridge-ips ";
+  const char *tmp;
   time_t stats_end_time;
   size_t controller_len;
   int seconds;
@@ -1111,14 +1110,11 @@ parse_bridge_stats_controller(const char *stats_str, time_t now)
 
   /* Parse timestamp and number of seconds from
     "bridge-stats-end YYYY-MM-DD HH:MM:SS (N s)" */
-  if (!strncmp(stats_str, stats_end_first, strlen(stats_end_first))) {
-    tmp = stats_str + strlen(stats_end_first);
-  } else {
-    tmp = strstr(stats_str, stats_end_middle);
-    if (!tmp)
-      return NULL;
-    tmp += strlen(stats_end_middle);
-  }
+  tmp = find_str_at_start_of_line(stats_str, BRIDGE_STATS_END);
+  if (!tmp)
+    return NULL;
+  tmp += strlen(BRIDGE_STATS_END);
+
   if (strlen(tmp) < ISO_TIME_LEN + 6)
     return NULL;
   strlcpy(stats_end_str, tmp, sizeof(stats_end_str));
@@ -1133,23 +1129,19 @@ parse_bridge_stats_controller(const char *stats_str, time_t now)
   format_iso_time(stats_start_str, stats_end_time - seconds);
 
   /* Parse: "bridge-ips CC=N,CC=N,..." */
-  if (!strncmp(stats_str, ips_first, strlen(ips_first))) {
-    tmp = stats_str + strlen(ips_first);
-  } else {
-    tmp = strstr(stats_str, ips_middle);
-    if (!tmp)
-      return NULL;
-    tmp += strlen(ips_middle);
-  }
-  if (strlen(tmp) > 2 && !strncmp(tmp, " ", 1))
-    tmp += 1;
-  else
-    tmp = "";
-  summary = tor_malloc(strlen(tmp) + 1);
-  strlcpy(summary, tmp, strlen(tmp) + 1);
-  eol = strstr(summary, "\n");
+  tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS);
+  if (!tmp)
+    return NULL;
+  tmp += strlen(BRIDGE_IPS);
+
+  tmp = eat_whitespace_no_nl(tmp);
+
+  eol = strchr(tmp, '\n');
   if (eol)
-    eol[0] = '\0';
+    summary = tor_strndup(tmp, eol-tmp);
+  else
+    summary = tor_strdup(tmp);
+
   controller_len = strlen("TimeStarted=\"\" CountrySummary=") +
                           strlen(summary) + 42;
   controller_str = tor_malloc(controller_len);

+ 31 - 0
src/test/test_util.c

@@ -1023,9 +1023,39 @@ test_util_strtok(void)
   ;
 }
 
+static void
+test_util_find_str_at_start_of_line(void *ptr)
+{
+  const char *long_string =
+    "hello world. hello world. hello hello. howdy.\n"
+    "hello hello world\n";
+
+  (void)ptr;
+
+  /* not-found case. */
+  tt_assert(! find_str_at_start_of_line(long_string, "fred"));
+
+  /* not-found case where haystack doesn't end with \n */
+  tt_assert(! find_str_at_start_of_line("foobar\nbaz", "fred"));
+
+  /* start-of-string case */
+  tt_assert(long_string ==
+            find_str_at_start_of_line(long_string, "hello world."));
+
+  /* start-of-line case */
+  tt_assert(strchr(long_string,'\n')+1 ==
+            find_str_at_start_of_line(long_string, "hello hello"));
+ done:
+  ;
+}
+
+
 #define UTIL_LEGACY(name)                                               \
   { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
 
+#define UTIL_TEST(name, flags)                          \
+  { #name, test_util_ ## name, flags, NULL, NULL }
+
 struct testcase_t util_tests[] = {
   UTIL_LEGACY(time),
   UTIL_LEGACY(config_line),
@@ -1040,6 +1070,7 @@ struct testcase_t util_tests[] = {
   UTIL_LEGACY(threads),
   UTIL_LEGACY(sscanf),
   UTIL_LEGACY(strtok),
+  UTIL_TEST(find_str_at_start_of_line, 0),
   END_OF_TESTCASES
 };