diff --git a/main/http.c b/main/http.c index 7dc46a3bcbf34bd03637c2f40dcc4a92d3bc0938..5ab4d27ca0bdc2a32ce7e41603ff0fd3a320e45f 100644 --- a/main/http.c +++ b/main/http.c @@ -370,6 +370,20 @@ void ast_http_uri_unlink_all_with_key(const char *key) AST_RWLIST_TRAVERSE_SAFE_END } +/* + * Decode special characters in http uri. + * We have ast_uri_decode to handle %XX sequences, but spaces + * are encoded as a '+' so we need to replace them beforehand. + */ +static void http_decode(char *s) +{ + for (;*s; s++) { + if (*s == '+') + *s = ' '; + } + ast_uri_decode(s); +} + static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char *uri, enum ast_http_method method, int *status, char **title, int *contentlength, struct ast_variable **cookies, struct ast_variable *headers, unsigned int *static_content) @@ -387,18 +401,22 @@ static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char if (method == AST_HTTP_GET) { strsep(¶ms, "?"); - /* Extract arguments from the request and store them in variables. */ + /* Extract arguments from the request and store them in variables. + * Note that a request can have multiple arguments with the same + * name, and we store them all in the list of variables. + * It is up to the application to handle multiple values. + */ if (params) { char *var, *val; while ((val = strsep(¶ms, "&"))) { var = strsep(&val, "="); if (val) { - ast_uri_decode(val); + http_decode(val); } else { val = ""; } - ast_uri_decode(var); + http_decode(var); if ((v = ast_variable_new(var, val, ""))) { if (vars) { prev->next = v; @@ -412,9 +430,11 @@ static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char } /* - * Append the cookies to the variables (the only reason to have them - * at the end is to avoid another pass of the cookies list to find - * the tail). + * Append the cookies to the list of variables. + * This saves a pass in the cookies list, but has the side effect + * that a variable might mask a cookie with the same name if the + * application stops at the first match. + * Note that this is the same behaviour as $_REQUEST variables in PHP. */ if (prev) { prev->next = *cookies; @@ -423,7 +443,7 @@ static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char } *cookies = NULL; - ast_uri_decode(uri); + http_decode(uri); AST_RWLIST_RDLOCK(&uri_redirects); AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {