]> granicus.if.org Git - libevent/commitdiff
Add an evbuffer_search_range() to search a bounded range of a buffer
authorNick Mathewson <nickm@torproject.org>
Fri, 7 Aug 2009 17:16:52 +0000 (17:16 +0000)
committerNick Mathewson <nickm@torproject.org>
Fri, 7 Aug 2009 17:16:52 +0000 (17:16 +0000)
This can be handy when you have one search to find the end of a header
section, and then you want to find a substring within the header
section without looking at the body.

svn:r1410

buffer.c
include/event2/buffer.h
test/regress_buffer.c

index e54d7df45268dc62caef24fd8e7800bbf283ae1d..c369f0cac4343449ee83e840212d54d806d3c262 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -1967,9 +1967,15 @@ evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
 
 struct evbuffer_ptr
 evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start)
+{
+       return evbuffer_search_range(buffer, what, len, start, NULL);
+}
+
+struct evbuffer_ptr
+evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end)
 {
         struct evbuffer_ptr pos;
-        struct evbuffer_chain *chain;
+        struct evbuffer_chain *chain, *last_chain = NULL;
        const unsigned char *p;
         char first;
 
@@ -1984,6 +1990,9 @@ evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const str
                 pos._internal.pos_in_chain = 0;
         }
 
+       if (end)
+               last_chain = end->_internal.chain;
+
         if (!len)
                 goto done;
 
@@ -1998,8 +2007,12 @@ evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const str
                 if (p) {
                         pos.pos += p - start_at;
                         pos._internal.pos_in_chain += p - start_at;
-                        if (!evbuffer_ptr_memcmp(buffer, &pos, what, len))
-                                goto done;
+                        if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
+                               if (end && pos.pos + len > end->pos)
+                                       goto not_found;
+                               else
+                                       goto done;
+                       }
                         ++pos.pos;
                         ++pos._internal.pos_in_chain;
                         if (pos._internal.pos_in_chain == chain->off) {
@@ -2007,12 +2020,15 @@ evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const str
                                 pos._internal.pos_in_chain = 0;
                         }
                 } else {
+                       if (chain == last_chain)
+                               goto not_found;
                         pos.pos += chain->off - pos._internal.pos_in_chain;
                         chain = pos._internal.chain = chain->next;
                         pos._internal.pos_in_chain = 0;
                 }
         }
 
+not_found:
         pos.pos = -1;
         pos._internal.chain = NULL;
 done:
index 50ea90f9a507ac2590e1e2f960be756aceaef599..2a8e8378f44abbd8fb232a20dbfbac294167dd7c 100644 (file)
@@ -456,6 +456,22 @@ int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
  */
 struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start);
 
+/**
+   Search for a string within part of an evbuffer.
+
+   @param buffer the evbuffer to be searched
+   @param what the string to be searched for
+   @param len the length of the search string
+   @param start NULL or a pointer to a valid struct evbuffer_ptr that
+     indicates where we should start searching.
+   @param end NULL or a pointer to a valid struct evbuffer_ptr that
+     indicates where we should stop searching.
+   @return a struct evbuffer_ptr whose 'pos' field has the offset of the
+     first occurrence of the string in the buffer after 'start'.  The 'pos'
+     field of the result is -1 if the string was not found.
+ */
+struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end);
+
 enum evbuffer_ptr_how {
        /** Sets the pointer to the position; can be called on with an
            uninitialized evbuffer_ptr. */
index ff7cccad3bf57d6d347de8b5a5d64bd3b4a85413..a6031a026831675840186884eb146e50c670d039 100644 (file)
@@ -715,7 +715,7 @@ test_evbuffer_search(void *ptr)
 {
        struct evbuffer *buf = evbuffer_new();
        struct evbuffer *tmp = evbuffer_new();
-       struct evbuffer_ptr pos;
+       struct evbuffer_ptr pos, end;
 
        /* set up our chains */
        evbuffer_add_printf(tmp, "hello");  /* 5 chars */
@@ -748,6 +748,18 @@ test_evbuffer_search(void *ptr)
        pos = evbuffer_search(buf, "tat", 3, &pos);
        tt_int_op(pos.pos, ==, 10);
 
+       /* test bounded search. */
+       /* Set "end" to the first t in "attack". */
+       evbuffer_ptr_set(buf, &end, 12, EVBUFFER_PTR_SET);
+       pos = evbuffer_search_range(buf, "foo", 3, NULL, &end);
+       tt_int_op(pos.pos, ==, 5);
+       pos = evbuffer_search_range(buf, "foocata", 7, NULL, &end);
+       tt_int_op(pos.pos, ==, 5);
+       pos = evbuffer_search_range(buf, "foocatat", 8, NULL, &end);
+       tt_int_op(pos.pos, ==, -1);
+       pos = evbuffer_search_range(buf, "ack", 3, NULL, &end);
+       tt_int_op(pos.pos, ==, -1);
+
 end:
        if (buf)
                evbuffer_free(buf);