Refactored HTTP header parsing.

This commit is contained in:
Igor Sysoev
2018-04-10 19:38:45 +03:00
parent 0a44ac371a
commit 73bdb5ec09

View File

@@ -19,6 +19,8 @@ static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data);
static void nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data);
static nxt_int_t nxt_h1p_header_process(nxt_h1proto_t *h1p, static nxt_int_t nxt_h1p_header_process(nxt_h1proto_t *h1p,
nxt_http_request_t *r); nxt_http_request_t *r);
static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task,
nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf);
static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field, static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field,
uintptr_t data); uintptr_t data);
static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field,
@@ -302,9 +304,7 @@ static const nxt_conn_state_t nxt_h1p_header_parse_state
static void static void
nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data) nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data)
{ {
size_t size;
nxt_int_t ret; nxt_int_t ret;
nxt_buf_t *in, *b;
nxt_conn_t *c; nxt_conn_t *c;
nxt_h1proto_t *h1p; nxt_h1proto_t *h1p;
nxt_http_status_t status; nxt_http_status_t status;
@@ -319,7 +319,11 @@ nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data)
r = h1p->request; r = h1p->request;
if (nxt_fast_path(ret == NXT_DONE)) { ret = nxt_expect(NXT_DONE, ret);
switch (ret) {
case NXT_DONE:
/* /*
* By default the keepalive mode is disabled in HTTP/1.0 and * By default the keepalive mode is disabled in HTTP/1.0 and
* enabled in HTTP/1.1. The mode can be overridden later by * enabled in HTTP/1.1. The mode can be overridden later by
@@ -335,49 +339,21 @@ nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data)
} }
/* ret == NXT_ERROR */ /* ret == NXT_ERROR */
status = NXT_HTTP_BAD_REQUEST;
nxt_http_request_error(task, r, NXT_HTTP_BAD_REQUEST); goto error;
return;
}
if (ret == NXT_AGAIN) { case NXT_AGAIN:
in = c->read; status = nxt_h1p_header_buffer_test(task, h1p, c, r->socket_conf);
if (nxt_buf_mem_free_size(&in->mem) == 0) { if (nxt_fast_path(status == NXT_OK)) {
size = r->socket_conf->large_header_buffer_size; c->read_state = &nxt_h1p_header_parse_state;
if (size <= (size_t) nxt_buf_mem_used_size(&in->mem) nxt_conn_read(task->thread->engine, c);
|| h1p->nbuffers >= r->socket_conf->large_header_buffers) return;
{
(void) nxt_h1p_header_process(h1p, r);
nxt_http_request_error(task, r,
NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE);
return;
}
b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
if (nxt_slow_path(b == NULL)) {
(void) nxt_h1p_header_process(h1p, r);
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
return;
}
h1p->nbuffers++;
size = nxt_buf_mem_used_size(&in->mem);
b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, size);
in->next = h1p->buffers;
h1p->buffers = in;
c->read = b;
} }
c->read_state = &nxt_h1p_header_parse_state; break;
nxt_conn_read(task->thread->engine, c);
return;
}
switch (ret) {
case NXT_HTTP_PARSE_INVALID: case NXT_HTTP_PARSE_INVALID:
status = NXT_HTTP_BAD_REQUEST; status = NXT_HTTP_BAD_REQUEST;
@@ -398,6 +374,9 @@ nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data)
} }
(void) nxt_h1p_header_process(h1p, r); (void) nxt_h1p_header_process(h1p, r);
error:
nxt_http_request_error(task, r, status); nxt_http_request_error(task, r, status);
} }
@@ -423,6 +402,41 @@ nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r)
} }
static nxt_int_t
nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c,
nxt_socket_conf_t *skcf)
{
size_t size, used;
nxt_buf_t *in, *b;
in = c->read;
if (nxt_buf_mem_free_size(&in->mem) == 0) {
size = skcf->large_header_buffer_size;
used = nxt_buf_mem_used_size(&in->mem);
if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) {
return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
}
b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
if (nxt_slow_path(b == NULL)) {
return NXT_HTTP_INTERNAL_SERVER_ERROR;
}
b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used);
in->next = h1p->buffers;
h1p->buffers = in;
h1p->nbuffers++;
c->read = b;
}
return NXT_OK;
}
static nxt_int_t static nxt_int_t
nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data) nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data)
{ {