HTTP parser: improved error reporting.
This commit is contained in:
@@ -190,6 +190,7 @@ nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data)
|
|||||||
nxt_buf_t *in, *b;
|
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_request_t *r;
|
nxt_http_request_t *r;
|
||||||
nxt_socket_conf_joint_t *joint;
|
nxt_socket_conf_joint_t *joint;
|
||||||
|
|
||||||
@@ -264,7 +265,13 @@ nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (ret == NXT_AGAIN) {
|
/* ret == NXT_ERROR */
|
||||||
|
|
||||||
|
nxt_http_request_error(task, r, NXT_HTTP_BAD_REQUEST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == NXT_AGAIN) {
|
||||||
in = c->read;
|
in = c->read;
|
||||||
|
|
||||||
if (nxt_buf_mem_free_size(&in->mem) == 0) {
|
if (nxt_buf_mem_free_size(&in->mem) == 0) {
|
||||||
@@ -298,9 +305,23 @@ nxt_h1p_header_parse(nxt_task_t *task, void *obj, void *data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ret == NXT_ERROR */
|
switch (ret) {
|
||||||
|
|
||||||
nxt_http_request_error(task, r, NXT_HTTP_BAD_REQUEST);
|
case NXT_HTTP_PARSE_INVALID:
|
||||||
|
status = NXT_HTTP_BAD_REQUEST;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
|
||||||
|
status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case NXT_ERROR:
|
||||||
|
status = NXT_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_http_request_error(task, r, status);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
p++;
|
p++;
|
||||||
@@ -306,7 +306,7 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
return NXT_AGAIN;
|
return NXT_AGAIN;
|
||||||
|
|
||||||
case NXT_HTTP_TARGET_BAD:
|
case NXT_HTTP_TARGET_BAD:
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt_unreachable();
|
nxt_unreachable();
|
||||||
@@ -332,7 +332,7 @@ rest_of_target:
|
|||||||
return NXT_AGAIN;
|
return NXT_AGAIN;
|
||||||
|
|
||||||
case NXT_HTTP_TARGET_BAD:
|
case NXT_HTTP_TARGET_BAD:
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
@@ -407,7 +407,7 @@ space_after_target:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(*p != '\n')) {
|
if (nxt_slow_path(*p != '\n')) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pos = p + 1;
|
*pos = p + 1;
|
||||||
@@ -492,7 +492,7 @@ nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
|
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -555,7 +555,7 @@ nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
len = p - *pos;
|
len = p - *pos;
|
||||||
|
|
||||||
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) {
|
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_TOO_LARGE_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
rp->field_hash = hash;
|
rp->field_hash = hash;
|
||||||
@@ -569,13 +569,13 @@ name_end:
|
|||||||
|
|
||||||
if (nxt_fast_path(*p == ':')) {
|
if (nxt_fast_path(*p == ':')) {
|
||||||
if (nxt_slow_path(p == *pos)) {
|
if (nxt_slow_path(p == *pos)) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = p - *pos;
|
len = p - *pos;
|
||||||
|
|
||||||
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) {
|
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_NAME)) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_TOO_LARGE_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
rp->field_hash = hash;
|
rp->field_hash = hash;
|
||||||
@@ -589,7 +589,7 @@ name_end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(p != *pos)) {
|
if (nxt_slow_path(p != *pos)) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nxt_http_parse_field_end(rp, pos, end);
|
return nxt_http_parse_field_end(rp, pos, end);
|
||||||
@@ -630,7 +630,7 @@ nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
len = p - *pos;
|
len = p - *pos;
|
||||||
|
|
||||||
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) {
|
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_TOO_LARGE_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
rp->field_value.length = len;
|
rp->field_value.length = len;
|
||||||
@@ -645,7 +645,7 @@ nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '\0') {
|
if (ch == '\0') {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +658,7 @@ nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
len = p - *pos;
|
len = p - *pos;
|
||||||
|
|
||||||
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) {
|
if (nxt_slow_path(len > NXT_HTTP_MAX_FIELD_VALUE)) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_TOO_LARGE_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
rp->field_value.length = len;
|
rp->field_value.length = len;
|
||||||
@@ -784,7 +784,7 @@ nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos,
|
|||||||
return NXT_DONE;
|
return NXT_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -976,7 +976,7 @@ nxt_http_parse_complex_target(nxt_http_request_parse_t *rp)
|
|||||||
u -= 5;
|
u -= 5;
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (u < rp->path.start) {
|
if (u < rp->path.start) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
if (*u == '/') {
|
if (*u == '/') {
|
||||||
u++;
|
u++;
|
||||||
@@ -1022,7 +1022,7 @@ nxt_http_parse_complex_target(nxt_http_request_parse_t *rp)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
|
|
||||||
case sw_quoted_second:
|
case sw_quoted_second:
|
||||||
if (ch >= '0' && ch <= '9') {
|
if (ch >= '0' && ch <= '9') {
|
||||||
@@ -1034,7 +1034,7 @@ nxt_http_parse_complex_target(nxt_http_request_parse_t *rp)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if (ch == '\0') {
|
} else if (ch == '\0') {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = saved_state;
|
state = saved_state;
|
||||||
@@ -1058,12 +1058,12 @@ nxt_http_parse_complex_target(nxt_http_request_parse_t *rp)
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state >= sw_quoted) {
|
if (state >= sw_quoted) {
|
||||||
return NXT_ERROR;
|
return NXT_HTTP_PARSE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
args:
|
args:
|
||||||
|
|||||||
@@ -8,6 +8,12 @@
|
|||||||
#define _NXT_HTTP_PARSER_H_INCLUDED_
|
#define _NXT_HTTP_PARSER_H_INCLUDED_
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NXT_HTTP_PARSE_INVALID = 1,
|
||||||
|
NXT_HTTP_PARSE_TOO_LARGE_FIELD,
|
||||||
|
} nxt_http_parse_error_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct nxt_http_request_parse_s nxt_http_request_parse_t;
|
typedef struct nxt_http_request_parse_s nxt_http_request_parse_t;
|
||||||
typedef struct nxt_http_field_s nxt_http_field_t;
|
typedef struct nxt_http_field_s nxt_http_field_t;
|
||||||
typedef struct nxt_http_fields_hash_s nxt_http_fields_hash_t;
|
typedef struct nxt_http_fields_hash_s nxt_http_fields_hash_t;
|
||||||
|
|||||||
@@ -101,27 +101,27 @@ static nxt_http_parse_test_case_t nxt_http_test_cases[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GEt / HTTP/1.0\r\n\r\n"),
|
nxt_string("GEt / HTTP/1.0\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET /\0 HTTP/1.0\r\n\r\n"),
|
nxt_string("GET /\0 HTTP/1.0\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET /\r HTTP/1.0\r\n\r\n"),
|
nxt_string("GET /\r HTTP/1.0\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET /\n HTTP/1.0\r\n\r\n"),
|
nxt_string("GET /\n HTTP/1.0\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.0\r\r\n"),
|
nxt_string("GET / HTTP/1.0\r\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -230,13 +230,13 @@ static nxt_http_parse_test_case_t nxt_http_test_cases[] = {
|
|||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.1\r\n"
|
nxt_string("GET / HTTP/1.1\r\n"
|
||||||
"Host example.com\r\n\r\n"),
|
"Host example.com\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.1\r\n"
|
nxt_string("GET / HTTP/1.1\r\n"
|
||||||
":Host: example.com\r\n\r\n"),
|
":Host: example.com\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -248,25 +248,25 @@ static nxt_http_parse_test_case_t nxt_http_test_cases[] = {
|
|||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.1\r\n"
|
nxt_string("GET / HTTP/1.1\r\n"
|
||||||
"Ho\0st: example.com\r\n\r\n"),
|
"Ho\0st: example.com\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.1\r\n"
|
nxt_string("GET / HTTP/1.1\r\n"
|
||||||
"Ho\rst: example.com\r\n\r\n"),
|
"Ho\rst: example.com\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.1\r\n"
|
nxt_string("GET / HTTP/1.1\r\n"
|
||||||
"Host: exa\0mple.com\r\n\r\n"),
|
"Host: exa\0mple.com\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
nxt_string("GET / HTTP/1.1\r\n"
|
nxt_string("GET / HTTP/1.1\r\n"
|
||||||
"Host: exa\rmple.com\r\n\r\n"),
|
"Host: exa\rmple.com\r\n\r\n"),
|
||||||
NXT_ERROR,
|
NXT_HTTP_PARSE_INVALID,
|
||||||
NULL, { NULL }
|
NULL, { NULL }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user