summaryrefslogtreecommitdiff
path: root/main/http.c
diff options
context:
space:
mode:
authorDavid M. Lee <dlee@digium.com>2013-12-24 16:50:48 +0000
committerDavid M. Lee <dlee@digium.com>2013-12-24 16:50:48 +0000
commita952abb9dab8587153d0712eac35f2c365b2b269 (patch)
tree97a3659a7b5925cb5ad486dffea999a51d2df264 /main/http.c
parentc3d5c41dae0b192a4967bc3b462de6c2bede8766 (diff)
http: Properly reject requests with Transfer-Encoding set
Asterisk does not support any of the transfer encodings specified in HTTP/1.1, other than the default "identity" encoding. According to RFC 2616: A server which receives an entity-body with a transfer-coding it does not understand SHOULD return 501 (Unimplemented), and close the connection. A server MUST NOT send transfer-codings to an HTTP/1.0 client. This patch adds the 501 Unimplemented response, instead of the hard work of actually implementing other recordings. This behavior is especially problematic for Node.js clients, which use chunked encoding by default. (closes issue ASTERISK-22486) Review: https://reviewboard.asterisk.org/r/3092/ ........ Merged revisions 404565 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404567 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/http.c')
-rw-r--r--main/http.c89
1 files changed, 73 insertions, 16 deletions
diff --git a/main/http.c b/main/http.c
index ebe0a636a..af1ef81c2 100644
--- a/main/http.c
+++ b/main/http.c
@@ -609,6 +609,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.
*
* This function only returns the "type/subtype" and any trailing parameter is
@@ -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;