summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzat Khuzhin <a3at.mail@gmail.com>2018-10-27 17:21:35 +0300
committerAzat Khuzhin <a3at.mail@gmail.com>2018-10-27 17:59:11 +0300
commit26ef859aa707fda72ce530bf761d1c41a76f67b7 (patch)
treea0b46476427f451749e6a5f2615c3fe558d3ab08
parentd161ec3842259f2896fc9b15a1e4d5a1ed178bb2 (diff)
downloadlibevent-26ef859aa707fda72ce530bf761d1c41a76f67b7.tar.gz
Add evhttp_parse_query_str_flags()
And a set of flags: - EVHTTP_URI_QUERY_LAST - EVHTTP_URI_QUERY_NONCONFORMANT Fixes: #15
-rw-r--r--http.c23
-rw-r--r--include/event2/http.h30
-rw-r--r--test/regress_http.c57
3 files changed, 104 insertions, 6 deletions
diff --git a/http.c b/http.c
index 181352b6..cd3f2f05 100644
--- a/http.c
+++ b/http.c
@@ -3216,7 +3216,7 @@ evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
static int
evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
- int is_whole_uri)
+ int is_whole_uri, unsigned flags)
{
char *line=NULL;
char *argument;
@@ -3254,8 +3254,14 @@ evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
value = argument;
key = strsep(&value, "=");
- if (value == NULL || *key == '\0') {
- goto error;
+ if (flags & EVHTTP_URI_QUERY_NONCONFORMANT) {
+ if (value == NULL)
+ value = "";
+ if (*key == '\0')
+ continue;
+ } else {
+ if (value == NULL || *key == '\0')
+ goto error;
}
if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
@@ -3265,6 +3271,8 @@ evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
evhttp_decode_uri_internal(value, strlen(value),
decoded_value, 1 /*always_decode_plus*/);
event_debug(("Query Param: %s -> %s\n", key, decoded_value));
+ if (flags & EVHTTP_URI_QUERY_LAST_VAL)
+ evhttp_remove_header(headers, key);
evhttp_add_header_internal(headers, key, decoded_value);
mm_free(decoded_value);
}
@@ -3284,12 +3292,17 @@ done:
int
evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
{
- return evhttp_parse_query_impl(uri, headers, 1);
+ return evhttp_parse_query_impl(uri, headers, 1, 0);
}
int
evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
{
- return evhttp_parse_query_impl(uri, headers, 0);
+ return evhttp_parse_query_impl(uri, headers, 0, 0);
+}
+int
+evhttp_parse_query_str_flags(const char *uri, struct evkeyvalq *headers, unsigned flags)
+{
+ return evhttp_parse_query_impl(uri, headers, 0, flags);
}
static struct evhttp_cb *
diff --git a/include/event2/http.h b/include/event2/http.h
index ed9acf45..534e604e 100644
--- a/include/event2/http.h
+++ b/include/event2/http.h
@@ -1004,6 +1004,33 @@ char *evhttp_uridecode(const char *uri, int decode_plus,
EVENT2_EXPORT_SYMBOL
int evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
+/** @see evhttp_parse_query_str_flags() */
+EVENT2_EXPORT_SYMBOL
+int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers);
+
+/** Tolerate queries that are not standard conformant.
+ *
+ * Here are some examples:
+ *
+ * - test=123&test2
+ * with with this flag test2 will be present in the output headers
+ *
+ * - test=123&&test2=1
+ * will parse the query with this flag
+ *
+ * - test=123&=456&test2=1
+ * will parse the queyr with this flag, however there won't be empty key
+ * present
+ */
+#define EVHTTP_URI_QUERY_NONCONFORMANT 0x01
+/** Prefer last value over the first from query args
+ *
+ * Example: test=123&test=456
+ * Without: test=123
+ * With : test=456
+ */
+#define EVHTTP_URI_QUERY_LAST_VAL 0x02
+
/**
Helper function to parse out arguments from the query portion of an
HTTP URI.
@@ -1019,10 +1046,11 @@ int evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
@param query_parse the query portion of the URI
@param headers the head of the evkeyval queue
+ @param flags one or more of EVHTTP_URI_QUERY_*
@return 0 on success, -1 on failure
*/
EVENT2_EXPORT_SYMBOL
-int evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers);
+int evhttp_parse_query_str_flags(const char *uri, struct evkeyvalq *headers, unsigned flags);
/**
* Escape HTML character entities in a string.
diff --git a/test/regress_http.c b/test/regress_http.c
index a1bd4a8a..46ecdc21 100644
--- a/test/regress_http.c
+++ b/test/regress_http.c
@@ -2520,6 +2520,62 @@ http_parse_query_str_test(void *ptr)
end:
evhttp_clear_headers(&headers);
}
+static void
+http_parse_query_str_flags_test(void *ptr)
+{
+ struct evkeyvalq headers;
+ int r;
+
+ TAILQ_INIT(&headers);
+
+ /** ~EVHTTP_URI_QUERY_LAST_VAL */
+ r = evhttp_parse_query_str_flags("q=test&q=test2", &headers, 0);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ /** EVHTTP_URI_QUERY_LAST_VAL */
+ r = evhttp_parse_query_str_flags("q=test&q=test2", &headers, EVHTTP_URI_QUERY_LAST_VAL);
+ tt_want(validate_header(&headers, "q", "test2") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ /** ~EVHTTP_URI_QUERY_NONCONFORMANT */
+ r = evhttp_parse_query_str_flags("q=test&q2", &headers, 0);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query_str_flags("q=test&&q2=test2", &headers, 0);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query_str_flags("q=test&=1&q2=test2", &headers, 0);
+ tt_int_op(r, ==, -1);
+ evhttp_clear_headers(&headers);
+
+ /** EVHTTP_URI_QUERY_NONCONFORMANT */
+ r = evhttp_parse_query_str_flags("q=test&q2", &headers, EVHTTP_URI_QUERY_NONCONFORMANT);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "q2", "") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query_str_flags("q=test&&q2=test2", &headers, EVHTTP_URI_QUERY_NONCONFORMANT);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "q2", "test2") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+ r = evhttp_parse_query_str_flags("q=test&=1&q2=test2", &headers, EVHTTP_URI_QUERY_NONCONFORMANT);
+ tt_want(validate_header(&headers, "q", "test") == 0);
+ tt_want(validate_header(&headers, "q2", "test2") == 0);
+ tt_int_op(r, ==, 0);
+ evhttp_clear_headers(&headers);
+
+
+end:
+ evhttp_clear_headers(&headers);
+}
static void
http_parse_uri_test(void *ptr)
@@ -4826,6 +4882,7 @@ struct testcase_t http_testcases[] = {
{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
{ "parse_query", http_parse_query_test, 0, NULL, NULL },
{ "parse_query_str", http_parse_query_str_test, 0, NULL, NULL },
+ { "parse_query_str_flags", http_parse_query_str_flags_test, 0, NULL, NULL },
{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
{ "uriencode", http_uriencode_test, 0, NULL, NULL },