diff --git a/main/http.c b/main/http.c index ebe0a636ae4967872e4a6cc4065d5338a31a3130..af1ef81c299b83a89aaf73218e00d65219443d99 100644 --- a/main/http.c +++ b/main/http.c @@ -608,6 +608,27 @@ void ast_http_uri_unlink_all_with_key(const char *key) #define MAX_POST_CONTENT 1025 +/*! + * \brief Retrieves the header with the given field name. + * + * \param headers Headers to search. + * \param field_name Name of the header to find. + * \return Associated header value. + * \return \c NULL if header is not present. + */ +static const char *get_header(struct ast_variable *headers, + const char *field_name) +{ + struct ast_variable *v; + + for (v = headers; v; v = v->next) { + if (!strcasecmp(v->name, field_name)) { + return v->value; + } + } + return NULL; +} + /*! * \brief Retrieves the content type specified in the "Content-Type" header. * @@ -620,32 +641,51 @@ void ast_http_uri_unlink_all_with_key(const char *key) */ static char *get_content_type(struct ast_variable *headers) { - struct ast_variable *v; + const char *content_type = get_header(headers, "Content-Type"); + const char *param; + size_t size; - for (v = headers; v; v = v->next) { - if (strcasecmp(v->name, "Content-Type") == 0) { - const char *param = strchr(v->value, ';'); - size_t size = (param ? param - v->value : - strlen(v->value)) + 1; - return ast_strndup(v->value, size); - } + if (!content_type) { + return NULL; } - return NULL; + param = strchr(content_type, ';'); + size = param ? param - content_type : strlen(content_type); + + return ast_strndup(content_type, size); } +/*! + * \brief Returns the value of the Content-Length header. + * + * \param headers HTTP headers. + * \return Value of the Content-Length header. + * \return 0 if header is not present, or is invalid. + */ static int get_content_length(struct ast_variable *headers) { - struct ast_variable *v; + const char *content_length = get_header(headers, "Content-Length"); - for (v = headers; v; v = v->next) { - if (!strcasecmp(v->name, "Content-Length")) { - return atoi(v->value); - } + if (!content_length) { + /* Missing content length; assume zero */ + return 0; } - /* Missing content length; assume zero */ - return 0; + /* atoi() will return 0 for invalid inputs, which is good enough for + * the HTTP parsing. */ + return atoi(content_length); +} + +/*! + * \brief Returns the value of the Transfer-Encoding header. + * + * \param headers HTTP headers. + * \return Value of the Transfer-Encoding header. + * \return 0 if header is not present, or is invalid. + */ +static const char *get_transfer_encoding(struct ast_variable *headers) +{ + return get_header(headers, "Transfer-Encoding"); } struct ast_json *ast_http_get_json( @@ -1068,6 +1108,7 @@ static void *httpd_helper_thread(void *data) struct ast_variable *tail = headers; char *uri, *method; enum ast_http_method http_method = AST_HTTP_UNKNOWN; + const char *transfer_encoding; if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) { goto done; @@ -1140,6 +1181,22 @@ static void *httpd_helper_thread(void *data) } } + transfer_encoding = get_transfer_encoding(headers); + /* Transfer encoding defaults to identity */ + if (!transfer_encoding) { + transfer_encoding = "identity"; + } + + /* + * RFC 2616, section 3.6, we should respond with a 501 for any transfer- + * codings we don't understand. + */ + if (strcasecmp(transfer_encoding, "identity") != 0) { + /* Transfer encodings not supported */ + ast_http_error(ser, 501, "Unimplemented", "Unsupported Transfer-Encoding."); + goto done; + } + if (!*uri) { ast_http_error(ser, 400, "Bad Request", "Invalid Request"); goto done;