summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2019-02-19 20:25:25 +0300
committerValentin Bartenev <vbart@nginx.com>2019-02-19 20:25:25 +0300
commit2d4697dbbec7dd51ed5aeebb10e543038e15a359 (patch)
treeea039720eda5ff7987ed5c4a107440b1c7edc15b
parentacb5b0aad7f9aca966f4d40d05c104f4df68b036 (diff)
downloadunit-2d4697dbbec7dd51ed5aeebb10e543038e15a359.tar.gz
unit-2d4697dbbec7dd51ed5aeebb10e543038e15a359.tar.bz2
Validation and normalization of request host.
-rw-r--r--src/nxt_h1proto.c4
-rw-r--r--src/nxt_http.h2
-rw-r--r--src/nxt_http_request.c117
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;