From 8a99083f0123765b6b73d7b5efccae1e88fff608 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 7 Aug 2009 17:16:52 +0000 Subject: [PATCH] Add an evbuffer_search_range() to search a bounded range of a buffer 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 | 22 +++++++++++++++++++--- include/event2/buffer.h | 16 ++++++++++++++++ test/regress_buffer.c | 14 +++++++++++++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/buffer.c b/buffer.c index e54d7df4..c369f0ca 100644 --- 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: diff --git a/include/event2/buffer.h b/include/event2/buffer.h index 50ea90f9..2a8e8378 100644 --- a/include/event2/buffer.h +++ b/include/event2/buffer.h @@ -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. */ diff --git a/test/regress_buffer.c b/test/regress_buffer.c index ff7cccad..a6031a02 100644 --- a/test/regress_buffer.c +++ b/test/regress_buffer.c @@ -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);