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.
This commit is contained in:
Xavier Del Campo Romero 2023-11-12 00:14:05 +01:00
parent 957ac188e5
commit 9ac68fd76c
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
2 changed files with 45 additions and 35 deletions

78
http.c
View File

@ -133,7 +133,7 @@ static int parse_arg(struct ctx *const c, const char *const arg,
int ret = -1; int ret = -1;
struct http_arg a = {0}, *args = NULL; struct http_arg a = {0}, *args = NULL;
const char *sep = memchr(arg, '=', n); const char *sep = memchr(arg, '=', n);
char *enckey = NULL, *encvalue = NULL; char *enckey = NULL, *encvalue = NULL, *deckey = NULL, *decvalue = NULL;
if (!sep) if (!sep)
{ {
@ -170,25 +170,25 @@ static int parse_arg(struct ctx *const c, const char *const arg,
__func__, strerror(errno)); __func__, strerror(errno));
goto end; goto end;
} }
/* URL parameters use '+' for whitespace, rather than %20. */ /* URL parameters use '+' for whitespace, rather than %20. */
else if ((ret = http_decode_url(enckey, true, &deckey)))
{
fprintf(stderr, "%s: http_decode_url enckey failed\n", __func__);
goto end;
}
else if ((ret = http_decode_url(encvalue, true, &decvalue)))
{
fprintf(stderr, "%s: http_decode_url encvalue failed\n", __func__);
goto end;
}
a = (const struct http_arg) a = (const struct http_arg)
{ {
.key = http_decode_url(enckey, true), .key = deckey,
.value = http_decode_url(encvalue, true) .value = decvalue
}; };
if (!a.key) if (!(args = realloc(c->args, (c->n_args + 1) * sizeof *args)))
{
fprintf(stderr, "%s: http_decode_url key failed\n", __func__);
goto end;
}
else if (!a.value)
{
fprintf(stderr, "%s: http_decode_url value failed\n", __func__);
goto end;
}
else if (!(args = realloc(c->args, (c->n_args + 1) * sizeof *args)))
{ {
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno)); fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
goto end; goto end;
@ -200,7 +200,11 @@ static int parse_arg(struct ctx *const c, const char *const arg,
end: end:
if (ret) if (ret)
{
arg_free(&a); arg_free(&a);
free(deckey);
free(decvalue);
}
free(enckey); free(enckey);
free(encvalue); 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)); fprintf(stderr, "%s: strndup(3): %s\n", __func__, strerror(errno));
goto end; 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__); fprintf(stderr, "%s: http_decode_url failed\n", __func__);
goto end; goto end;
@ -1968,31 +1972,32 @@ failure:
return NULL; 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; size_t n = 0;
while (*url) while (*url)
{ {
char *const r = realloc(ret, n + 1); char *const r = realloc(str, n + 1);
if (!r) if (!r)
{ {
fprintf(stderr, "%s: realloc(3) loop: %s\n", fprintf(stderr, "%s: realloc(3) loop: %s\n",
__func__, strerror(errno)); __func__, strerror(errno));
goto failure; goto end;
} }
ret = r; str = r;
if (spaces && *url == '+') if (spaces && *url == '+')
{ {
ret[n++] = ' '; str[n++] = ' ';
url++; url++;
} }
else if (*url != '%') else if (*url != '%')
ret[n++] = *url++; str[n++] = *url++;
else if (*(url + 1) && *(url + 2)) else if (*(url + 1) && *(url + 2))
{ {
const char buf[sizeof "00"] = {*(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) if (*endptr)
{ {
fprintf(stderr, "%s: invalid number %s\n", __func__, buf); fprintf(stderr, "%s: invalid number %s\n", __func__, buf);
goto failure; ret = 1;
goto end;
} }
url += 3; url += 3;
ret[n++] = res; str[n++] = res;
} }
else else
{ {
fprintf(stderr, "%s: unterminated %%\n", __func__); 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) if (!r)
{ {
fprintf(stderr, "%s: realloc(3) end: %s\n", __func__, strerror(errno)); fprintf(stderr, "%s: realloc(3) end: %s\n", __func__, strerror(errno));
goto failure; goto end;
} }
ret = r; str = r;
ret[n] = '\0'; str[n] = '\0';
return ret; *out = str;
ret = 0;
failure: end:
free(ret); if (ret)
return NULL; free(str);
return ret;
} }

View File

@ -105,6 +105,6 @@ int http_response_add_header(struct http_response *r, const char *header,
const char *value); const char *value);
char *http_cookie_create(const char *key, const char *value); char *http_cookie_create(const char *key, const char *value);
char *http_encode_url(const char *url); 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 */ #endif /* HTTP_H */