From 9ac68fd76c43523ea3aa3bcc4f9fef0ac2cee830 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Sun, 12 Nov 2023 00:14:05 +0100 Subject: http: Make http_decode_url return int So far, it was not possible callers to distinguish between decoding errors, as caused by ill-formed input, from fatal errors. --- http.c | 74 +++++++++++++++++++++++++++++---------------------- include/libweb/http.h | 2 +- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/http.c b/http.c index 42f5181..0184c65 100644 --- a/http.c +++ b/http.c @@ -133,7 +133,7 @@ static int parse_arg(struct ctx *const c, const char *const arg, int ret = -1; struct http_arg a = {0}, *args = NULL; const char *sep = memchr(arg, '=', n); - char *enckey = NULL, *encvalue = NULL; + char *enckey = NULL, *encvalue = NULL, *deckey = NULL, *decvalue = NULL; if (!sep) { @@ -170,25 +170,25 @@ static int parse_arg(struct ctx *const c, const char *const arg, __func__, strerror(errno)); goto end; } - /* URL parameters use '+' for whitespace, rather than %20. */ - a = (const struct http_arg) + else if ((ret = http_decode_url(enckey, true, &deckey))) { - .key = http_decode_url(enckey, true), - .value = http_decode_url(encvalue, true) - }; - - if (!a.key) - { - fprintf(stderr, "%s: http_decode_url key failed\n", __func__); + fprintf(stderr, "%s: http_decode_url enckey failed\n", __func__); goto end; } - else if (!a.value) + else if ((ret = http_decode_url(encvalue, true, &decvalue))) { - fprintf(stderr, "%s: http_decode_url value failed\n", __func__); + fprintf(stderr, "%s: http_decode_url encvalue failed\n", __func__); goto end; } - else if (!(args = realloc(c->args, (c->n_args + 1) * sizeof *args))) + + a = (const struct http_arg) + { + .key = deckey, + .value = decvalue + }; + + if (!(args = realloc(c->args, (c->n_args + 1) * sizeof *args))) { fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno)); goto end; @@ -200,7 +200,11 @@ static int parse_arg(struct ctx *const c, const char *const arg, end: if (ret) + { arg_free(&a); + free(deckey); + free(decvalue); + } free(enckey); free(encvalue); @@ -321,7 +325,7 @@ static int parse_resource(struct ctx *const c, const char *const enc_res) fprintf(stderr, "%s: strndup(3): %s\n", __func__, strerror(errno)); goto end; } - else if (!(resource = http_decode_url(trimmed_encres, false))) + else if ((ret = http_decode_url(trimmed_encres, false, &resource))) { fprintf(stderr, "%s: http_decode_url failed\n", __func__); goto end; @@ -1968,31 +1972,32 @@ failure: return NULL; } -char *http_decode_url(const char *url, const bool spaces) +int http_decode_url(const char *url, const bool spaces, char **out) { - char *ret = NULL; + int ret = -1; + char *str = NULL; size_t n = 0; while (*url) { - char *const r = realloc(ret, n + 1); + char *const r = realloc(str, n + 1); if (!r) { fprintf(stderr, "%s: realloc(3) loop: %s\n", __func__, strerror(errno)); - goto failure; + goto end; } - ret = r; + str = r; if (spaces && *url == '+') { - ret[n++] = ' '; + str[n++] = ' '; url++; } else if (*url != '%') - ret[n++] = *url++; + str[n++] = *url++; else if (*(url + 1) && *(url + 2)) { const char buf[sizeof "00"] = {*(url + 1), *(url + 2)}; @@ -2002,32 +2007,37 @@ char *http_decode_url(const char *url, const bool spaces) if (*endptr) { fprintf(stderr, "%s: invalid number %s\n", __func__, buf); - goto failure; + ret = 1; + goto end; } url += 3; - ret[n++] = res; + str[n++] = res; } else { fprintf(stderr, "%s: unterminated %%\n", __func__); - goto failure; + ret = 1; + goto end; } } - char *const r = realloc(ret, n + 1); + char *const r = realloc(str, n + 1); if (!r) { fprintf(stderr, "%s: realloc(3) end: %s\n", __func__, strerror(errno)); - goto failure; + goto end; } - ret = r; - ret[n] = '\0'; - return ret; + str = r; + str[n] = '\0'; + *out = str; + ret = 0; -failure: - free(ret); - return NULL; +end: + if (ret) + free(str); + + return ret; } diff --git a/include/libweb/http.h b/include/libweb/http.h index 68ffb9a..80030fb 100644 --- a/include/libweb/http.h +++ b/include/libweb/http.h @@ -105,6 +105,6 @@ int http_response_add_header(struct http_response *r, const char *header, const char *value); char *http_cookie_create(const char *key, const char *value); char *http_encode_url(const char *url); -char *http_decode_url(const char *url, bool spaces); +int http_decode_url(const char *url, bool spaces, char **out); #endif /* HTTP_H */ -- cgit v1.2.3