diff --git a/plugins/restful/http.c b/plugins/restful/http.c index 42d5cd5b..03a048e0 100644 --- a/plugins/restful/http.c +++ b/plugins/restful/http.c @@ -56,6 +56,26 @@ static int response(nng_aio *aio, char *content, enum nng_http_status status) return 0; } +ssize_t url_decode(const char *s, size_t len, char *buf, size_t size) +{ + size_t i = 0, j = 0; + int c = 0, n = 0; + while (i < len && j < size) { + c = s[i++]; + if ('+' == c) { + c = ' '; + } else if ('%' == c) { + if (i + 2 > len || !sscanf(s + i, "%2x%n", &c, &n) || 2 != n) { + return -1; + } + i += 2, n = 0; + } + buf[j++] = c; + } + buf[(j < size) ? j : --j] = '\0'; + return j; +} + const char *http_get_header(nng_aio *aio, char *name) { nng_http_req *req = nng_aio_get_input(aio, 0); @@ -153,6 +173,17 @@ const char *http_get_param(nng_aio *aio, const char *name, size_t *len) return val; } +ssize_t http_get_param_str(nng_aio *aio, const char *name, char *buf, + size_t size) +{ + size_t len = 0; + const char *s = http_get_param(aio, name, &len); + if (NULL == s) { + return -2; + } + return url_decode(s, len, buf, size); +} + int http_get_param_uintmax(nng_aio *aio, const char *name, uintmax_t *param) { size_t len = 0; diff --git a/plugins/restful/http.h b/plugins/restful/http.h index 90b3229d..a158f432 100644 --- a/plugins/restful/http.h +++ b/plugins/restful/http.h @@ -29,6 +29,12 @@ extern "C" { #endif +// Decode url encoded string. +// Return -1 if decode fails, otherwise return the number of bytes written to +// `buf` excluding the terminating NULL byte. A return value of `size` indicates +// buffer overflow. +ssize_t url_decode(const char *s, size_t len, char *buf, size_t size); + int http_get_body(nng_aio *aio, void **data, size_t *data_size); // Find query parameter value of the given name. @@ -47,6 +53,13 @@ int http_get_body(nng_aio *aio, void **data, size_t *data_size); // touch len. const char *http_get_param(nng_aio *aio, const char *name, size_t *len); +// Get query parameter as url decoded string. +// Return -2 if param does not exist, -1 if url decode fail, otherwise return +// the number of bytes written to `buf` excluding the terminating NULL byte. A +// return value of `size` indicates buffer overflow. +ssize_t http_get_param_str(nng_aio *aio, const char *name, char *buf, + size_t size); + // Returns 0 on success. // On failure returns // NEU_ERR_ENOENT if no query parameter named `name`. diff --git a/tests/http_test.cc b/tests/http_test.cc index 7394c902..4e0937a7 100644 --- a/tests/http_test.cc +++ b/tests/http_test.cc @@ -69,6 +69,43 @@ TEST(HTTPTest, http_get_param) nng_url_free(url); } +TEST(HTTPTest, http_get_param_str) +{ + nng_aio * aio = NULL; + nng_http_req *req = NULL; + nng_url * url = NULL; + ssize_t ret = 0; + + char buf[256] = { 0 }; + nng_aio_alloc(&aio, NULL, NULL); + nng_url_parse(&url, "http://127.0.0.1"); + nng_http_req_alloc(&req, url); + nng_aio_set_input(aio, 0, req); + + nng_http_req_set_uri(req, "/?node_id"); + ret = http_get_param_str(aio, "group", buf, sizeof(buf)); + EXPECT_EQ(ret, -2); + + nng_http_req_set_uri(req, "/?group"); + ret = http_get_param_str(aio, "group", buf, sizeof(buf)); + EXPECT_EQ(ret, 0); + EXPECT_EQ(0, strcmp("", buf)); + + nng_http_req_set_uri(req, "/?group=%EZ%BB%84"); + ret = http_get_param_str(aio, "group", buf, 3); + EXPECT_EQ(ret, -1); + EXPECT_EQ(0, strcmp("", buf)); + + nng_http_req_set_uri(req, "/?group=%E7%BB%84"); + ret = http_get_param_str(aio, "group", buf, 4); + EXPECT_EQ(ret, 3); + EXPECT_EQ(0, strcmp("组", buf)); + + nng_aio_free(aio); + nng_http_req_free(req); + nng_url_free(url); +} + TEST(HTTPTest, http_get_param_node_id) { nng_aio * aio = NULL;