diff options
author | Valentin Bartenev <vbart@nginx.com> | 2019-02-19 20:25:25 +0300 |
---|---|---|
committer | Valentin Bartenev <vbart@nginx.com> | 2019-02-19 20:25:25 +0300 |
commit | 2d4697dbbec7dd51ed5aeebb10e543038e15a359 (patch) | |
tree | ea039720eda5ff7987ed5c4a107440b1c7edc15b | |
parent | acb5b0aad7f9aca966f4d40d05c104f4df68b036 (diff) | |
download | unit-2d4697dbbec7dd51ed5aeebb10e543038e15a359.tar.gz unit-2d4697dbbec7dd51ed5aeebb10e543038e15a359.tar.bz2 |
Validation and normalization of request host.
-rw-r--r-- | src/nxt_h1proto.c | 4 | ||||
-rw-r--r-- | src/nxt_http.h | 2 | ||||
-rw-r--r-- | src/nxt_http_request.c | 117 |
3 files changed, 112 insertions, 11 deletions
diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c index 2194e56f..4e1b22e9 100644 --- a/src/nxt_h1proto.c +++ b/src/nxt_h1proto.c @@ -526,9 +526,7 @@ nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, void *data) return; } - /* ret == NXT_ERROR */ - status = NXT_HTTP_BAD_REQUEST; - + status = ret; goto error; case NXT_AGAIN: diff --git a/src/nxt_http.h b/src/nxt_http.h index 10c6a9f1..af0b2cd6 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -119,12 +119,12 @@ struct nxt_http_request_s { nxt_str_t *args; nxt_list_t *fields; - nxt_http_field_t *host; nxt_http_field_t *content_type; nxt_http_field_t *content_length; nxt_http_field_t *cookie; nxt_http_field_t *referer; nxt_http_field_t *user_agent; + nxt_str_t host; nxt_off_t content_length_n; nxt_sockaddr_t *remote; diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index ed65a592..6029c5c0 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -8,6 +8,7 @@ #include <nxt_http.h> +static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); static void nxt_http_app_request(nxt_task_t *task, void *obj, void *data); static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, @@ -52,13 +53,118 @@ nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt) nxt_int_t nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) { + nxt_int_t ret; + nxt_str_t host; nxt_http_request_t *r; r = ctx; - /* TODO: validate host. */ + if (nxt_slow_path(r->host.start != NULL)) { + return NXT_HTTP_BAD_REQUEST; + } + + host.length = field->value_length; + host.start = field->value; + + ret = nxt_http_validate_host(&host, r->mem_pool); + + if (nxt_fast_path(ret == NXT_OK)) { + r->host = host; + } + + return ret; +} + + +static nxt_int_t +nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp) +{ + u_char *h, ch; + size_t i, dot_pos, host_length; + nxt_bool_t lowcase; + + enum { + sw_usual, + sw_literal, + sw_rest + } state; + + dot_pos = host->length; + host_length = host->length; + + h = host->start; + + lowcase = 0; + state = sw_usual; + + for (i = 0; i < host->length; i++) { + ch = h[i]; + + if (ch > ']') { + /* Short path. */ + continue; + } + + switch (ch) { + + case '.': + if (dot_pos == i - 1) { + return NXT_HTTP_BAD_REQUEST; + } - r->host = field; + dot_pos = i; + break; + + case ':': + if (state == sw_usual) { + host_length = i; + state = sw_rest; + } + + break; + + case '[': + if (i == 0) { + state = sw_literal; + } + + break; + + case ']': + if (state == sw_literal) { + host_length = i + 1; + state = sw_rest; + } + + break; + + case '/': + case '\0': + return NXT_HTTP_BAD_REQUEST; + + default: + if (ch >= 'A' && ch <= 'Z') { + lowcase = 1; + } + + break; + } + } + + if (dot_pos == host_length - 1) { + host_length--; + } + + host->length = host_length; + + if (lowcase) { + host->start = nxt_mp_nget(mp, host_length); + if (nxt_slow_path(host->start == NULL)) { + return NXT_HTTP_INTERNAL_SERVER_ERROR; + } + + nxt_memcpy_lowcase(host->start, h, host_length); + } return NXT_OK; } @@ -97,7 +203,7 @@ nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, } } - return NXT_ERROR; + return NXT_HTTP_BAD_REQUEST; } @@ -237,10 +343,7 @@ nxt_http_app_request(nxt_task_t *task, void *obj, void *data) ar->r.header.query = *r->args; } - if (r->host != NULL) { - ar->r.header.host.length = r->host->value_length; - ar->r.header.host.start = r->host->value; - } + ar->r.header.host = r->host; if (r->content_type != NULL) { ar->r.header.content_type.length = r->content_type->value_length; |