[httpd] Fix parsing of uri into path parts with encoded '/' (%2F)

In path with an encoded '/' character, the parsing of the path into
parts was wrong.

E. g. an uri like
'/api/library/composers/Adam%20Gardner%2FDavid%20Schneider' would result
in the following parts:

- path_part[0] = "/api"
- path_part[1] = "library"
- path_part[2] = "composer"
- path_part[3] = "Adam Gardner"
- path_part[4] = "David Schneider"

Doing the decode after splitting the uri into parts fixes this and
results in:

- path_part[0] = "api"
- path_part[1] = "library"
- path_part[2] = "composer"
- path_part[3] = "Adam Gardner/David Schneider"
This commit is contained in:
chme 2022-03-27 08:48:46 +02:00
parent a932cc532d
commit b18b76413d
2 changed files with 21 additions and 13 deletions

View File

@ -883,12 +883,17 @@ httpd_gen_cb(struct evhttp_request *req, void *arg)
void
httpd_uri_free(struct httpd_uri_parsed *parsed)
{
int i;
if (!parsed)
return;
free(parsed->uri_decoded);
free(parsed->path);
free(parsed->path_parts[0]);
for (i = 0; i < ARRAY_SIZE(parsed->path_parts); i++)
{
free(parsed->path_parts[i]);
}
evhttp_clear_headers(&(parsed->ev_query));
@ -902,8 +907,9 @@ struct httpd_uri_parsed *
httpd_uri_parse(const char *uri)
{
struct httpd_uri_parsed *parsed;
const char *path;
char *path = NULL;
const char *query;
char *path_part;
char *ptr;
int i;
int ret;
@ -937,7 +943,7 @@ httpd_uri_parse(const char *uri)
}
}
path = evhttp_uri_get_path(parsed->ev_uri);
path = strdup(evhttp_uri_get_path(parsed->ev_uri));
if (!path)
{
DPRINTF(E_WARN, L_HTTPD, "No path in request: '%s'\n", parsed->uri);
@ -951,23 +957,26 @@ httpd_uri_parse(const char *uri)
goto error;
}
CHECK_NULL(L_HTTPD, parsed->path_parts[0] = strdup(parsed->path));
strtok_r(parsed->path_parts[0], "/", &ptr);
for (i = 1; (i < sizeof(parsed->path_parts) / sizeof(parsed->path_parts[0])) && parsed->path_parts[i - 1]; i++)
path_part = strtok_r(path, "/", &ptr);
for (i = 0; (i < ARRAY_SIZE(parsed->path_parts) && path_part); i++)
{
parsed->path_parts[i] = strtok_r(NULL, "/", &ptr);
parsed->path_parts[i] = evhttp_uridecode(path_part, 0, NULL);
path_part = strtok_r(NULL, "/", &ptr);
}
if (!parsed->path_parts[0] || parsed->path_parts[i - 1] || (i < 2))
if (path_part)
{
DPRINTF(E_LOG, L_HTTPD, "URI path has too many/few components (%d): '%s'\n", (parsed->path_parts[0]) ? i : 0, parsed->path);
// If "path_part" is not NULL, we have path tokens that could not be parsed into the "parsed->path_parts" array
DPRINTF(E_LOG, L_HTTPD, "URI path has too many components (%d): '%s'\n", i, parsed->path);
goto error;
}
free(path);
return parsed;
error:
free(path);
httpd_uri_free(parsed);
return NULL;
}

View File

@ -23,10 +23,9 @@ enum httpd_send_flags
*
* We are interested in the path and the query, so they are disassembled to
* path_parts and ev_query. If the request is http://x:3689/foo/bar?key1=val1,
* then part_parts[1] is "foo", [2] is "bar" and the rest is null (the first
* element points to the copy of the path so it can be freed).
* then part_parts[0] is "foo", [1] is "bar" and the rest is null.
*
* The allocated strings are URI decoded.
* Each path_part is an allocated URI decoded string.
*/
struct httpd_uri_parsed
{